Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: extract FormModal from Modal #3922

Merged
merged 1 commit into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions extensions/flags/js/src/forum/components/FlagPostModal.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import app from 'flarum/forum/app';
import Modal from 'flarum/common/components/Modal';
import FormModal from 'flarum/common/components/FormModal';
import Form from 'flarum/common/components/Form';
import Button from 'flarum/common/components/Button';

import Stream from 'flarum/common/utils/Stream';
import withAttr from 'flarum/common/utils/withAttr';
import ItemList from 'flarum/common/utils/ItemList';

export default class FlagPostModal extends Modal {
export default class FlagPostModal extends FormModal {
oninit(vnode) {
super.oninit(vnode);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import app from 'flarum/forum/app';
import Modal from 'flarum/common/components/Modal';
import FormModal from 'flarum/common/components/FormModal';
import Button from 'flarum/common/components/Button';
import Stream from 'flarum/common/utils/Stream';
import Form from '@flarum/core/src/common/components/Form';

export default class NicknameModal extends Modal {
export default class NicknameModal extends FormModal {
oninit(vnode) {
super.oninit(vnode);
this.nickname = Stream(app.session.user.displayName());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import app from 'flarum/admin/app';
import ItemList from 'flarum/common/utils/ItemList';
import generateElementId from 'flarum/admin/utils/generateElementId';
import Modal, { IInternalModalAttrs } from 'flarum/common/components/Modal';
import FormModal, { IFormModalAttrs } from 'flarum/common/components/FormModal';

import Mithril from 'mithril';
import Button from 'flarum/common/components/Button';
Expand All @@ -22,7 +22,7 @@ export interface IDateSelection {
end: number;
}

export interface IStatisticsWidgetDateSelectionModalAttrs extends IInternalModalAttrs {
export interface IStatisticsWidgetDateSelectionModalAttrs extends IFormModalAttrs {
onModalSubmit: (dates: IDateSelection) => void;
value?: IDateSelection;
}
Expand All @@ -38,7 +38,7 @@ interface IStatisticsWidgetDateSelectionModalState {
};
}

export default class StatisticsWidgetDateSelectionModal extends Modal<IStatisticsWidgetDateSelectionModalAttrs> {
export default class StatisticsWidgetDateSelectionModal extends FormModal<IStatisticsWidgetDateSelectionModalAttrs> {
/* @ts-expect-error core typings don't allow us to set the type of the state attr :( */
state: IStatisticsWidgetDateSelectionModalState = {
inputs: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import app from 'flarum/forum/app';
import Modal from 'flarum/common/components/Modal';
import FormModal from 'flarum/common/components/FormModal';
import Button from 'flarum/common/components/Button';
import Stream from 'flarum/common/utils/Stream';
import withAttr from 'flarum/common/utils/withAttr';
Expand All @@ -9,7 +9,7 @@ import { getPermanentSuspensionDate } from '../helpers/suspensionHelper';
import Form from '@flarum/core/src/common/components/Form';
import FieldSet from '@flarum/core/src/common/components/FieldSet';

export default class SuspendUserModal extends Modal {
export default class SuspendUserModal extends FormModal {
oninit(vnode) {
super.oninit(vnode);

Expand Down
6 changes: 3 additions & 3 deletions extensions/tags/js/src/admin/components/EditTagModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import app from 'flarum/admin/app';
import Modal, { IInternalModalAttrs } from 'flarum/common/components/Modal';
import FormModal, { IFormModalAttrs } from 'flarum/common/components/FormModal';
import Button from 'flarum/common/components/Button';
import ColorPreviewInput from 'flarum/common/components/ColorPreviewInput';
import ItemList from 'flarum/common/utils/ItemList';
Expand All @@ -12,7 +12,7 @@ import type Mithril from 'mithril';
import tagLabel from '../../common/helpers/tagLabel';
import type Tag from '../../common/models/Tag';

export interface EditTagModalAttrs extends IInternalModalAttrs {
export interface EditTagModalAttrs extends IFormModalAttrs {
primary?: boolean;
model?: Tag;
}
Expand All @@ -21,7 +21,7 @@ export interface EditTagModalAttrs extends IInternalModalAttrs {
* The `EditTagModal` component shows a modal dialog which allows the user
* to create or edit a tag.
*/
export default class EditTagModal extends Modal<EditTagModalAttrs> {
export default class EditTagModal extends FormModal<EditTagModalAttrs> {
tag!: Tag;

name!: Stream<string>;
Expand Down
10 changes: 5 additions & 5 deletions extensions/tags/js/src/common/components/TagSelectionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import extractText from 'flarum/common/utils/extractText';
import highlight from 'flarum/common/helpers/highlight';
import KeyboardNavigatable from 'flarum/common/utils/KeyboardNavigatable';
import LoadingIndicator from 'flarum/common/components/LoadingIndicator';
import Modal from 'flarum/common/components/Modal';
import FormModal from 'flarum/common/components/FormModal';
import Stream from 'flarum/common/utils/Stream';

import sortTags from '../utils/sortTags';
Expand All @@ -14,7 +14,7 @@ import tagIcon from '../helpers/tagIcon';
import ToggleButton from '../../forum/components/ToggleButton';

import type Tag from '../models/Tag';
import type { IInternalModalAttrs } from 'flarum/common/components/Modal';
import type { IFormModalAttrs } from 'flarum/common/components/FormModal';
import type Mithril from 'mithril';

export interface ITagSelectionModalLimits {
Expand All @@ -34,7 +34,7 @@ export interface ITagSelectionModalLimits {
};
}

export interface ITagSelectionModalAttrs extends IInternalModalAttrs {
export interface ITagSelectionModalAttrs extends IFormModalAttrs {
/** Custom modal className to use. */
className?: string;
/** Modal title, defaults to 'Choose Tags'. */
Expand Down Expand Up @@ -64,7 +64,7 @@ export type ITagSelectionModalState = undefined;
export default class TagSelectionModal<
CustomAttrs extends ITagSelectionModalAttrs = ITagSelectionModalAttrs,
CustomState extends ITagSelectionModalState = ITagSelectionModalState
> extends Modal<CustomAttrs, CustomState> {
> extends FormModal<CustomAttrs, CustomState> {
protected loading = true;
protected tags!: Tag[];
protected selected: Tag[] = [];
Expand Down Expand Up @@ -108,7 +108,7 @@ export default class TagSelectionModal<
.onSelect(this.select.bind(this))
.onRemove(() => this.selected.splice(this.selected.length - 1, 1));

app.tagList.load(['parent']).then((tags) => {
app.tagList.load(['parent']).then((tags: Tag[]) => {
this.loading = false;

if (this.attrs.selectableTags) {
Expand Down
2 changes: 1 addition & 1 deletion extensions/tags/js/src/common/states/TagListState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default class TagListState {
async query(includes: string[] = []): Promise<Tag[]> {
this.loadedIncludes ??= new Set();

return app.store.find<Tag[]>('tags', { include: includes.join(',') }).then((val) => {
return app.store.find<Tag[]>('tags', { include: includes.join(',') }).then((val: Tag) => {
includes.forEach((include) => this.loadedIncludes!.add(include));
return val;
});
Expand Down
6 changes: 3 additions & 3 deletions framework/core/js/src/admin/components/CreateUserModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import app from '../../admin/app';
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import FormModal, { IFormModalAttrs } from '../../common/components/FormModal';
import Button from '../../common/components/Button';
import extractText from '../../common/utils/extractText';
import ItemList from '../../common/utils/ItemList';
Expand All @@ -9,7 +9,7 @@ import Switch from '../../common/components/Switch';
import { generateRandomString } from '../../common/utils/string';
import Form from '../../common/components/Form';

export interface ICreateUserModalAttrs extends IInternalModalAttrs {
export interface ICreateUserModalAttrs extends IFormModalAttrs {
username?: string;
email?: string;
password?: string;
Expand All @@ -24,7 +24,7 @@ export type SignupBody = {
password: string;
};

export default class CreateUserModal<CustomAttrs extends ICreateUserModalAttrs = ICreateUserModalAttrs> extends Modal<CustomAttrs> {
export default class CreateUserModal<CustomAttrs extends ICreateUserModalAttrs = ICreateUserModalAttrs> extends FormModal<CustomAttrs> {
/**
* The value of the username input.
*/
Expand Down
6 changes: 3 additions & 3 deletions framework/core/js/src/admin/components/EditGroupModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import app from '../../admin/app';
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import FormModal, { IFormModalAttrs } from '../../common/components/FormModal';
import Button from '../../common/components/Button';
import Badge from '../../common/components/Badge';
import Group from '../../common/models/Group';
Expand All @@ -11,15 +11,15 @@ import extractText from '../../common/utils/extractText';
import ColorPreviewInput from '../../common/components/ColorPreviewInput';
import Form from '../../common/components/Form';

export interface IEditGroupModalAttrs extends IInternalModalAttrs {
export interface IEditGroupModalAttrs extends IFormModalAttrs {
group?: Group;
}

/**
* The `EditGroupModal` component shows a modal dialog which allows the user
* to create or edit a group.
*/
export default class EditGroupModal<CustomAttrs extends IEditGroupModalAttrs = IEditGroupModalAttrs> extends Modal<CustomAttrs> {
export default class EditGroupModal<CustomAttrs extends IEditGroupModalAttrs = IEditGroupModalAttrs> extends FormModal<CustomAttrs> {
group!: Group;
nameSingular!: Stream<string>;
namePlural!: Stream<string>;
Expand Down
4 changes: 0 additions & 4 deletions framework/core/js/src/admin/components/LoadingModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,4 @@ export default class LoadingModal<ModalAttrs extends ILoadingModalAttrs = ILoadi
content() {
return null;
}

onsubmit(e: Event): void {
throw new Error('LoadingModal should not throw errors.');
}
}
6 changes: 3 additions & 3 deletions framework/core/js/src/admin/components/SettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import app from '../../admin/app';
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import FormModal, { IFormModalAttrs } from '../../common/components/FormModal';
import Button from '../../common/components/Button';
import Stream from '../../common/utils/Stream';
import saveSettings from '../utils/saveSettings';
import Mithril from 'mithril';
import { MutableSettings, SettingValue } from './AdminPage';
import Form from '../../common/components/Form';

export interface ISettingsModalAttrs extends IInternalModalAttrs {}
export interface ISettingsModalAttrs extends IFormModalAttrs {}

export default abstract class SettingsModal<CustomAttrs extends ISettingsModalAttrs = ISettingsModalAttrs> extends Modal<CustomAttrs> {
export default abstract class SettingsModal<CustomAttrs extends ISettingsModalAttrs = ISettingsModalAttrs> extends FormModal<CustomAttrs> {
settings: MutableSettings = {};
loading: boolean = false;

Expand Down
1 change: 1 addition & 0 deletions framework/core/js/src/common/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import './components/SelectDropdown';
import './components/ModalManager';
import './components/Button';
import './components/Modal';
import './components/FormModal';
import './components/GroupBadge';
import './components/TextEditor';
import './components/TextEditorButton';
Expand Down
6 changes: 3 additions & 3 deletions framework/core/js/src/common/components/EditUserModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import app from '../../common/app';
import Modal, { IInternalModalAttrs } from './Modal';
import FormModal, { IFormModalAttrs } from '../../common/components/FormModal';
import Button from './Button';
import GroupBadge from './GroupBadge';
import Group from '../models/Group';
Expand All @@ -11,11 +11,11 @@ import type User from '../models/User';
import type { SaveAttributes, SaveRelationships } from '../Model';
import Form from './Form';

export interface IEditUserModalAttrs extends IInternalModalAttrs {
export interface IEditUserModalAttrs extends IFormModalAttrs {
user: User;
}

export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEditUserModalAttrs> extends Modal<CustomAttrs> {
export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEditUserModalAttrs> extends FormModal<CustomAttrs> {
protected username!: Stream<string>;
protected email!: Stream<string>;
protected isEmailConfirmed!: Stream<boolean>;
Expand Down
51 changes: 51 additions & 0 deletions framework/core/js/src/common/components/FormModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Modal from './Modal';
import type { IInternalModalAttrs } from './Modal';
import RequestError from '../utils/RequestError';
import Mithril from 'mithril';

export interface IFormModalAttrs extends IInternalModalAttrs {}

/**
* The `FormModal` component displays a modal dialog, wrapped in a form.
* Subclasses should implement the `className`, `title`, and `content` methods.
*/
export default abstract class FormModal<ModalAttrs extends IFormModalAttrs = IFormModalAttrs, CustomState = undefined> extends Modal<
ModalAttrs,
CustomState
> {
wrapper(children: Mithril.Children): Mithril.Children {
return <form onsubmit={this.onsubmit.bind(this)}>{children}</form>;
}

/**
* Handle the modal form's submit event.
*/
onsubmit(e: SubmitEvent): void {
// ...
}

/**
* Callback executed when the modal is shown and ready to be interacted with.
*
* @remark Focuses the first input in the modal.
*/
onready(): void {
this.$().find('input, select, textarea').first().trigger('focus').trigger('select');
}

/**
* Shows an alert describing an error returned from the API, and gives focus to
* the first relevant field involved in the error.
*/
onerror(error: RequestError): void {
this.alertAttrs = error.alert;

m.redraw();

if (error.status === 422 && error.response?.errors) {
this.$('form [name=' + (error.response.errors as any[])[0].source.pointer.replace('/data/attributes/', '') + ']').trigger('select');
} else {
this.onready();
}
}
}
Loading
Loading