Skip to content

Commit

Permalink
#448 Open resource viewer to selected project (#606)
Browse files Browse the repository at this point in the history
  • Loading branch information
tombogle committed Oct 31, 2023
2 parents 1f68274 + 03d95fb commit d9f006c
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 19 deletions.
12 changes: 12 additions & 0 deletions extensions/src/resource-viewer/resource-viewer.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
declare module 'resource-viewer' {}

declare module 'papi-shared-types' {
export interface CommandHandlers {
/**
* Opens a new text Resource Viewer WebView and returns the WebView id
* @param projectId optional project ID of the resource to open. Prompts the user to
* select a resource project if not provided
* @returns WebView id for new Resource Viewer WebView or `null` if the user canceled the dialog
*/
'resourceViewer.open': (projectId: string | undefined) => Promise<string | null | undefined>;
}
}
70 changes: 60 additions & 10 deletions extensions/src/resource-viewer/resource-viewer.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,99 @@
import papi from 'papi-backend';
import type { IWebViewProvider } from 'shared/models/web-view-provider.model';
import type { SavedWebViewDefinition, WebViewDefinition } from 'shared/data/web-view.model';
import type { DialogOptions } from 'shared/models/dialog-options.model';
import type {
GetWebViewOptions,
SavedWebViewDefinition,
WebViewDefinition,
} from 'shared/data/web-view.model';
import type { ExecutionActivationContext } from 'extension-host/extension-types/extension-activation-context.model';
import resourceViewerWebView from './resource-viewer.web-view?inline';
import resourceViewerWebViewStyles from './resource-viewer.web-view.scss?inline';

const { logger } = papi;

logger.info('Resource Viewer is importing!');

const resourceWebViewType = 'resourceViewer.react';

interface ResourceViewerOptions extends GetWebViewOptions {
projectId: string | undefined;
}

/**
* Function to prompt for a project and open it in the resource viewer. Registered as a command handler.
*/
async function openResourceViewer(
projectId: string | undefined,
): Promise<string | null | undefined> {
let projectIdForWebView = projectId;
if (!projectIdForWebView) {
const options: DialogOptions = {
title: 'Select Resource',
prompt: 'Choose the resource project to view:',
};
projectIdForWebView = (await papi.dialogs.selectProject(options)) ?? undefined;
}
if (projectIdForWebView) {
const options: ResourceViewerOptions = { projectId: projectIdForWebView };
// REVIEW: If a resource viewer is already open for the selected project, we open another.
// This matches the current behavior in P9, though it might not be what we want long-term.
return papi.webViews.getWebView(resourceWebViewType, undefined, options);
}
return null;
}

