From 23b79f75604fd5441c2613068186c37047693936 Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sat, 31 Jul 2021 22:33:26 +0100 Subject: [PATCH 01/21] Rewrite AdminPage.js into Typescript --- js/src/admin/components/AdminPage.js | 177 ----------------- js/src/admin/components/AdminPage.tsx | 275 ++++++++++++++++++++++++++ 2 files changed, 275 insertions(+), 177 deletions(-) delete mode 100644 js/src/admin/components/AdminPage.js create mode 100644 js/src/admin/components/AdminPage.tsx diff --git a/js/src/admin/components/AdminPage.js b/js/src/admin/components/AdminPage.js deleted file mode 100644 index aca2b44c98..0000000000 --- a/js/src/admin/components/AdminPage.js +++ /dev/null @@ -1,177 +0,0 @@ -import app from '../../admin/app'; -import Page from '../../common/components/Page'; -import Button from '../../common/components/Button'; -import Switch from '../../common/components/Switch'; -import Select from '../../common/components/Select'; -import classList from '../../common/utils/classList'; -import Stream from '../../common/utils/Stream'; -import saveSettings from '../utils/saveSettings'; -import AdminHeader from './AdminHeader'; - -export default class AdminPage extends Page { - oninit(vnode) { - super.oninit(vnode); - - this.settings = {}; - - this.loading = false; - } - - view() { - const className = classList(['AdminPage', this.headerInfo().className]); - - return ( -
- {this.header()} -
{this.content()}
-
- ); - } - - content() { - return ''; - } - - submitButton() { - return ( - - ); - } - - header() { - const headerInfo = this.headerInfo(); - - return ( - - {headerInfo.title} - - ); - } - - headerInfo() { - return { - className: '', - icon: '', - title: '', - description: '', - }; - } - - /** - * buildSettingComponent takes a settings object and turns it into a component. - * Depending on the type of input, you can set the type to 'bool', 'select', or - * any standard type. Any values inside the 'extra' object will be added - * to the component as an attribute. - * - * Alternatively, you can pass a callback that will be executed in ExtensionPage's - * context to include custom JSX elements. - * - * @example - * - * { - * setting: 'acme.checkbox', - * label: app.translator.trans('acme.admin.setting_label'), - * type: 'bool', - * help: app.translator.trans('acme.admin.setting_help'), - * className: 'Setting-item' - * } - * - * @example - * - * { - * setting: 'acme.select', - * label: app.translator.trans('acme.admin.setting_label'), - * type: 'select', - * options: { - * 'option1': 'Option 1 label', - * 'option2': 'Option 2 label', - * }, - * default: 'option1', - * } - * - * @param setting - * @returns {JSX.Element} - */ - buildSettingComponent(entry) { - if (typeof entry === 'function') { - return entry.call(this); - } - - const { setting, help, type, label, ...componentAttrs } = entry; - - const value = this.setting(setting)(); - - if (['bool', 'checkbox', 'switch', 'boolean'].includes(type)) { - return ( -
- - {label} - -
{help}
-
- ); - } else if (['select', 'dropdown', 'selectdropdown'].includes(type)) { - const { default: defaultValue, options } = componentAttrs; - - return ( -
- -
{help}
- -
- ); - } - } - - onsaved() { - this.loading = false; - - app.alerts.show({ type: 'success' }, app.translator.trans('core.admin.settings.saved_message')); - } - - setting(key, fallback = '') { - this.settings[key] = this.settings[key] || Stream(app.data.settings[key] || fallback); - - return this.settings[key]; - } - - dirty() { - const dirty = {}; - - Object.keys(this.settings).forEach((key) => { - const value = this.settings[key](); - - if (value !== app.data.settings[key]) { - dirty[key] = value; - } - }); - - return dirty; - } - - isChanged() { - return Object.keys(this.dirty()).length; - } - - saveSettings(e) { - e.preventDefault(); - - app.alerts.clear(); - - this.loading = true; - - return saveSettings(this.dirty()).then(this.onsaved.bind(this)); - } -} diff --git a/js/src/admin/components/AdminPage.tsx b/js/src/admin/components/AdminPage.tsx new file mode 100644 index 0000000000..2f4dc859fd --- /dev/null +++ b/js/src/admin/components/AdminPage.tsx @@ -0,0 +1,275 @@ +import Page from '../../common/components/Page'; +import Button from '../../common/components/Button'; +import Switch from '../../common/components/Switch'; +import Select from '../../common/components/Select'; +import classList from '../../common/utils/classList'; +import Stream from '../../common/utils/Stream'; +import saveSettings from '../utils/saveSettings'; +import AdminHeader from './AdminHeader'; +import type Mithril from 'mithril'; + +interface AdminHeaderOptions { + title: string; + description: string; + icon: string; + /** + * Will be used as the class for the AdminPage. + * + * Will also be appended with `-header` and set as the class for the `AdminHeader` component. + */ + className: string; +} + +type HTMLInputTypes = + | 'button' + | 'checkbox' + | 'color' + | 'date' + | 'datetime-local' + | 'email' + | 'file' + | 'hidden' + | 'image' + | 'month' + | 'number' + | 'password' + | 'radio' + | 'range' + | 'reset' + | 'search' + | 'submit' + | 'tel' + | 'text' + | 'time' + | 'url' + | 'week'; + +interface CommonSettingsItemOptions extends Mithril.Attributes { + setting: string; + label: string | ReturnType; + help?: string | ReturnType; + className?: string; +} + +interface HTMLInputSettingsComponentOptions extends CommonSettingsItemOptions { + /** + * Any valid HTML input `type` value. + */ + type: HTMLInputTypes; +} + +interface SwitchSettingComponentOptions extends CommonSettingsItemOptions { + type: 'bool' | 'checkbox' | 'switch' | 'boolean'; +} + +interface SelectSettingComponentOptions extends CommonSettingsItemOptions { + type: 'select' | 'dropdown' | 'selectdropdown'; + /** + * Map of values to their labels + */ + options: { [value: string]: string | ReturnType }; + default: string; +} + +export type SettingsComponentOptions = HTMLInputSettingsComponentOptions | SwitchSettingComponentOptions | SelectSettingComponentOptions; + +export type AdminHeaderAttrs = AdminHeaderOptions & Partial>; + +export default class AdminPage extends Page { + settings: Record string> = {}; + loading: boolean = false; + + oninit(vnode: Mithril.Vnode, this>) { + super.oninit(vnode); + } + + view(vnode: Mithril.Vnode, this>) { + const className = classList('AdminPage', this.headerInfo().className); + + return ( +
+ {this.header(vnode)} +
{this.content(vnode)}
+
+ ); + } + + /** + * Returns the content of the AdminPage. + */ + content(vnode: Mithril.Vnode, this>): Mithril.Children { + return ''; + } + + /** + * Returns the submit button for this AdminPage. + * + * Calls `this.saveSettings` when the button is clicked. + */ + submitButton(vnode: Mithril.Vnode, this>): Mithril.Children { + return ( + + ); + } + + /** + * Returns the Header component for this AdminPage. + */ + header(vnode: Mithril.Vnode, this>): Mithril.Children { + const { title, className, ...headerAttrs } = this.headerInfo(); + + return ( + + {title} + + ); + } + + /** + * Returns the options passed to the AdminHeader component. + */ + headerInfo(): AdminHeaderAttrs { + return { + className: '', + icon: '', + title: '', + description: '', + }; + } + + /** + * `buildSettingComponent` takes a settings object and turns it into a component. + * Depending on the type of input, you can set the type to 'bool', 'select', or + * any standard type. Any values inside the 'extra' object will be added + * to the component as an attribute. + * + * Alternatively, you can pass a callback that will be executed in ExtensionPage's + * context to include custom JSX elements. + * + * @example + * + * { + * setting: 'acme.checkbox', + * label: app.translator.trans('acme.admin.setting_label'), + * type: 'bool', + * help: app.translator.trans('acme.admin.setting_help'), + * className: 'Setting-item' + * } + * + * @example + * + * { + * setting: 'acme.select', + * label: app.translator.trans('acme.admin.setting_label'), + * type: 'select', + * options: { + * 'option1': 'Option 1 label', + * 'option2': 'Option 2 label', + * }, + * default: 'option1', + * } + * + * @example + * + * () => { + * return

My cool component

; + * } + */ + buildSettingComponent(entry: ((this: typeof this) => Mithril.Children) | SettingsComponentOptions): Mithril.Children { + if (typeof entry === 'function') { + return entry.call(this); + } + + const { setting, help, type, label, ...componentAttrs } = entry; + + const value = this.setting(setting)(); + + if (['bool', 'checkbox', 'switch', 'boolean'].includes(type)) { + return ( +
+ + {label} + +
{help}
+
+ ); + } else if (['select', 'dropdown', 'selectdropdown'].includes(type)) { + const { default: defaultValue, options, ...otherAttrs } = componentAttrs; + + return ( +
+ +
{help}
+ +
+ ); + } + } + + /** + * Called when `saveSettings` completes successfully. + */ + onsaved(): void { + this.loading = false; + + app.alerts.show({ type: 'success' }, app.translator.trans('core.admin.settings.saved_message')); + } + + /** + * Returns a function that fetches the setting from the `app` global. + */ + setting(key: string, fallback: string = ''): () => string { + this.settings[key] = this.settings[key] || Stream(app.data.settings[key] || fallback); + + return this.settings[key]; + } + + /** + * Returns a list of settings that have been modified, but not yet saved. + */ + dirty(): Record { + const dirty: Record = {}; + + Object.keys(this.settings).forEach((key) => { + const value = this.settings[key](); + + if (value !== app.data.settings[key]) { + dirty[key] = value; + } + }); + + return dirty; + } + + /** + * Returns the number of settings that have been modified. + */ + isChanged(): number { + return Object.keys(this.dirty()).length; + } + + /** + * Saves the modified settings to the database. + */ + saveSettings(e: SubmitEvent & { redraw: boolean }) { + e.preventDefault(); + + app.alerts.clear(); + + this.loading = true; + + return saveSettings(this.dirty()).then(this.onsaved.bind(this)); + } +} From 3639b943624114f435248083f4b6bc0105b6558a Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sat, 31 Jul 2021 22:39:32 +0100 Subject: [PATCH 02/21] Export more interfaces and types --- js/src/admin/components/AdminPage.tsx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/js/src/admin/components/AdminPage.tsx b/js/src/admin/components/AdminPage.tsx index 2f4dc859fd..844f386c5d 100644 --- a/js/src/admin/components/AdminPage.tsx +++ b/js/src/admin/components/AdminPage.tsx @@ -51,18 +51,27 @@ interface CommonSettingsItemOptions extends Mithril.Attributes { className?: string; } -interface HTMLInputSettingsComponentOptions extends CommonSettingsItemOptions { +/** + * Valid options for the setting component builder to generate an HTML input element. + */ +export interface HTMLInputSettingsComponentOptions extends CommonSettingsItemOptions { /** * Any valid HTML input `type` value. */ type: HTMLInputTypes; } -interface SwitchSettingComponentOptions extends CommonSettingsItemOptions { +/** + * Valid options for the setting component builder to generate a Switch. + */ +export interface SwitchSettingComponentOptions extends CommonSettingsItemOptions { type: 'bool' | 'checkbox' | 'switch' | 'boolean'; } -interface SelectSettingComponentOptions extends CommonSettingsItemOptions { +/** + * Valid options for the setting component builder to generate a Select dropdown. + */ +export interface SelectSettingComponentOptions extends CommonSettingsItemOptions { type: 'select' | 'dropdown' | 'selectdropdown'; /** * Map of values to their labels @@ -71,8 +80,14 @@ interface SelectSettingComponentOptions extends CommonSettingsItemOptions { default: string; } +/** + * All valid options for the setting component builder. + */ export type SettingsComponentOptions = HTMLInputSettingsComponentOptions | SwitchSettingComponentOptions | SelectSettingComponentOptions; +/** + * Valid attrs that can be returned by the `headerInfo` function + */ export type AdminHeaderAttrs = AdminHeaderOptions & Partial>; export default class AdminPage extends Page { From 32c81250911f9667aacab9b2d7dfeaacbceb7a90 Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Mon, 9 Aug 2021 18:03:28 +0200 Subject: [PATCH 03/21] Use Stream type --- js/src/admin/components/AdminPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/admin/components/AdminPage.tsx b/js/src/admin/components/AdminPage.tsx index 844f386c5d..5ef89eb788 100644 --- a/js/src/admin/components/AdminPage.tsx +++ b/js/src/admin/components/AdminPage.tsx @@ -91,7 +91,7 @@ export type SettingsComponentOptions = HTMLInputSettingsComponentOptions | Switc export type AdminHeaderAttrs = AdminHeaderOptions & Partial>; export default class AdminPage extends Page { - settings: Record string> = {}; + settings!: Record>; loading: boolean = false; oninit(vnode: Mithril.Vnode, this>) { From b336fd63740ff8543e1e6a72b7b17559edcfd279 Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Tue, 10 Aug 2021 21:08:54 +0200 Subject: [PATCH 04/21] Update js/src/admin/components/AdminPage.tsx Co-authored-by: Sami Mazouz --- js/src/admin/components/AdminPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/admin/components/AdminPage.tsx b/js/src/admin/components/AdminPage.tsx index 5ef89eb788..3a3ff04fc6 100644 --- a/js/src/admin/components/AdminPage.tsx +++ b/js/src/admin/components/AdminPage.tsx @@ -245,7 +245,7 @@ export default class AdminPage extends Page { /** * Returns a function that fetches the setting from the `app` global. */ - setting(key: string, fallback: string = ''): () => string { + setting(key: string, fallback: string = ''): Stream { this.settings[key] = this.settings[key] || Stream(app.data.settings[key] || fallback); return this.settings[key]; From c900cb3f6d50c7e315aeb9a97ec966c5fe2134d1 Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Fri, 20 Aug 2021 23:59:54 +0200 Subject: [PATCH 05/21] Move `HTMLInputTypes` type to global declarations --- js/src/@types/global.d.ts | 28 +++++++++++++++++++++++++++ js/src/admin/components/AdminPage.tsx | 24 ----------------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/js/src/@types/global.d.ts b/js/src/@types/global.d.ts index 82019b82d7..db508e78ed 100644 --- a/js/src/@types/global.d.ts +++ b/js/src/@types/global.d.ts @@ -1,3 +1,31 @@ +/** + * A type that matches any valid value for the `type` attribute on an + * HTML `` element. + */ +declare type HTMLInputTypes = + | 'button' + | 'checkbox' + | 'color' + | 'date' + | 'datetime-local' + | 'email' + | 'file' + | 'hidden' + | 'image' + | 'month' + | 'number' + | 'password' + | 'radio' + | 'range' + | 'reset' + | 'search' + | 'submit' + | 'tel' + | 'text' + | 'time' + | 'url' + | 'week'; + /** * @deprecated Please import `app` from a namespace instead of using it as a global variable. * diff --git a/js/src/admin/components/AdminPage.tsx b/js/src/admin/components/AdminPage.tsx index 3a3ff04fc6..ca6361959e 100644 --- a/js/src/admin/components/AdminPage.tsx +++ b/js/src/admin/components/AdminPage.tsx @@ -20,30 +20,6 @@ interface AdminHeaderOptions { className: string; } -type HTMLInputTypes = - | 'button' - | 'checkbox' - | 'color' - | 'date' - | 'datetime-local' - | 'email' - | 'file' - | 'hidden' - | 'image' - | 'month' - | 'number' - | 'password' - | 'radio' - | 'range' - | 'reset' - | 'search' - | 'submit' - | 'tel' - | 'text' - | 'time' - | 'url' - | 'week'; - interface CommonSettingsItemOptions extends Mithril.Attributes { setting: string; label: string | ReturnType; From 716a37792da4cee61a777ba2fe37d35f247fd2bd Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sat, 21 Aug 2021 00:00:11 +0200 Subject: [PATCH 06/21] Add missing app import --- js/src/admin/components/AdminPage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/src/admin/components/AdminPage.tsx b/js/src/admin/components/AdminPage.tsx index ca6361959e..859a9af25a 100644 --- a/js/src/admin/components/AdminPage.tsx +++ b/js/src/admin/components/AdminPage.tsx @@ -1,3 +1,6 @@ +import type Mithril from 'mithril'; + +import app from '../app'; import Page from '../../common/components/Page'; import Button from '../../common/components/Button'; import Switch from '../../common/components/Switch'; @@ -6,7 +9,6 @@ import classList from '../../common/utils/classList'; import Stream from '../../common/utils/Stream'; import saveSettings from '../utils/saveSettings'; import AdminHeader from './AdminHeader'; -import type Mithril from 'mithril'; interface AdminHeaderOptions { title: string; From 0d1d3ac9bf9d9b14aa691ae9b61922f27a6d66b2 Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sat, 21 Aug 2021 00:00:23 +0200 Subject: [PATCH 07/21] Export options interface --- js/src/admin/components/AdminPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/admin/components/AdminPage.tsx b/js/src/admin/components/AdminPage.tsx index 859a9af25a..3faa2ee27c 100644 --- a/js/src/admin/components/AdminPage.tsx +++ b/js/src/admin/components/AdminPage.tsx @@ -10,7 +10,7 @@ import Stream from '../../common/utils/Stream'; import saveSettings from '../utils/saveSettings'; import AdminHeader from './AdminHeader'; -interface AdminHeaderOptions { +export interface AdminHeaderOptions { title: string; description: string; icon: string; From e26498385c575b60bce296137fa919e932ed71de Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sat, 21 Aug 2021 00:00:35 +0200 Subject: [PATCH 08/21] Remove unused method --- js/src/admin/components/AdminPage.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/js/src/admin/components/AdminPage.tsx b/js/src/admin/components/AdminPage.tsx index 3faa2ee27c..0a0115f7f9 100644 --- a/js/src/admin/components/AdminPage.tsx +++ b/js/src/admin/components/AdminPage.tsx @@ -72,10 +72,6 @@ export default class AdminPage extends Page { settings!: Record>; loading: boolean = false; - oninit(vnode: Mithril.Vnode, this>) { - super.oninit(vnode); - } - view(vnode: Mithril.Vnode, this>) { const className = classList('AdminPage', this.headerInfo().className); From dad40bc3b190585e7a461be9a26cf0f59ad75840 Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sat, 21 Aug 2021 00:50:59 +0200 Subject: [PATCH 09/21] Add random element ID generator --- js/package-lock.json | 17 +++++++++++++++++ js/package.json | 1 + js/src/admin/compat.js | 2 ++ js/src/admin/utils/generateElementId.ts | 1 + 4 files changed, 21 insertions(+) create mode 100644 js/src/admin/utils/generateElementId.ts diff --git a/js/package-lock.json b/js/package-lock.json index 2b2d45a9d6..efe81d05ed 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -16,6 +16,7 @@ "jquery": "^3.6.0", "jquery.hotkeys": "^0.1.0", "mithril": "^2.0.4", + "nanoid": "^3.1.25", "punycode": "^2.1.1", "textarea-caret": "^3.1.0", "throttle-debounce": "^3.0.1" @@ -4649,6 +4650,17 @@ "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", "optional": true }, + "node_modules/nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -11081,6 +11093,11 @@ "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", "optional": true }, + "nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==" + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", diff --git a/js/package.json b/js/package.json index 6ebed0b493..a43d17131e 100644 --- a/js/package.json +++ b/js/package.json @@ -13,6 +13,7 @@ "jquery": "^3.6.0", "jquery.hotkeys": "^0.1.0", "mithril": "^2.0.4", + "nanoid": "^3.1.25", "punycode": "^2.1.1", "textarea-caret": "^3.1.0", "throttle-debounce": "^3.0.1" diff --git a/js/src/admin/compat.js b/js/src/admin/compat.js index 96b13bc5a5..9ff8d9b58b 100644 --- a/js/src/admin/compat.js +++ b/js/src/admin/compat.js @@ -34,12 +34,14 @@ import EditCustomCssModal from './components/EditCustomCssModal'; import EditGroupModal from './components/EditGroupModal'; import routes from './routes'; import AdminApplication from './AdminApplication'; +import generateElementId from './utils/generateElementId'; export default Object.assign(compat, { 'utils/saveSettings': saveSettings, 'utils/ExtensionData': ExtensionData, 'utils/isExtensionEnabled': isExtensionEnabled, 'utils/getCategorizedExtensions': getCategorizedExtensions, + 'utils/generateElementId': generateElementId, 'components/SettingDropdown': SettingDropdown, 'components/EditCustomFooterModal': EditCustomFooterModal, 'components/SessionDropdown': SessionDropdown, diff --git a/js/src/admin/utils/generateElementId.ts b/js/src/admin/utils/generateElementId.ts new file mode 100644 index 0000000000..f7c758f3bc --- /dev/null +++ b/js/src/admin/utils/generateElementId.ts @@ -0,0 +1 @@ +export { nanoid as default } from 'nanoid'; From 13d976d9956571dd1fad3aa96f9677b982c4626a Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sat, 21 Aug 2021 00:51:21 +0200 Subject: [PATCH 10/21] Add attrs for Page component Full rewrite needed later --- js/src/common/components/{Page.js => Page.tsx} | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) rename js/src/common/components/{Page.js => Page.tsx} (86%) diff --git a/js/src/common/components/Page.js b/js/src/common/components/Page.tsx similarity index 86% rename from js/src/common/components/Page.js rename to js/src/common/components/Page.tsx index 531ffa3171..c8ff39be0d 100644 --- a/js/src/common/components/Page.js +++ b/js/src/common/components/Page.tsx @@ -1,13 +1,18 @@ -import app from '../../common/app'; +import app from '../app'; import Component from '../Component'; import PageState from '../states/PageState'; +export interface IPageAttrs { + key?: number; + routeName: string; +} + /** * The `Page` component * * @abstract */ -export default class Page extends Component { +export default class Page extends Component { oninit(vnode) { super.oninit(vnode); From 19d44616bcdf68a108214c0a11a54f4c00fa7691 Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sat, 21 Aug 2021 00:51:47 +0200 Subject: [PATCH 11/21] Provide correct attrs --- js/src/admin/components/AdminPage.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/src/admin/components/AdminPage.tsx b/js/src/admin/components/AdminPage.tsx index 0a0115f7f9..e458ae24b7 100644 --- a/js/src/admin/components/AdminPage.tsx +++ b/js/src/admin/components/AdminPage.tsx @@ -1,7 +1,7 @@ import type Mithril from 'mithril'; import app from '../app'; -import Page from '../../common/components/Page'; +import Page, { IPageAttrs } from '../../common/components/Page'; import Button from '../../common/components/Button'; import Switch from '../../common/components/Switch'; import Select from '../../common/components/Select'; @@ -68,11 +68,11 @@ export type SettingsComponentOptions = HTMLInputSettingsComponentOptions | Switc */ export type AdminHeaderAttrs = AdminHeaderOptions & Partial>; -export default class AdminPage extends Page { +export default class AdminPage extends Page { settings!: Record>; loading: boolean = false; - view(vnode: Mithril.Vnode, this>) { + view(vnode: Mithril.Vnode) { const className = classList('AdminPage', this.headerInfo().className); return ( @@ -86,7 +86,7 @@ export default class AdminPage extends Page { /** * Returns the content of the AdminPage. */ - content(vnode: Mithril.Vnode, this>): Mithril.Children { + content(vnode: Mithril.Vnode): Mithril.Children { return ''; } @@ -95,7 +95,7 @@ export default class AdminPage extends Page { * * Calls `this.saveSettings` when the button is clicked. */ - submitButton(vnode: Mithril.Vnode, this>): Mithril.Children { + submitButton(vnode: Mithril.Vnode): Mithril.Children { return (