From 2831ce226c663b9b0280f0ab093da70fca2b4178 Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Thu, 19 Aug 2021 11:10:40 +0200 Subject: [PATCH] Fix global typings for extensions (#2992) * Fix global typings for extensions * Deprecate global `app` typings See https://github.com/flarum/core/issues/2857#issuecomment-889841326 * Add `app` export for common namespace * Add missing `app` imports within core * Add missing `app` imports to JS files * Fix incorrect import * Fix admin file importing forum `app` * Add `flarum` global variable * Format * Update JSDoc comment * Update JSDoc comment Co-authored-by: Alexander Skvortsov * Fix frontend JS error * Empty commit Co-authored-by: Alexander Skvortsov --- js/@types/global/index.d.ts | 53 ------------ js/package.json | 2 +- js/src/@types/global.d.ts | 82 +++++++++++++++++++ js/{ => src}/@types/tooltips/index.d.ts | 0 js/src/admin/components/AdminNav.js | 1 + js/src/admin/components/AdminPage.js | 1 + js/src/admin/components/AppearancePage.js | 1 + js/src/admin/components/BasicsPage.js | 1 + js/src/admin/components/DashboardPage.js | 1 + js/src/admin/components/EditCustomCssModal.js | 1 + .../admin/components/EditCustomFooterModal.js | 1 + .../admin/components/EditCustomHeaderModal.js | 1 + js/src/admin/components/EditGroupModal.js | 1 + .../admin/components/ExtensionLinkButton.js | 1 + js/src/admin/components/ExtensionPage.js | 1 + .../components/ExtensionPermissionGrid.js | 1 + js/src/admin/components/ExtensionsWidget.js | 1 + js/src/admin/components/HeaderSecondary.js | 1 + js/src/admin/components/LoadingModal.js | 1 + js/src/admin/components/MailPage.js | 1 + js/src/admin/components/PermissionDropdown.js | 1 + js/src/admin/components/PermissionGrid.js | 1 + js/src/admin/components/PermissionsPage.js | 1 + js/src/admin/components/SessionDropdown.js | 1 + js/src/admin/components/SettingDropdown.js | 1 + js/src/admin/components/SettingsModal.js | 1 + js/src/admin/components/StatusWidget.js | 1 + js/src/admin/components/UploadImageButton.js | 1 + js/src/admin/components/UserListPage.tsx | 2 + .../admin/resolvers/ExtensionPageResolver.ts | 1 + .../admin/utils/getCategorizedExtensions.js | 2 + js/src/admin/utils/isExtensionEnabled.js | 2 + js/src/admin/utils/saveSettings.js | 2 + js/src/common/Application.js | 2 + js/src/common/Component.ts | 2 +- js/src/common/Fragment.ts | 2 +- js/src/common/Model.js | 2 + js/src/common/Session.js | 2 + js/src/common/Store.js | 1 + js/src/common/app.ts | 31 +++++++ js/src/common/components/Alert.tsx | 2 +- js/src/common/components/Dropdown.js | 1 + js/src/common/components/EditUserModal.js | 1 + js/src/common/components/LoadingIndicator.tsx | 1 + js/src/common/components/Navigation.js | 1 + js/src/common/components/Page.js | 1 + js/src/common/components/TextEditor.js | 2 + js/src/common/helpers/avatar.tsx | 2 +- js/src/common/helpers/fullTime.tsx | 2 +- js/src/common/helpers/highlight.tsx | 2 +- js/src/common/helpers/humanTime.tsx | 2 +- js/src/common/helpers/icon.tsx | 2 +- js/src/common/helpers/listItems.tsx | 2 +- js/src/common/helpers/punctuateSeries.js | 2 + js/src/common/helpers/userOnline.tsx | 2 +- js/src/common/helpers/username.tsx | 3 +- js/src/common/index.js | 3 +- js/src/common/models/Discussion.js | 1 + js/src/common/resolvers/DefaultResolver.ts | 2 +- js/src/common/states/AlertManagerState.ts | 2 +- js/src/common/states/PaginatedListState.ts | 1 + js/src/common/utils/abbreviateNumber.ts | 2 + .../common/utils/setRouteWithForcedRefresh.ts | 2 +- js/src/forum/ForumApplication.js | 1 + js/src/forum/components/AvatarEditor.js | 1 + js/src/forum/components/ChangeEmailModal.js | 1 + .../forum/components/ChangePasswordModal.js | 1 + js/src/forum/components/CommentPost.js | 1 + js/src/forum/components/Composer.js | 1 + js/src/forum/components/DiscussionComposer.js | 1 + js/src/forum/components/DiscussionList.js | 4 +- js/src/forum/components/DiscussionListItem.js | 1 + js/src/forum/components/DiscussionListPane.js | 1 + js/src/forum/components/DiscussionPage.js | 1 + .../DiscussionRenamedNotification.js | 1 + .../forum/components/DiscussionRenamedPost.js | 1 + .../components/DiscussionsSearchSource.tsx | 3 +- js/src/forum/components/EditPostComposer.js | 1 + js/src/forum/components/EventPost.js | 1 + .../forum/components/ForgotPasswordModal.js | 1 + js/src/forum/components/HeaderSecondary.js | 1 + js/src/forum/components/IndexPage.js | 2 +- js/src/forum/components/LogInButton.js | 1 + js/src/forum/components/LogInModal.js | 1 + js/src/forum/components/Notification.js | 1 + js/src/forum/components/NotificationGrid.js | 1 + js/src/forum/components/NotificationList.js | 1 + .../forum/components/NotificationsDropdown.js | 1 + js/src/forum/components/NotificationsPage.js | 1 + js/src/forum/components/Post.js | 1 + js/src/forum/components/PostEdited.js | 1 + js/src/forum/components/PostMeta.js | 1 + js/src/forum/components/PostPreview.js | 1 + js/src/forum/components/PostStream.js | 1 + js/src/forum/components/PostStreamScrubber.js | 1 + js/src/forum/components/PostUser.js | 1 + js/src/forum/components/PostsUserPage.js | 1 + .../forum/components/RenameDiscussionModal.js | 1 + js/src/forum/components/ReplyComposer.js | 1 + js/src/forum/components/ReplyPlaceholder.js | 3 +- js/src/forum/components/Search.tsx | 3 +- js/src/forum/components/SessionDropdown.js | 1 + js/src/forum/components/SettingsPage.js | 1 + js/src/forum/components/SignUpModal.js | 1 + js/src/forum/components/TerminalPost.js | 1 + js/src/forum/components/UserCard.js | 1 + js/src/forum/components/UserPage.js | 1 + js/src/forum/components/UsersSearchSource.tsx | 3 +- js/src/forum/components/WelcomeHero.js | 1 + .../forum/resolvers/DiscussionPageResolver.ts | 1 + js/src/forum/states/ComposerState.js | 1 + js/src/forum/states/DiscussionListState.ts | 1 + js/src/forum/states/GlobalSearchState.ts | 1 + js/src/forum/states/NotificationListState.ts | 1 + js/src/forum/states/PostStreamState.js | 1 + js/src/forum/utils/DiscussionControls.js | 1 + js/src/forum/utils/PostControls.js | 1 + js/src/forum/utils/UserControls.js | 1 + 118 files changed, 243 insertions(+), 77 deletions(-) delete mode 100644 js/@types/global/index.d.ts create mode 100644 js/src/@types/global.d.ts rename js/{ => src}/@types/tooltips/index.d.ts (100%) create mode 100644 js/src/common/app.ts diff --git a/js/@types/global/index.d.ts b/js/@types/global/index.d.ts deleted file mode 100644 index 9d830686b..000000000 --- a/js/@types/global/index.d.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Mithril -import Mithril from 'mithril'; - -// Other third-party libs -import * as _dayjs from 'dayjs'; -import 'dayjs/plugin/relativeTime'; -import * as _$ from 'jquery'; - -// Globals from flarum/core -import Application from '../../src/common/Application'; - -import type { TooltipJQueryFunction } from '../tooltips'; - -/** - * flarum/core exposes several extensions globally: - * - * - jQuery for convenient DOM manipulation - * - Mithril for VDOM and components - * - dayjs for date/time operations - * - * Since these are already part of the global namespace, extensions won't need - * to (and should not) bundle these themselves. - */ -declare global { - // $ is already defined by `@types/jquery` - const m: Mithril.Static; - const dayjs: typeof _dayjs; - - // Extend JQuery with our custom functions, defined with $.fn - interface JQuery { - tooltip: TooltipJQueryFunction; - } - - /** - * For more info, see: https://www.typescriptlang.org/docs/handbook/jsx.html#attribute-type-checking - * - * In a nutshell, we need to add `ElementAttributesProperty` to tell Typescript - * what property on component classes to look at for attribute typings. For our - * Component class, this would be `attrs` (e.g. `this.attrs...`) - */ - namespace JSX { - interface ElementAttributesProperty { - attrs: Record; - } - } -} - -/** - * All global variables owned by flarum/core. - */ -declare global { - const app: Application; -} diff --git a/js/package.json b/js/package.json index 2dc2981b3..6ebed0b49 100644 --- a/js/package.json +++ b/js/package.json @@ -41,6 +41,6 @@ "format": "prettier --write src", "format-check": "prettier --check src", "clean-typings": "npx rimraf dist-typings && mkdir dist-typings", - "build-typings": "npm run clean-typings && cp -r @types dist-typings/@types && tsc" + "build-typings": "npm run clean-typings && cp -r src/@types dist-typings/@types && tsc" } } diff --git a/js/src/@types/global.d.ts b/js/src/@types/global.d.ts new file mode 100644 index 000000000..82019b82d --- /dev/null +++ b/js/src/@types/global.d.ts @@ -0,0 +1,82 @@ +/** + * @deprecated Please import `app` from a namespace instead of using it as a global variable. + * + * @example App in forum JS + * ``` + * import app from 'flarum/forum/app'; + * ``` + * + * @example App in admin JS + * ``` + * import app from 'flarum/admin/app'; + * ``` + * + * @example App in common JS + * ``` + * import app from 'flarum/common/app'; + * ``` + */ +declare const app: never; + +declare const m: import('mithril').Static; +declare const dayjs: typeof import('dayjs'); + +type ESModule = { __esModule: true; [key: string]: unknown }; + +/** + * The global `flarum` variable. + * + * Contains the compiled ES Modules for all Flarum extensions and core. + * + * @example Check if `flarum-tags` is present + * if ('flarum-tags' in flarum.extensions) { + * // Tags is installed and enabled! + * } + */ +interface FlarumObject { + /** + * Contains the compiled ES Module for Flarum's core. + * + * You shouldn't need to access this directly for any reason. + */ + core: Readonly; + /** + * Contains the compiled ES Modules for all Flarum extensions. + * + * @example Check if `flarum-tags` is present + * if ('flarum-tags' in flarum.extensions) { + * // Tags is installed and enabled! + * } + */ + extensions: Readonly>; +} + +declare const flarum: FlarumObject; + +// Extend JQuery with our custom functions, defined with $.fn +interface JQuery { + /** + * Flarum's tooltip JQuery plugin. + * + * Do not use this directly. Instead use the `` component that + * is exported from `flarum/common/components/Tooltip`. + * + * This will be removed in a future version of Flarum. + * + * @deprecated + */ + tooltip: import('./tooltips/index').TooltipJQueryFunction; +} + +/** + * For more info, see: https://www.typescriptlang.org/docs/handbook/jsx.html#attribute-type-checking + * + * In a nutshell, we need to add `ElementAttributesProperty` to tell Typescript + * what property on component classes to look at for attribute typings. For our + * Component class, this would be `attrs` (e.g. `this.attrs...`) + */ +interface JSX { + ElementAttributesProperty: { + attrs: Record; + }; +} diff --git a/js/@types/tooltips/index.d.ts b/js/src/@types/tooltips/index.d.ts similarity index 100% rename from js/@types/tooltips/index.d.ts rename to js/src/@types/tooltips/index.d.ts diff --git a/js/src/admin/components/AdminNav.js b/js/src/admin/components/AdminNav.js index 4e6fffb0f..36f7cd906 100644 --- a/js/src/admin/components/AdminNav.js +++ b/js/src/admin/components/AdminNav.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import ExtensionLinkButton from './ExtensionLinkButton'; import Component from '../../common/Component'; import LinkButton from '../../common/components/LinkButton'; diff --git a/js/src/admin/components/AdminPage.js b/js/src/admin/components/AdminPage.js index 8ecfbdd12..aca2b44c9 100644 --- a/js/src/admin/components/AdminPage.js +++ b/js/src/admin/components/AdminPage.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Page from '../../common/components/Page'; import Button from '../../common/components/Button'; import Switch from '../../common/components/Switch'; diff --git a/js/src/admin/components/AppearancePage.js b/js/src/admin/components/AppearancePage.js index ad728e269..727cf8deb 100644 --- a/js/src/admin/components/AppearancePage.js +++ b/js/src/admin/components/AppearancePage.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Button from '../../common/components/Button'; import EditCustomCssModal from './EditCustomCssModal'; import EditCustomHeaderModal from './EditCustomHeaderModal'; diff --git a/js/src/admin/components/BasicsPage.js b/js/src/admin/components/BasicsPage.js index a437b8a50..d2e70a99d 100644 --- a/js/src/admin/components/BasicsPage.js +++ b/js/src/admin/components/BasicsPage.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import FieldSet from '../../common/components/FieldSet'; import ItemList from '../../common/utils/ItemList'; import AdminPage from './AdminPage'; diff --git a/js/src/admin/components/DashboardPage.js b/js/src/admin/components/DashboardPage.js index d606e1a62..006c24b4f 100644 --- a/js/src/admin/components/DashboardPage.js +++ b/js/src/admin/components/DashboardPage.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import StatusWidget from './StatusWidget'; import ExtensionsWidget from './ExtensionsWidget'; import ItemList from '../../common/utils/ItemList'; diff --git a/js/src/admin/components/EditCustomCssModal.js b/js/src/admin/components/EditCustomCssModal.js index bd855d545..79a9db0bc 100644 --- a/js/src/admin/components/EditCustomCssModal.js +++ b/js/src/admin/components/EditCustomCssModal.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import SettingsModal from './SettingsModal'; export default class EditCustomCssModal extends SettingsModal { diff --git a/js/src/admin/components/EditCustomFooterModal.js b/js/src/admin/components/EditCustomFooterModal.js index 43cfd29d4..97188ec83 100644 --- a/js/src/admin/components/EditCustomFooterModal.js +++ b/js/src/admin/components/EditCustomFooterModal.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import SettingsModal from './SettingsModal'; export default class EditCustomFooterModal extends SettingsModal { diff --git a/js/src/admin/components/EditCustomHeaderModal.js b/js/src/admin/components/EditCustomHeaderModal.js index 11a1f8d4e..4da7afe9d 100644 --- a/js/src/admin/components/EditCustomHeaderModal.js +++ b/js/src/admin/components/EditCustomHeaderModal.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import SettingsModal from './SettingsModal'; export default class EditCustomHeaderModal extends SettingsModal { diff --git a/js/src/admin/components/EditGroupModal.js b/js/src/admin/components/EditGroupModal.js index 129af73a9..a347a5995 100644 --- a/js/src/admin/components/EditGroupModal.js +++ b/js/src/admin/components/EditGroupModal.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Modal from '../../common/components/Modal'; import Button from '../../common/components/Button'; import Badge from '../../common/components/Badge'; diff --git a/js/src/admin/components/ExtensionLinkButton.js b/js/src/admin/components/ExtensionLinkButton.js index 6415aa1a1..46a331c05 100644 --- a/js/src/admin/components/ExtensionLinkButton.js +++ b/js/src/admin/components/ExtensionLinkButton.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import isExtensionEnabled from '../utils/isExtensionEnabled'; import LinkButton from '../../common/components/LinkButton'; import icon from '../../common/helpers/icon'; diff --git a/js/src/admin/components/ExtensionPage.js b/js/src/admin/components/ExtensionPage.js index f3d1fd5ff..dc18f0348 100644 --- a/js/src/admin/components/ExtensionPage.js +++ b/js/src/admin/components/ExtensionPage.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Button from '../../common/components/Button'; import Link from '../../common/components/Link'; import LinkButton from '../../common/components/LinkButton'; diff --git a/js/src/admin/components/ExtensionPermissionGrid.js b/js/src/admin/components/ExtensionPermissionGrid.js index 876777c74..104a16dfa 100644 --- a/js/src/admin/components/ExtensionPermissionGrid.js +++ b/js/src/admin/components/ExtensionPermissionGrid.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import PermissionGrid from './PermissionGrid'; import Button from '../../common/components/Button'; import ItemList from '../../common/utils/ItemList'; diff --git a/js/src/admin/components/ExtensionsWidget.js b/js/src/admin/components/ExtensionsWidget.js index 0dd602356..0647f272f 100644 --- a/js/src/admin/components/ExtensionsWidget.js +++ b/js/src/admin/components/ExtensionsWidget.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import DashboardWidget from './DashboardWidget'; import isExtensionEnabled from '../utils/isExtensionEnabled'; import getCategorizedExtensions from '../utils/getCategorizedExtensions'; diff --git a/js/src/admin/components/HeaderSecondary.js b/js/src/admin/components/HeaderSecondary.js index 19f14b70d..d67618a89 100644 --- a/js/src/admin/components/HeaderSecondary.js +++ b/js/src/admin/components/HeaderSecondary.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Component from '../../common/Component'; import LinkButton from '../../common/components/LinkButton'; import SessionDropdown from './SessionDropdown'; diff --git a/js/src/admin/components/LoadingModal.js b/js/src/admin/components/LoadingModal.js index 7e055eebb..df2cb70b8 100644 --- a/js/src/admin/components/LoadingModal.js +++ b/js/src/admin/components/LoadingModal.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Modal from '../../common/components/Modal'; export default class LoadingModal extends Modal { diff --git a/js/src/admin/components/MailPage.js b/js/src/admin/components/MailPage.js index f03b7a583..5ac5d9be9 100644 --- a/js/src/admin/components/MailPage.js +++ b/js/src/admin/components/MailPage.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import FieldSet from '../../common/components/FieldSet'; import Button from '../../common/components/Button'; import Alert from '../../common/components/Alert'; diff --git a/js/src/admin/components/PermissionDropdown.js b/js/src/admin/components/PermissionDropdown.js index 999f72fcd..aa635d925 100644 --- a/js/src/admin/components/PermissionDropdown.js +++ b/js/src/admin/components/PermissionDropdown.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Dropdown from '../../common/components/Dropdown'; import Button from '../../common/components/Button'; import Separator from '../../common/components/Separator'; diff --git a/js/src/admin/components/PermissionGrid.js b/js/src/admin/components/PermissionGrid.js index b4a2a330f..384b1f594 100644 --- a/js/src/admin/components/PermissionGrid.js +++ b/js/src/admin/components/PermissionGrid.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Component from '../../common/Component'; import PermissionDropdown from './PermissionDropdown'; import SettingDropdown from './SettingDropdown'; diff --git a/js/src/admin/components/PermissionsPage.js b/js/src/admin/components/PermissionsPage.js index c7b34f7b5..c985fa35e 100644 --- a/js/src/admin/components/PermissionsPage.js +++ b/js/src/admin/components/PermissionsPage.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import GroupBadge from '../../common/components/GroupBadge'; import EditGroupModal from './EditGroupModal'; import Group from '../../common/models/Group'; diff --git a/js/src/admin/components/SessionDropdown.js b/js/src/admin/components/SessionDropdown.js index 4acca51b8..9e28775b4 100644 --- a/js/src/admin/components/SessionDropdown.js +++ b/js/src/admin/components/SessionDropdown.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import avatar from '../../common/helpers/avatar'; import username from '../../common/helpers/username'; import Dropdown from '../../common/components/Dropdown'; diff --git a/js/src/admin/components/SettingDropdown.js b/js/src/admin/components/SettingDropdown.js index 5338e92c0..b800215b4 100644 --- a/js/src/admin/components/SettingDropdown.js +++ b/js/src/admin/components/SettingDropdown.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import SelectDropdown from '../../common/components/SelectDropdown'; import Button from '../../common/components/Button'; import saveSettings from '../utils/saveSettings'; diff --git a/js/src/admin/components/SettingsModal.js b/js/src/admin/components/SettingsModal.js index 328c8753c..e108c78ae 100644 --- a/js/src/admin/components/SettingsModal.js +++ b/js/src/admin/components/SettingsModal.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Modal from '../../common/components/Modal'; import Button from '../../common/components/Button'; import Stream from '../../common/utils/Stream'; diff --git a/js/src/admin/components/StatusWidget.js b/js/src/admin/components/StatusWidget.js index 44aefa0c7..65f9b323b 100644 --- a/js/src/admin/components/StatusWidget.js +++ b/js/src/admin/components/StatusWidget.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import DashboardWidget from './DashboardWidget'; import listItems from '../../common/helpers/listItems'; import ItemList from '../../common/utils/ItemList'; diff --git a/js/src/admin/components/UploadImageButton.js b/js/src/admin/components/UploadImageButton.js index 2b63f587f..1af51aec6 100644 --- a/js/src/admin/components/UploadImageButton.js +++ b/js/src/admin/components/UploadImageButton.js @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import Button from '../../common/components/Button'; export default class UploadImageButton extends Button { diff --git a/js/src/admin/components/UserListPage.tsx b/js/src/admin/components/UserListPage.tsx index cbc790cfb..a4cfbc7e8 100644 --- a/js/src/admin/components/UserListPage.tsx +++ b/js/src/admin/components/UserListPage.tsx @@ -1,3 +1,5 @@ +import app from '../../admin/app'; + import EditUserModal from '../../common/components/EditUserModal'; import LoadingIndicator from '../../common/components/LoadingIndicator'; import Button from '../../common/components/Button'; diff --git a/js/src/admin/resolvers/ExtensionPageResolver.ts b/js/src/admin/resolvers/ExtensionPageResolver.ts index a8dc93c33..6ab785c73 100644 --- a/js/src/admin/resolvers/ExtensionPageResolver.ts +++ b/js/src/admin/resolvers/ExtensionPageResolver.ts @@ -1,3 +1,4 @@ +import app from '../../admin/app'; import DefaultResolver from '../../common/resolvers/DefaultResolver'; /** diff --git a/js/src/admin/utils/getCategorizedExtensions.js b/js/src/admin/utils/getCategorizedExtensions.js index e43c7229a..afc9d4a73 100644 --- a/js/src/admin/utils/getCategorizedExtensions.js +++ b/js/src/admin/utils/getCategorizedExtensions.js @@ -1,3 +1,5 @@ +import app from '../../admin/app'; + export default function getCategorizedExtensions() { let extensions = {}; diff --git a/js/src/admin/utils/isExtensionEnabled.js b/js/src/admin/utils/isExtensionEnabled.js index 953c08fcb..05dc7ff4a 100644 --- a/js/src/admin/utils/isExtensionEnabled.js +++ b/js/src/admin/utils/isExtensionEnabled.js @@ -1,3 +1,5 @@ +import app from '../../admin/app'; + export default function isExtensionEnabled(name) { const enabled = JSON.parse(app.data.settings.extensions_enabled); diff --git a/js/src/admin/utils/saveSettings.js b/js/src/admin/utils/saveSettings.js index 1330b4b69..a69ccee0e 100644 --- a/js/src/admin/utils/saveSettings.js +++ b/js/src/admin/utils/saveSettings.js @@ -1,3 +1,5 @@ +import app from '../../admin/app'; + export default function saveSettings(settings) { const oldSettings = JSON.parse(JSON.stringify(app.data.settings)); diff --git a/js/src/common/Application.js b/js/src/common/Application.js index 94e631cf2..e86cb0ced 100644 --- a/js/src/common/Application.js +++ b/js/src/common/Application.js @@ -1,3 +1,5 @@ +import app from '../common/app'; + import ItemList from './utils/ItemList'; import Button from './components/Button'; import ModalManager from './components/ModalManager'; diff --git a/js/src/common/Component.ts b/js/src/common/Component.ts index 1304d02c0..4b5a59947 100644 --- a/js/src/common/Component.ts +++ b/js/src/common/Component.ts @@ -1,4 +1,4 @@ -import * as Mithril from 'mithril'; +import type Mithril from 'mithril'; export interface ComponentAttrs extends Mithril.Attributes {} diff --git a/js/src/common/Fragment.ts b/js/src/common/Fragment.ts index bc1c9d108..b196be17e 100644 --- a/js/src/common/Fragment.ts +++ b/js/src/common/Fragment.ts @@ -1,4 +1,4 @@ -import * as Mithril from 'mithril'; +import type Mithril from 'mithril'; /** * The `Fragment` class represents a chunk of DOM that is rendered once with Mithril and then takes diff --git a/js/src/common/Model.js b/js/src/common/Model.js index ecda6aebb..270ef5a17 100644 --- a/js/src/common/Model.js +++ b/js/src/common/Model.js @@ -1,3 +1,5 @@ +import app from '../common/app'; + /** * The `Model` class represents a local data resource. It provides methods to * persist changes via the API. diff --git a/js/src/common/Session.js b/js/src/common/Session.js index 16fd8a54e..ca89f310a 100644 --- a/js/src/common/Session.js +++ b/js/src/common/Session.js @@ -1,3 +1,5 @@ +import app from '../common/app'; + /** * The `Session` class defines the current user session. It stores a reference * to the current authenticated user, and provides methods to log in/out. diff --git a/js/src/common/Store.js b/js/src/common/Store.js index 0805b8202..ebbb9d9b2 100644 --- a/js/src/common/Store.js +++ b/js/src/common/Store.js @@ -1,3 +1,4 @@ +import app from '../common/app'; /** * The `Store` class defines a local data store, and provides methods to * retrieve data from the API. diff --git a/js/src/common/app.ts b/js/src/common/app.ts new file mode 100644 index 000000000..b487c0da2 --- /dev/null +++ b/js/src/common/app.ts @@ -0,0 +1,31 @@ +import type Application from './Application'; + +// Used to fix typings +const w = window as any; + +/** + * Proxy app. Common JS is run first, at which point `window.app` is not + * set as this is done by the namespaced JS. + * + * When the corrent value is set, this code would retain the reference to + * the original invalid value. + * + * By using a proxy, we can ensure that our `window.app` value is always + * up-to-date with the latest reference. + */ +const appProxy = new Proxy( + {}, + { + get(_, properties) { + return Reflect.get(w.app, properties, w.app); + }, + set(_, properties, value) { + return Reflect.set(w.app, properties, value, w.app); + }, + } +); + +/** + * The instance of Application within the common namespace. + */ +export default appProxy as Application; diff --git a/js/src/common/components/Alert.tsx b/js/src/common/components/Alert.tsx index bdebc89d1..7e344517d 100644 --- a/js/src/common/components/Alert.tsx +++ b/js/src/common/components/Alert.tsx @@ -2,7 +2,7 @@ import Component, { ComponentAttrs } from '../Component'; import Button from './Button'; import listItems from '../helpers/listItems'; import extract from '../utils/extract'; -import Mithril from 'mithril'; +import type Mithril from 'mithril'; export interface AlertAttrs extends ComponentAttrs { /** The type of alert this is. Will be used to give the alert a class name of `Alert--{type}`. */ diff --git a/js/src/common/components/Dropdown.js b/js/src/common/components/Dropdown.js index b05784415..3a38cfcf0 100644 --- a/js/src/common/components/Dropdown.js +++ b/js/src/common/components/Dropdown.js @@ -1,3 +1,4 @@ +import app from '../../common/app'; import Component from '../Component'; import icon from '../helpers/icon'; import listItems from '../helpers/listItems'; diff --git a/js/src/common/components/EditUserModal.js b/js/src/common/components/EditUserModal.js index 570e16f3d..70b3ca9c5 100644 --- a/js/src/common/components/EditUserModal.js +++ b/js/src/common/components/EditUserModal.js @@ -1,3 +1,4 @@ +import app from '../../common/app'; import Modal from './Modal'; import Button from './Button'; import GroupBadge from './GroupBadge'; diff --git a/js/src/common/components/LoadingIndicator.tsx b/js/src/common/components/LoadingIndicator.tsx index f99575747..66330b6bb 100644 --- a/js/src/common/components/LoadingIndicator.tsx +++ b/js/src/common/components/LoadingIndicator.tsx @@ -1,3 +1,4 @@ +import app from '../../common/app'; import Component, { ComponentAttrs } from '../Component'; import classList from '../utils/classList'; diff --git a/js/src/common/components/Navigation.js b/js/src/common/components/Navigation.js index ac8cd0454..c22648726 100644 --- a/js/src/common/components/Navigation.js +++ b/js/src/common/components/Navigation.js @@ -1,3 +1,4 @@ +import app from '../../common/app'; import Component from '../Component'; import Button from './Button'; import LinkButton from './LinkButton'; diff --git a/js/src/common/components/Page.js b/js/src/common/components/Page.js index 14b2836e6..531ffa317 100644 --- a/js/src/common/components/Page.js +++ b/js/src/common/components/Page.js @@ -1,3 +1,4 @@ +import app from '../../common/app'; import Component from '../Component'; import PageState from '../states/PageState'; diff --git a/js/src/common/components/TextEditor.js b/js/src/common/components/TextEditor.js index 2b457725e..a1d30f354 100644 --- a/js/src/common/components/TextEditor.js +++ b/js/src/common/components/TextEditor.js @@ -1,3 +1,5 @@ +import app from '../../common/app'; + import Component from '../Component'; import ItemList from '../utils/ItemList'; import listItems from '../helpers/listItems'; diff --git a/js/src/common/helpers/avatar.tsx b/js/src/common/helpers/avatar.tsx index 4262abc75..12fb3faac 100644 --- a/js/src/common/helpers/avatar.tsx +++ b/js/src/common/helpers/avatar.tsx @@ -1,4 +1,4 @@ -import * as Mithril from 'mithril'; +import type Mithril from 'mithril'; import User from '../models/User'; /** diff --git a/js/src/common/helpers/fullTime.tsx b/js/src/common/helpers/fullTime.tsx index 00bae7a9c..efde8faf4 100644 --- a/js/src/common/helpers/fullTime.tsx +++ b/js/src/common/helpers/fullTime.tsx @@ -1,5 +1,5 @@ import dayjs from 'dayjs'; -import * as Mithril from 'mithril'; +import type Mithril from 'mithril'; /** * The `fullTime` helper displays a formatted time string wrapped in a