diff --git a/extensions/src/platform-scripture/src/main.ts b/extensions/src/platform-scripture/src/main.ts index 66014ad8e4..e905fa5e0d 100644 --- a/extensions/src/platform-scripture/src/main.ts +++ b/extensions/src/platform-scripture/src/main.ts @@ -143,6 +143,10 @@ export async function activate(context: ExecutionActivationContext) { '%webView_configureChecks_title%', ); + const showAboutDialogPromise = papi.commands.registerCommand('platform.about', async () => + papi.dialogs.showAboutDialog(), + ); + const includeProjectsCommandPromise = papi.commands.registerCommand( 'platformScripture.toggleIncludeMyParatext9Projects', async (shouldInclude) => { @@ -220,6 +224,7 @@ export async function activate(context: ExecutionActivationContext) { await checkAggregatorService.initialize(); context.registrations.add( + await showAboutDialogPromise, await scriptureExtenderPdpefPromise, await includeProjectsCommandPromise, await includeProjectsValidatorPromise, diff --git a/extensions/src/platform-scripture/src/types/platform-scripture.d.ts b/extensions/src/platform-scripture/src/types/platform-scripture.d.ts index f1bb40a54f..01027b939a 100644 --- a/extensions/src/platform-scripture/src/types/platform-scripture.d.ts +++ b/extensions/src/platform-scripture/src/types/platform-scripture.d.ts @@ -650,6 +650,8 @@ declare module 'papi-shared-types' { } export interface CommandHandlers { + 'platform.about': (projectId?: string | undefined) => Promise; + /** * Toggle the `platformScripture.includeMyParatext9Projects` setting on or off * diff --git a/lib/papi-dts/papi.d.ts b/lib/papi-dts/papi.d.ts index 48f291335a..e11e1c441f 100644 --- a/lib/papi-dts/papi.d.ts +++ b/lib/papi-dts/papi.d.ts @@ -4882,12 +4882,15 @@ declare module 'renderer/components/dialogs/dialog-definition.model' { import { DialogDefinitionBase, DialogProps } from 'renderer/components/dialogs/dialog-base.data'; import { ReactElement } from 'react'; import { ProjectMetadataFilterOptions } from 'shared/models/project-data-provider-factory.interface'; + /** The tabType for the about dialog in `about-dialog.component.tsx` */ + export const ABOUT_DIALOG_TYPE = 'platform.about'; /** The tabType for the select project dialog in `select-project.dialog.tsx` */ export const SELECT_PROJECT_DIALOG_TYPE = 'platform.selectProject'; /** The tabType for the select multiple projects dialog in `select-multiple-projects.dialog.tsx` */ export const SELECT_MULTIPLE_PROJECTS_DIALOG_TYPE = 'platform.selectMultipleProjects'; /** The tabType for the select books dialog in `select-books.dialog.tsx` */ export const SELECT_BOOKS_DIALOG_TYPE = 'platform.selectBooks'; + export type AboutDialogOptions = DialogOptions; type ProjectDialogOptionsBase = DialogOptions & ProjectMetadataFilterOptions; /** Options to provide when showing the Select Project dialog */ export type SelectProjectDialogOptions = ProjectDialogOptionsBase; @@ -4909,6 +4912,7 @@ declare module 'renderer/components/dialogs/dialog-definition.model' { * If you add a dialog here, you must also add it on {@link DIALOGS} */ export interface DialogTypes { + [ABOUT_DIALOG_TYPE]: DialogDataTypes; [SELECT_PROJECT_DIALOG_TYPE]: DialogDataTypes; [SELECT_MULTIPLE_PROJECTS_DIALOG_TYPE]: DialogDataTypes< SelectMultipleProjectsDialogOptions, @@ -4957,6 +4961,7 @@ declare module 'renderer/components/dialogs/dialog-definition.model' { } declare module 'shared/services/dialog.service-model' { import { + AboutDialogOptions, DialogTabTypes, DialogTypes, SelectProjectDialogOptions, @@ -4985,6 +4990,13 @@ declare module 'shared/services/dialog.service-model' { * @returns Returns the user's selected project id or `undefined` if the user cancels */ selectProject(options?: SelectProjectDialogOptions): Promise; + /** + * Shows the about dialog + * + * @param options Various options for configuring the dialog that shows + * @returns Returns the user's selected project id or `undefined` if the user cancels + */ + showAboutDialog(options?: AboutDialogOptions): Promise; } /** Prefix on requests that indicates that the request is related to dialog operations */ export const CATEGORY_DIALOG = 'dialog'; diff --git a/src/renderer/testing/about-panel.component.tsx b/src/renderer/components/dialogs/about-dialog.component.tsx similarity index 57% rename from src/renderer/testing/about-panel.component.tsx rename to src/renderer/components/dialogs/about-dialog.component.tsx index 93d46f174e..0b82edc4d2 100644 --- a/src/renderer/testing/about-panel.component.tsx +++ b/src/renderer/components/dialogs/about-dialog.component.tsx @@ -1,13 +1,14 @@ import icon from '@assets/icon.png'; import { useLocalizedStrings } from '@renderer/hooks/papi-hooks'; -import { SavedTabInfo, TabInfo } from '@shared/models/docking-framework.model'; import { LocalizeKey } from 'platform-bible-utils'; +import DIALOG_BASE from './dialog-base.data'; +import { ABOUT_DIALOG_TYPE, DialogDefinition } from './dialog-definition.model'; export const TAB_TYPE_ABOUT = 'about'; const STRING_KEYS: LocalizeKey[] = ['%product_name%']; -export default function AboutPanel() { +function AboutDialog() { const [{ '%product_name%': productName }] = useLocalizedStrings(STRING_KEYS); return ( @@ -22,12 +23,15 @@ export default function AboutPanel() { ); } -export function loadAboutTab(savedTabInfo: SavedTabInfo): TabInfo { - return { - ...savedTabInfo, - tabTitle: 'About', - content: , - minWidth: 230, - minHeight: 230, - }; -} +const ABOUT_DIALOG: DialogDefinition = Object.freeze({ + ...DIALOG_BASE, + tabType: ABOUT_DIALOG_TYPE, + defaultTitle: 'About', + initialSize: { + width: 500, + height: 500, + }, + Component: AboutDialog, +}); + +export default ABOUT_DIALOG; diff --git a/src/renderer/components/dialogs/dialog-definition.model.ts b/src/renderer/components/dialogs/dialog-definition.model.ts index ba71de26a0..d04778e640 100644 --- a/src/renderer/components/dialogs/dialog-definition.model.ts +++ b/src/renderer/components/dialogs/dialog-definition.model.ts @@ -3,6 +3,8 @@ import { DialogDefinitionBase, DialogProps } from '@renderer/components/dialogs/ import { ReactElement } from 'react'; import { ProjectMetadataFilterOptions } from '@shared/models/project-data-provider-factory.interface'; +/** The tabType for the about dialog in `about-dialog.component.tsx` */ +export const ABOUT_DIALOG_TYPE = 'platform.about'; /** The tabType for the select project dialog in `select-project.dialog.tsx` */ export const SELECT_PROJECT_DIALOG_TYPE = 'platform.selectProject'; /** The tabType for the select multiple projects dialog in `select-multiple-projects.dialog.tsx` */ @@ -10,6 +12,8 @@ export const SELECT_MULTIPLE_PROJECTS_DIALOG_TYPE = 'platform.selectMultipleProj /** The tabType for the select books dialog in `select-books.dialog.tsx` */ export const SELECT_BOOKS_DIALOG_TYPE = 'platform.selectBooks'; +export type AboutDialogOptions = DialogOptions; + type ProjectDialogOptionsBase = DialogOptions & ProjectMetadataFilterOptions; /** Options to provide when showing the Select Project dialog */ @@ -35,6 +39,7 @@ export type SelectBooksDialogOptions = DialogOptions & { * If you add a dialog here, you must also add it on {@link DIALOGS} */ export interface DialogTypes { + [ABOUT_DIALOG_TYPE]: DialogDataTypes; [SELECT_PROJECT_DIALOG_TYPE]: DialogDataTypes; [SELECT_MULTIPLE_PROJECTS_DIALOG_TYPE]: DialogDataTypes< SelectMultipleProjectsDialogOptions, diff --git a/src/renderer/components/dialogs/index.ts b/src/renderer/components/dialogs/index.ts index 7c396dd97d..1856037e77 100644 --- a/src/renderer/components/dialogs/index.ts +++ b/src/renderer/components/dialogs/index.ts @@ -1,5 +1,6 @@ -import SELECT_PROJECT_DIALOG from '@renderer/components/dialogs/select-project.dialog'; +import ABOUT_DIALOG from '@renderer/components/dialogs/about-dialog.component'; import SELECT_MULTIPLE_PROJECTS_DIALOG from '@renderer/components/dialogs/select-multiple-projects.dialog'; +import SELECT_PROJECT_DIALOG from '@renderer/components/dialogs/select-project.dialog'; import { DialogDefinition, DialogTabTypes } from './dialog-definition.model'; import SELECT_BOOKS_DIALOG from './select-books-dialog.component'; @@ -9,6 +10,7 @@ import SELECT_BOOKS_DIALOG from './select-books-dialog.component'; * If you add a dialog here, you must also add it on {@link DialogTypes} */ const DIALOGS: { [DialogTabType in DialogTabTypes]: DialogDefinition } = { + [ABOUT_DIALOG.tabType]: ABOUT_DIALOG, [SELECT_PROJECT_DIALOG.tabType]: SELECT_PROJECT_DIALOG, [SELECT_MULTIPLE_PROJECTS_DIALOG.tabType]: SELECT_MULTIPLE_PROJECTS_DIALOG, [SELECT_BOOKS_DIALOG.tabType]: SELECT_BOOKS_DIALOG, diff --git a/src/renderer/components/docking/platform-dock-layout-storage.util.ts b/src/renderer/components/docking/platform-dock-layout-storage.util.ts index 3d289a787a..60c927edd2 100644 --- a/src/renderer/components/docking/platform-dock-layout-storage.util.ts +++ b/src/renderer/components/docking/platform-dock-layout-storage.util.ts @@ -43,7 +43,6 @@ import { updateWebViewTab, } from '@renderer/components/web-view.component'; -import { TAB_TYPE_ABOUT, loadAboutTab } from '@renderer/testing/about-panel.component'; import { TAB_TYPE_BUTTONS, loadButtonsTab } from '@renderer/testing/test-buttons-panel.component'; import { TAB_TYPE_TEST, loadTestTab } from '@renderer/testing/test-panel.component'; import { @@ -60,7 +59,6 @@ import { ErrorTabData, TAB_TYPE_ERROR, createErrorTab, saveErrorTab } from './er let tabLoaderMap: Map; if (globalThis.isNoisyDevModeEnabled) { tabLoaderMap = new Map([ - [TAB_TYPE_ABOUT, loadAboutTab], [TAB_TYPE_BUTTONS, loadButtonsTab], [TAB_TYPE_QUICK_VERSE_HERESY, loadQuickVerseHeresyTab], [TAB_TYPE_TEST, loadTestTab], @@ -77,7 +75,6 @@ if (globalThis.isNoisyDevModeEnabled) { ]); } else { tabLoaderMap = new Map([ - [TAB_TYPE_ABOUT, loadAboutTab], [TAB_TYPE_BUTTONS, loadButtonsTab], [TAB_TYPE_WEBVIEW, loadWebViewTab], [TAB_TYPE_DOWNLOAD_UPDATE_PROJECT_DIALOG, loadDownloadUpdateProjectTab], diff --git a/src/renderer/components/platform-bible-menu.commands.tsx b/src/renderer/components/platform-bible-menu.commands.tsx index 267e50aa80..799cd85b76 100644 --- a/src/renderer/components/platform-bible-menu.commands.tsx +++ b/src/renderer/components/platform-bible-menu.commands.tsx @@ -31,9 +31,6 @@ export function handleMenuCommand(command: Command, tabId?: string) { case 'platform.visitSupportPage': VisitPage('https://support.bible'); break; - case 'platform.about': - logger.info(`TODO: display about. tabId: ${tabId}`); - break; default: (async () => { try { diff --git a/src/renderer/services/dialog.service-host.ts b/src/renderer/services/dialog.service-host.ts index 81b0cc6593..414f36794d 100644 --- a/src/renderer/services/dialog.service-host.ts +++ b/src/renderer/services/dialog.service-host.ts @@ -18,6 +18,7 @@ import SELECT_PROJECT_DIALOG from '@renderer/components/dialogs/select-project.d import { DialogTabTypes, DialogTypes } from '@renderer/components/dialogs/dialog-definition.model'; import { hookUpDialogService } from '@renderer/components/dialogs/dialog-base.data'; import localizationService from '@shared/services/localization.service'; +import ABOUT_DIALOG from '@renderer/components/dialogs/about-dialog.component'; /** A live dialog request. Includes the dialog's id and the functions to run on receiving results */ // TODO: preserve requests between refreshes - save the request id or something? @@ -233,6 +234,13 @@ async function showDialog( return dialogPromise; } +// on the dialogService - see `dialog.service-model.ts` for JSDoc +async function showAboutDialog( + options?: DialogTypes[typeof ABOUT_DIALOG.tabType]['options'], +): Promise { + return showDialog(ABOUT_DIALOG.tabType, options); +} + // on the dialogService - see `dialog.service-model.ts` for JSDoc async function selectProject( options?: DialogTypes[typeof SELECT_PROJECT_DIALOG.tabType]['options'], @@ -242,6 +250,7 @@ async function selectProject( const dialogService: DialogService = { showDialog, + showAboutDialog, selectProject, }; diff --git a/src/renderer/testing/test-layout.data.ts b/src/renderer/testing/test-layout.data.ts index 431dd0c0a4..c45aa65df9 100644 --- a/src/renderer/testing/test-layout.data.ts +++ b/src/renderer/testing/test-layout.data.ts @@ -1,6 +1,5 @@ import { SavedTabInfo } from '@shared/models/docking-framework.model'; import { LayoutBase } from 'rc-dock'; -import { TAB_TYPE_ABOUT } from '@renderer/testing/about-panel.component'; import { TAB_TYPE_BUTTONS } from '@renderer/testing/test-buttons-panel.component'; // import { TAB_TYPE_QUICK_VERSE_HERESY } from '@renderer/testing/test-quick-verse-heresy-panel.component'; import { TAB_TYPE_TEST } from '@renderer/testing/test-panel.component'; @@ -9,8 +8,6 @@ import { TAB_TYPE_TEST } from '@renderer/testing/test-panel.component'; // import { TAB_TYPE_EXTENSION_MANAGER } from '@renderer/components/extension-manager/extension-manager-tab.component'; import LOREM_IPSUM from './lorem-ipsum'; -export const FIRST_TAB_ID = 'About'; - // Using `as` here simplifies type changes. /* eslint-disable no-type-assertion/no-type-assertion */ const testLayout: LayoutBase = globalThis.isNoisyDevModeEnabled @@ -24,7 +21,6 @@ const testLayout: LayoutBase = globalThis.isNoisyDevModeEnabled children: [ { tabs: [ - { id: 'About', tabType: TAB_TYPE_ABOUT }, { id: 'Test Tab Two', tabType: TAB_TYPE_TEST }, { id: 'Test Tab One', tabType: TAB_TYPE_TEST }, { @@ -101,7 +97,7 @@ const testLayout: LayoutBase = globalThis.isNoisyDevModeEnabled size: 250, children: [ { - tabs: [{ id: 'About', tabType: TAB_TYPE_ABOUT }] as SavedTabInfo[], + tabs: [] as SavedTabInfo[], }, ], }, diff --git a/src/shared/services/dialog.service-model.ts b/src/shared/services/dialog.service-model.ts index 434b302bee..70b49b5ede 100644 --- a/src/shared/services/dialog.service-model.ts +++ b/src/shared/services/dialog.service-model.ts @@ -1,4 +1,5 @@ import { + AboutDialogOptions, DialogTabTypes, DialogTypes, SelectProjectDialogOptions, @@ -29,6 +30,13 @@ export interface DialogService { * @returns Returns the user's selected project id or `undefined` if the user cancels */ selectProject(options?: SelectProjectDialogOptions): Promise; + /** + * Shows the about dialog + * + * @param options Various options for configuring the dialog that shows + * @returns Returns the user's selected project id or `undefined` if the user cancels + */ + showAboutDialog(options?: AboutDialogOptions): Promise; } /** Prefix on requests that indicates that the request is related to dialog operations */ diff --git a/src/shared/services/dialog.service.ts b/src/shared/services/dialog.service.ts index 633bbfd6c5..f648a916e6 100644 --- a/src/shared/services/dialog.service.ts +++ b/src/shared/services/dialog.service.ts @@ -17,6 +17,13 @@ const dialogService: DialogService = { await initialize(); return networkService.request(serializeRequestType(CATEGORY_DIALOG, 'showDialog'), ...args); }, + showAboutDialog: async (...args) => { + await initialize(); + return networkService.request( + serializeRequestType(CATEGORY_DIALOG, 'showAboutDialog'), + ...args, + ); + }, selectProject: async (...args) => { await initialize(); return networkService.request(serializeRequestType(CATEGORY_DIALOG, 'selectProject'), ...args);