diff --git a/package.json b/package.json index fb59177..37b4a80 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,10 @@ "push": "clasp push", "setup:https": "mkdirp certs && mkcert -key-file ./certs/key.pem -cert-file ./certs/cert.pem localhost 127.0.0.1", "build:dev": "tsc && vite build --mode development", + "build:test": "tsc && NODE_ENV=test vite build --mode test", "build": "tsc && vite build --mode production", "deploy:dev": "yarn build:dev && yarn push", + "deploy:test": "yarn build:test && yarn push", "deploy": "yarn build && yarn push", "start": "yarn deploy:dev && yarn dev" }, diff --git a/src/client/create-diagram-dialog/components/create-diagram-dialog.tsx b/src/client/create-diagram-dialog/components/create-diagram-dialog.tsx index 166662d..8722f5e 100644 --- a/src/client/create-diagram-dialog/components/create-diagram-dialog.tsx +++ b/src/client/create-diagram-dialog/components/create-diagram-dialog.tsx @@ -10,7 +10,6 @@ const CreateDiagramDialog = () => { useEffect(() => { if (!authState?.authorized) return; - // const url = buildUrl('/app/plugins/confluence/select', state.token); const url = buildUrl( '/app/diagrams/new?pluginSource=googledocs', authState.token diff --git a/src/client/create-diagram-dialog/index.jsx b/src/client/create-diagram-dialog/index.jsx index c85839d..31b2420 100644 --- a/src/client/create-diagram-dialog/index.jsx +++ b/src/client/create-diagram-dialog/index.jsx @@ -1,7 +1,7 @@ -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import CreateDiagramDialog from './components/create-diagram-dialog'; import './styles.css'; const container = document.getElementById('index'); -const root = ReactDOM.createRoot(container); +const root = createRoot(container); root.render(); diff --git a/src/client/edit-diagram-dialog/index.jsx b/src/client/edit-diagram-dialog/index.jsx index 0102351..d1f605d 100644 --- a/src/client/edit-diagram-dialog/index.jsx +++ b/src/client/edit-diagram-dialog/index.jsx @@ -1,8 +1,7 @@ -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import EditDiagramDialog from './components/edit-diagram-dialog'; - import './styles.css'; const container = document.getElementById('index'); -const root = ReactDOM.createRoot(container); +const root = createRoot(container); root.render(); diff --git a/src/client/hooks/useAuth.ts b/src/client/hooks/useAuth.ts index 51e7711..492fa6a 100644 --- a/src/client/hooks/useAuth.ts +++ b/src/client/hooks/useAuth.ts @@ -1,5 +1,6 @@ import { useCallback, useEffect, useState } from 'react'; import { serverFunctions } from '../utils/serverFunctions'; +import { baseURL } from '../../config/urls'; type Status = 'idle' | 'loading' | 'success' | 'error'; @@ -21,6 +22,7 @@ const useAuth = () => { const getAuth = useCallback(async () => { setAuthStatus('loading'); try { + await serverFunctions.setBaseUrl(baseURL); const state = await serverFunctions.getAuthorizationState(); setAuthState(state as AuthState); setAuthStatus('success'); diff --git a/src/client/preview-diagram-dialog/index.jsx b/src/client/preview-diagram-dialog/index.jsx index 44b3dc1..9dcd08e 100644 --- a/src/client/preview-diagram-dialog/index.jsx +++ b/src/client/preview-diagram-dialog/index.jsx @@ -1,7 +1,7 @@ -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import PreviewDiagramDialog from './components/preview-diagram-dialog'; import './styles.css'; const container = document.getElementById('index'); -const root = ReactDOM.createRoot(container); +const root = createRoot(container); root.render(); diff --git a/src/client/select-diagram-dialog/components/select-diagram-dialog.tsx b/src/client/select-diagram-dialog/components/select-diagram-dialog.tsx index 799fb08..d30bfb6 100644 --- a/src/client/select-diagram-dialog/components/select-diagram-dialog.tsx +++ b/src/client/select-diagram-dialog/components/select-diagram-dialog.tsx @@ -10,7 +10,6 @@ const SelectDiagramDialog = () => { useEffect(() => { if (!authState?.authorized) return; - // const url = buildUrl('/app/plugins/confluence/select', state.token); const url = buildUrl( '/app/plugins/select?pluginSource=googledocs', authState.token diff --git a/src/client/select-diagram-dialog/index.jsx b/src/client/select-diagram-dialog/index.jsx index 0a0d4f3..caa570d 100644 --- a/src/client/select-diagram-dialog/index.jsx +++ b/src/client/select-diagram-dialog/index.jsx @@ -1,7 +1,7 @@ -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import SelectDiagramDialog from './components/select-diagram-dialog'; import './styles.css'; const container = document.getElementById('index'); -const root = ReactDOM.createRoot(container); +const root = createRoot(container); root.render(); diff --git a/src/client/sidebar/components/Sidebar.tsx b/src/client/sidebar/components/Sidebar.tsx index 69e9e13..2d20165 100644 --- a/src/client/sidebar/components/Sidebar.tsx +++ b/src/client/sidebar/components/Sidebar.tsx @@ -33,7 +33,6 @@ const Sidebar = () => { useEffect(() => { if (!authState?.authorized) return; - // const url = buildUrl('/app/plugins/confluence/select', state.token); const url = buildUrl( '/app/plugins/recent?pluginSource=googledocs', authState.token @@ -65,9 +64,11 @@ const Sidebar = () => { useEffect(() => { const handleMessage = async (e: MessageEvent) => { const action = e.data.action; - console.log('action', action); + const actionData = e.data; + if (action === 'save') { - const data = e.data.data; + const data = actionData.data; + if (!data) return; const metadata = new URLSearchParams({ projectID: data.projectID, documentID: data.documentID, @@ -83,20 +84,24 @@ const Sidebar = () => { } catch (error) { console.error('Error inserting image with metadata', error); } - } else if (action === 'edit') { - const data = e.data; - if (!data.editUrl) return; + return; + } + if (action === 'edit') { + const editUrl = actionData.editUrl; + if (!editUrl) return; try { - localStorage.setItem('editUrl', data.editUrl); + localStorage.setItem('editUrl', editUrl); await serverFunctions.openEditDiagramDialogWithUrl(); } catch (error) { console.error('Error opening edit dialog', error); } - } else if (action === 'view') { - console.log(e.data); - if (!e.data.url) return; + return; + } + if (action === 'view') { + const viewUrl = actionData.url; + if (!viewUrl) return; try { - localStorage.setItem('previewUrl', e.data.url); + localStorage.setItem('previewUrl', viewUrl); await serverFunctions.openPreviewDiagramDialog(); } catch (error) { console.error('Error opening edit dialog', error); diff --git a/src/client/utils/helpers.ts b/src/client/utils/helpers.ts index 2696144..a2025ff 100644 --- a/src/client/utils/helpers.ts +++ b/src/client/utils/helpers.ts @@ -1,19 +1,9 @@ -import { baseURL } from '../../utils/urls'; - -interface Document { - documentID: string; - major: string; - minor: string; -} +import { baseURL } from '../../config/urls'; export const buildUrl = (pathname: string, accessToken: string) => { return `${baseURL}/oauth/frame?token=${accessToken}&redirect=${pathname}`; }; -export const buildRawUrl = (document: Document, theme = 'light') => { - return `${baseURL}/raw/${document.documentID}?version=v${document.major}.${document.minor}&theme=${theme}&format=png`; -}; - export const handleDialogClose = () => { if ((window as any).google) { (window as any).google.script.host.close(); diff --git a/src/config/urls.ts b/src/config/urls.ts new file mode 100644 index 0000000..1c03ed9 --- /dev/null +++ b/src/config/urls.ts @@ -0,0 +1,3 @@ +export const devUrl = 'https://test.mermaidchart.com'; +export const prodUrl = 'https://mermaidchart.com'; +export const baseURL = (import.meta as any).env.PROD ? prodUrl : devUrl; diff --git a/src/server/index.ts b/src/server/index.ts index 8050ee9..15afe64 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -7,6 +7,7 @@ import { openPreviewDiagramDialog, openSidebar, getOAuthURL, + setBaseUrl, handleCallback, getAuthorizationState, resetOAuth, @@ -28,6 +29,7 @@ export { openPreviewDiagramDialog, openSidebar, getOAuthURL, + setBaseUrl, handleCallback, getAuthorizationState, resetOAuth, diff --git a/src/server/ui.js b/src/server/ui.js index 4dbfb4b..c293aab 100644 --- a/src/server/ui.js +++ b/src/server/ui.js @@ -1,5 +1,3 @@ -const baseURL = 'https://test.mermaidchart.com'; - export const onOpen = () => { const menu = DocumentApp.getUi() .createAddonMenu() @@ -11,6 +9,26 @@ export const onOpen = () => { menu.addToUi(); }; +export const setBaseUrl = (url) => { + try { + const scriptProperties = PropertiesService.getScriptProperties(); + scriptProperties.setProperty('baseURL', url); + } catch (err) { + Logger.log('Failed with error %s', err.message); + } +}; + +const getBaseUrl = () => { + try { + const scriptProperties = PropertiesService.getScriptProperties(); + const baseURL = scriptProperties.getProperty('baseURL'); + Logger.log('Base URL: %s', baseURL); + return baseURL; + } catch (error) { + Logger.log('Failed with error %s', error.message); + } +}; + export const openCreateDiagramDialog = () => { const html = HtmlService.createHtmlOutputFromFile('create-diagram-dialog') .append( @@ -125,6 +143,11 @@ export function handleCallback(callbackRequest) { function getOAuthService() { pkceChallengeVerifier(); const userProps = PropertiesService.getUserProperties(); + const baseURL = getBaseUrl(); + + if (!baseURL) { + throw new Error('Base URL is not defined.'); + } return OAuth2.createService('Mermaid Chart') .setAuthorizationBaseUrl(baseURL + '/oauth/authorize') @@ -349,6 +372,11 @@ export function syncImages(maxWidth = 400) { const { token } = getAuthorizationState(); const body = DocumentApp.getActiveDocument().getBody(); const images = body.getImages(); + const baseURL = getBaseUrl(); + + if (!baseURL) { + throw new Error('Base URL is not defined.'); + } images.forEach((image) => { const altDescription = image.getAltDescription(); diff --git a/src/utils/urls.js b/src/utils/urls.js deleted file mode 100644 index c1957f9..0000000 --- a/src/utils/urls.js +++ /dev/null @@ -1 +0,0 @@ -export const baseURL = 'https://test.mermaidchart.com'; diff --git a/vite.config.ts b/vite.config.ts index 3231126..c3e096b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -164,16 +164,16 @@ const buildConfig = ({ mode }: { mode: string }) => { targets, }), /** - * This builds the client react app bundles for production, and writes them to disk. + * This builds the client react app bundles for production and test, and writes them to disk. * Because multiple client entrypoints (dialogs) are built, we need to loop through * each entrypoint and build the client bundle for each. Vite doesn't have great tooling for * building multiple single-page apps in one project, so we have to do this manually with a * post-build closeBundle hook (https://rollupjs.org/guide/en/#closebundle). */ - mode === 'production' && { - name: 'build-client-production-bundles', + (mode === 'production' || mode === 'test') && { + name: `build-client-${mode}-bundles`, closeBundle: async () => { - console.log('Building client production bundles...'); + console.log(`Building client ${mode} bundles...`); // eslint-disable-next-line no-restricted-syntax for (const clientEntrypoint of clientEntrypoints) { console.log('Building client bundle for', clientEntrypoint.name);