/**
* Simple web view provider that provides Resource web views when papi requests them
*/
const resourceWebViewProvider: IWebViewProvider = {
async getWebView(savedWebView: SavedWebViewDefinition): Promise<WebViewDefinition | undefined> {
async getWebView(
savedWebView: SavedWebViewDefinition,
getWebViewOptions: ResourceViewerOptions,
): Promise<WebViewDefinition | undefined> {
if (savedWebView.webViewType !== resourceWebViewType)
throw new Error(
`${resourceWebViewType} provider received request to provide a ${savedWebView.webViewType} web view`,
);

// We know that the projectId (if present in the state) will be a string.
const projectId =
getWebViewOptions.projectId ||
// eslint-disable-next-line no-type-assertion/no-type-assertion
(savedWebView.state?.projectId as string) ||
null;
return {
title: projectId
? `Resource Viewer : ${
(await papi.projectLookup.getMetadataForProject(projectId)).name ?? projectId
}`
: 'Resource Viewer',
...savedWebView,
title: 'Resource Viewer',
content: resourceViewerWebView,
styles: resourceViewerWebViewStyles,
state: {
...savedWebView.state,
projectId,
},
};
},
};

export async function activate(context: ExecutionActivationContext): Promise<void> {
logger.info('Resource viewer is activating!');

const openResourceViewerPromise = papi.commands.registerCommand(
'resourceViewer.open',
openResourceViewer,
);

const resourceWebViewProviderPromise = papi.webViewProviders.register(
resourceWebViewType,
resourceWebViewProvider,
);

// Create a webview or get an existing webview if one already exists for this type
// Note: here, we are using `existingId: '?'` to indicate we do not want to create a new webview
// if one already exists. The webview that already exists could have been created by anyone
// anywhere; it just has to match `webViewType`.
papi.webViews.getWebView(resourceWebViewType, undefined, { existingId: '?' });

// Await the registration promises at the end so we don't hold everything else up
context.registrations.add(await resourceWebViewProviderPromise);
context.registrations.add(await resourceWebViewProviderPromise, await openResourceViewerPromise);

logger.info('The Resource Viewer is finished activating!');
}
24 changes: 16 additions & 8 deletions extensions/src/resource-viewer/resource-viewer.web-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { VerseRef } from '@sillsdev/scripture';
import papi from 'papi-frontend';
import { ScriptureReference } from 'papi-components';
import { JSX, useMemo } from 'react';
// eslint-disable-next-line import/no-unresolved
import { UsfmProviderDataTypes } from 'usfm-data-provider';
import UsxEditor from 'usxeditor';
import type { WebViewProps } from 'shared/data/web-view.model';
import { ProjectDataTypes } from 'papi-shared-types';

/** Characteristics of a marker style */
interface StyleInfo {
Expand All @@ -26,7 +26,7 @@ interface ElementInfo {

const {
react: {
hooks: { useData, useSetting },
hooks: { useProjectData, useSetting },
},
logger,
} = papi;
Expand Down Expand Up @@ -133,7 +133,7 @@ const defaultScrRef: ScriptureReference = {
};

/**
* Scripture text panel that displays a read only version of a usx editor that displays the current
* Scripture text panel that displays a read-only version of a usx editor that displays the current
* chapter
*/
function ScriptureTextPanelUsxEditor({ usx, onChanged }: ScriptureTextPanelUsxProps) {
Expand All @@ -153,12 +153,20 @@ function ScriptureTextPanelUsxEditor({ usx, onChanged }: ScriptureTextPanelUsxPr
);
}

globalThis.webViewComponent = function ResourceViewer(): JSX.Element {
logger.info('Preparing to display the Resource Viewer');
globalThis.webViewComponent = function ResourceViewer({
useWebViewState,
}: WebViewProps): JSX.Element {
const [projectId] = useWebViewState<string>('projectId', '');

logger.info(`Resource Viewer project ID: ${projectId}`);

const [scrRef] = useSetting('platform.verseRef', defaultScrRef);
const [usx, setUsx] = useData.ChapterUsx<UsfmProviderDataTypes, 'ChapterUsx'>(
'usfm',

const [usx, setUsx] = useProjectData.ChapterUSX<
ProjectDataTypes['ParatextStandard'],
'ChapterUSX'
>(
projectId,
useMemo(() => new VerseRef(scrRef.bookNum, scrRef.chapterNum, scrRef.verseNum), [scrRef]),
'Loading Scripture...',
);
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/components/dialogs/select-project.dialog.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.select-project-dialog {
overflow-y: auto;
}

.select-project-dialog .prompt {
margin: 8px;
}
2 changes: 1 addition & 1 deletion src/renderer/components/dialogs/select-project.dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function SelectProjectDialog({

return (
<div className="select-project-dialog">
<div>{prompt}</div>
<div className="prompt">{prompt}</div>
{isLoadingProjects ? (
<div>Loading Projects</div>
) : (
Expand Down
10 changes: 10 additions & 0 deletions src/renderer/components/platform-bible-menu.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ const standardMenuLayout: GridMenuInfo = {
command: 'platform.downloadAndInstallResources',
hasDivider: true,
},
{
name: 'Open Resource Viewer...',
command: 'resourceViewer.open',
hasDivider: true,
},
{
name: 'Open Text Collection...',
command: 'paratextTextCollection.open',
Expand Down Expand Up @@ -88,6 +93,11 @@ export const supportAndDevelopmentMenuLayout: GridMenuInfo = {
command: 'platform.downloadAndInstallResources',
hasDivider: true,
},
{
name: 'Open Resource Viewer...',
command: 'resourceViewer.open',
hasDivider: true,
},
{
name: 'Open Text Collection...',
command: 'platform.openTextCollection',
Expand Down

0 comments on commit d9f006c

Please sign in to comment.