(userOpts: ComponentDecoratorOptions
// TO-DO have a UX designed for when a catastrophic error occurs
return An error has occurred. Please try reloading the page.
;
} else {
+ const swrConfig = { ...defaultSwrConfig, ...opts.swrConfig };
const content = (
-
+
{opts.disableTranslations ? (
@@ -120,7 +122,7 @@ export function openmrsComponentDecorator(userOpts: ComponentDecoratorOptions
);
-
+
if (!opts.strictMode || !React.StrictMode) {
return content;
} else {
diff --git a/packages/framework/esm-routes/src/loaders/components.ts b/packages/framework/esm-routes/src/loaders/components.ts
index 3027946b2..e47ee810c 100644
--- a/packages/framework/esm-routes/src/loaders/components.ts
+++ b/packages/framework/esm-routes/src/loaders/components.ts
@@ -1,15 +1,18 @@
import {
attach,
+ attachWorkspaceToGroup,
type ExtensionRegistration,
registerExtension,
registerModal,
registerWorkspace,
+ registerWorkspaceGroup,
} from '@openmrs/esm-extensions';
import {
type FeatureFlagDefinition,
type ExtensionDefinition,
type ModalDefinition,
type WorkspaceDefinition,
+ type WorkspaceGroupDefinition,
} from '@openmrs/esm-globals';
import { getLoader } from './app';
import { registerFeatureFlag } from '@openmrs/esm-feature-flags';
@@ -194,9 +197,36 @@ supported, so the workspace will not be loaded.`,
canMaximize: workspace.canMaximize,
width: workspace.width,
preferredWindowSize: workspace.preferredWindowSize,
- groups: workspace.groups ?? [],
+ groups: workspace.groups,
});
}
+
+ for (const group of workspace.groups || []) {
+ attachWorkspaceToGroup(name, group);
+ }
+}
+
+/**
+ * This function registers a workspace group definition with the framework so that it can be launched.
+ *
+ * @param appName The name of the app defining this workspace
+ * @param workspace An object that describes the workspace, derived from `routes.json`
+ */
+export function tryRegisterWorkspaceGroup(appName: string, workspaceGroup: WorkspaceGroupDefinition) {
+ const name = workspaceGroup.name;
+ if (!name) {
+ console.error(
+ `A workspace group definition in ${appName} is missing a name and thus cannot be registered.
+To fix this, ensure that you define the "name" field inside the workspace definition.`,
+ workspaceGroup,
+ );
+ return;
+ }
+
+ registerWorkspaceGroup({
+ name,
+ members: workspaceGroup.members ?? [],
+ });
}
/**
diff --git a/packages/framework/esm-routes/src/loaders/pages.ts b/packages/framework/esm-routes/src/loaders/pages.ts
index 9a13cb24f..18648c884 100644
--- a/packages/framework/esm-routes/src/loaders/pages.ts
+++ b/packages/framework/esm-routes/src/loaders/pages.ts
@@ -1,6 +1,7 @@
import { type ActivityFn, pathToActiveWhen, registerApplication } from 'single-spa';
import { registerModuleWithConfigSystem } from '@openmrs/esm-config';
import {
+ type WorkspaceGroupDefinition,
type ExtensionDefinition,
type FeatureFlagDefinition,
type ModalDefinition,
@@ -12,7 +13,13 @@ import {
import { getFeatureFlag } from '@openmrs/esm-feature-flags';
import { routeRegex } from './helpers';
import { getLoader } from './app';
-import { tryRegisterExtension, tryRegisterFeatureFlag, tryRegisterModal, tryRegisterWorkspace } from './components';
+import {
+ tryRegisterExtension,
+ tryRegisterFeatureFlag,
+ tryRegisterModal,
+ tryRegisterWorkspace,
+ tryRegisterWorkspaceGroup,
+} from './components';
// this is the global holder of all pages registered in the app
const pages: Array = [];
@@ -93,6 +100,7 @@ export function registerApp(appName: string, routes: OpenmrsAppRoutes) {
const availableExtensions: Array = routes.extensions ?? [];
const availableModals: Array = routes.modals ?? [];
const availableWorkspaces: Array = routes.workspaces ?? [];
+ const availableWorkspaceGroups: Array = routes.workspaceGroups ?? [];
const availableFeatureFlags: Array = routes.featureFlags ?? [];
routes.pages?.forEach((p) => {
@@ -153,6 +161,17 @@ export function registerApp(appName: string, routes: OpenmrsAppRoutes) {
}
});
+ availableWorkspaceGroups.forEach((workspaceGroup) => {
+ if (workspaceGroup && typeof workspaceGroup === 'object' && Object.hasOwn(workspaceGroup, 'name')) {
+ tryRegisterWorkspaceGroup(appName, workspaceGroup);
+ } else {
+ console.warn(
+ `A workspace group for ${appName} could not be registered as it does not appear to have the required properties`,
+ workspaceGroup,
+ );
+ }
+ });
+
availableFeatureFlags.forEach((featureFlag) => {
if (featureFlag && typeof featureFlag === 'object' && Object.hasOwn(featureFlag, 'flagName')) {
tryRegisterFeatureFlag(appName, featureFlag);
diff --git a/packages/framework/esm-styleguide/src/workspaces/workspaces.test.ts b/packages/framework/esm-styleguide/src/workspaces/workspaces.test.ts
index 51052e473..e7d026d26 100644
--- a/packages/framework/esm-styleguide/src/workspaces/workspaces.test.ts
+++ b/packages/framework/esm-styleguide/src/workspaces/workspaces.test.ts
@@ -1,5 +1,5 @@
import { clearMockExtensionRegistry } from '@openmrs/esm-framework/mock';
-import { registerExtension, registerWorkspace } from '@openmrs/esm-extensions';
+import { registerExtension, registerWorkspace, registerWorkspaceGroup } from '@openmrs/esm-extensions';
import {
type Prompt,
cancelPrompt,
@@ -555,7 +555,7 @@ describe('workspace system', () => {
});
expect(workspaceGroupStore).toBeTruthy();
- expect(workspaceGroupStore?.getState()?.['foo']).toBe(true);
+ expect(workspaceGroupStore?.getState()['foo']).toBe(true);
});
it('should update the store state with new additionalProps if workspaces with same workspaceGroup name calls the function', () => {
@@ -564,15 +564,15 @@ describe('workspace system', () => {
});
expect(workspaceGroupStore).toBeTruthy();
- expect(workspaceGroupStore?.getState()?.['foo']).toBe(true);
+ expect(workspaceGroupStore?.getState()['foo']).toBe(true);
workspaceGroupStore = getWorkspaceGroupStore('ward-patient-store', {
bar: true,
});
expect(workspaceGroupStore).toBeTruthy();
- expect(workspaceGroupStore?.getState()?.['foo']).toBe(true);
- expect(workspaceGroupStore?.getState()?.['bar']).toBe(true);
+ expect(workspaceGroupStore?.getState()['foo']).toBe(true);
+ expect(workspaceGroupStore?.getState()['bar']).toBe(true);
});
});
@@ -590,7 +590,11 @@ describe('workspace system', () => {
load: jest.fn(),
type: 'ward-patient',
moduleName: '@openmrs/esm-ward-app',
- groups: ['ward-patient-store'],
+ });
+
+ registerWorkspaceGroup({
+ name: 'ward-patient-store',
+ members: ['ward-patient-workspace'],
});
launchWorkspaceGroup('ward-patient-store', {
@@ -620,7 +624,10 @@ describe('workspace system', () => {
load: jest.fn(),
type: 'ward-patient',
moduleName: '@openmrs/esm-ward-app',
- groups: ['ward-patient-store'],
+ });
+ registerWorkspaceGroup({
+ name: 'ward-patient-store',
+ members: ['ward-patient-workspace'],
});
launchWorkspaceGroup('ward-patient-store', {
state: {
@@ -647,7 +654,6 @@ describe('workspace system', () => {
load: jest.fn(),
type: 'ward-patient',
moduleName: '@openmrs/esm-ward-app',
- groups: [workspaceGroup],
});
registerWorkspace({
name: 'transfer-patient-workspace',
@@ -655,7 +661,10 @@ describe('workspace system', () => {
load: jest.fn(),
type: 'transfer-patient',
moduleName: '@openmrs/esm-ward-app',
- groups: [workspaceGroup],
+ });
+ registerWorkspaceGroup({
+ name: workspaceGroup,
+ members: ['ward-patient-workspace', 'transfer-patient-workspace'],
});
launchWorkspaceGroup(workspaceGroup, {
@@ -689,7 +698,6 @@ describe('workspace system', () => {
load: jest.fn(),
type: 'ward-patient',
moduleName: '@openmrs/esm-ward-app',
- groups: ['ward-patient-store'],
});
registerWorkspace({
name: 'transfer-patient-workspace',
@@ -697,7 +705,16 @@ describe('workspace system', () => {
load: jest.fn(),
type: 'transfer-patient',
moduleName: '@openmrs/esm-ward-app',
- groups: ['another-sidebar-group'],
+ });
+
+ registerWorkspaceGroup({
+ name: 'ward-patient-store',
+ members: ['ward-patient-workspace'],
+ });
+
+ registerWorkspaceGroup({
+ name: 'another-sidebar-group',
+ members: ['transfer-patient-workspace'],
});
const workspaceStore = getWorkspaceStore();
@@ -737,7 +754,6 @@ describe('workspace system', () => {
type: 'ward-patient',
moduleName: '@openmrs/esm-ward-app',
canHide: true,
- groups: ['ward-patient-store'],
});
registerWorkspace({
name: 'transfer-patient-workspace',
@@ -745,7 +761,11 @@ describe('workspace system', () => {
load: jest.fn(),
type: 'transfer-patient',
moduleName: '@openmrs/esm-ward-app',
- groups: ['ward-patient-store'],
+ });
+
+ registerWorkspaceGroup({
+ name: 'ward-patient-store',
+ members: ['ward-patient-workspace', 'transfer-patient-workspace'],
});
const workspaceStore = getWorkspaceStore();
@@ -776,7 +796,10 @@ describe('workspace system', () => {
load: jest.fn(),
type: 'ward-patient',
moduleName: '@openmrs/esm-ward-app',
- groups: ['ward-patient-store'],
+ });
+ registerWorkspaceGroup({
+ name: 'ward-patient-store',
+ members: ['ward-patient-workspace'],
});
launchWorkspaceGroup('ward-patient-store', {
state: { foo: true },
diff --git a/packages/framework/esm-styleguide/src/workspaces/workspaces.ts b/packages/framework/esm-styleguide/src/workspaces/workspaces.ts
index 3f3fd26b1..790da90c0 100644
--- a/packages/framework/esm-styleguide/src/workspaces/workspaces.ts
+++ b/packages/framework/esm-styleguide/src/workspaces/workspaces.ts
@@ -1,6 +1,11 @@
/** @module @category Workspace */
import { useMemo, type ReactNode } from 'react';
-import { getWorkspaceRegistration, type WorkspaceRegistration } from '@openmrs/esm-extensions';
+import {
+ getWorkspaceGroupRegistration,
+ getWorkspaceRegistration,
+ WorkspaceGroupRegistration,
+ type WorkspaceRegistration,
+} from '@openmrs/esm-extensions';
import { type WorkspaceWindowState } from '@openmrs/esm-globals';
import { navigate } from '@openmrs/esm-navigation';
import { getGlobalStore, createGlobalStore } from '@openmrs/esm-state';
@@ -101,6 +106,7 @@ export interface WorkspaceStoreState {
workspaceWindowState: WorkspaceWindowState;
workspaceGroup?: {
name: string;
+ members: Array;
cleanup?: Function;
};
}
@@ -203,6 +209,7 @@ interface LaunchWorkspaceGroupArg {
* });
*/
export function launchWorkspaceGroup(groupName: string, args: LaunchWorkspaceGroupArg) {
+ const workspaceGroupRegistration = getWorkspaceGroupRegistration(groupName);
const { state, onWorkspaceGroupLaunch, workspaceGroupCleanup, workspaceToLaunch } = args;
const store = getWorkspaceStore();
if (store.getState().openWorkspaces.length) {
@@ -221,6 +228,7 @@ export function launchWorkspaceGroup(groupName: string, args: LaunchWorkspaceGro
...prev,
workspaceGroup: {
name: groupName,
+ members: workspaceGroupRegistration.members,
cleanup: workspaceGroupCleanup,
},
}));
@@ -293,7 +301,7 @@ export function launchWorkspace<
const workspace = getWorkspaceRegistration(name);
const currentWorkspaceGroup = store.getState().workspaceGroup;
- if (currentWorkspaceGroup && !workspace.groups?.includes(currentWorkspaceGroup?.name)) {
+ if (currentWorkspaceGroup && !currentWorkspaceGroup.members?.includes(name)) {
closeWorkspaceGroup(currentWorkspaceGroup.name, () => {
launchWorkspace(name, additionalProps);
});
diff --git a/packages/framework/esm-translations/translations/bn.json b/packages/framework/esm-translations/translations/bn.json
new file mode 100644
index 000000000..6ae6e0fbe
--- /dev/null
+++ b/packages/framework/esm-translations/translations/bn.json
@@ -0,0 +1,60 @@
+{
+ "actions": "Actions",
+ "address": "Address",
+ "address1": "Address line 1",
+ "address2": "Address line 2",
+ "address3": "Address line 3",
+ "address4": "Address line 4",
+ "address5": "Address line 5",
+ "address6": "Address line 6",
+ "age": "Age",
+ "cancel": "Cancel",
+ "change": "Change",
+ "city": "City",
+ "cityVillage": "City",
+ "Clinic": "Clinic",
+ "close": "Close",
+ "closeAllOpenedWorkspaces": "Discard changes in {{count}} workspaces",
+ "closingAllWorkspacesPromptBody": "There are unsaved changes in the following workspaces. Do you want to discard changes in the following workspaces? {{workspaceNames}}",
+ "closingAllWorkspacesPromptTitle": "You have unsaved changes",
+ "confirm": "Confirm",
+ "contactAdministratorIfIssuePersists": "Contact your system administrator if the problem persists.",
+ "contactDetails": "Contact Details",
+ "country": "Country",
+ "countyDistrict": "District",
+ "discard": "Discard",
+ "district": "District",
+ "error": "Error",
+ "errorCopy": "Sorry, there was a problem displaying this information. You can try to reload this page, or contact the site administrator and quote the error code above.",
+ "female": "Female",
+ "hide": "Hide",
+ "loading": "Loading",
+ "male": "Male",
+ "maximize": "Maximize",
+ "minimize": "Minimize",
+ "openAnyway": "Open Anyway",
+ "other": "Other",
+ "patientIdentifierSticker": "Patient identifier sticker",
+ "patientLists": "Patient Lists",
+ "postalCode": "Postal code",
+ "print": "Print",
+ "printError": "Print error",
+ "printErrorExplainer": "An error occurred in {{errorLocation}}",
+ "printIdentifierSticker": "Print identifier sticker",
+ "printing": "Printing",
+ "relationships": "Relationships",
+ "resetOverrides": "Reset overrides",
+ "save": "Save",
+ "scriptLoadingError": "Failed to load overridden script from {{url}}. Please check that the bundled script is available at the expected URL. Click the button below to reset all import map overrides.",
+ "scriptLoadingFailed": "Error: Script failed to load",
+ "seeMoreLists": "See {{count}} more lists",
+ "sex": "Sex",
+ "showLess": "Show less",
+ "showMore": "Show more",
+ "state": "State",
+ "stateProvince": "State",
+ "unknown": "Unknown",
+ "unsavedChangesInWorkspace": "There are unsaved changes in {{workspaceName}}. Please save them before opening another workspace.",
+ "unsavedChangesTitleText": "Unsaved changes",
+ "workspaceHeader": "Workspace header"
+}
diff --git a/packages/framework/esm-translations/translations/lg.json b/packages/framework/esm-translations/translations/lg.json
new file mode 100644
index 000000000..6ae6e0fbe
--- /dev/null
+++ b/packages/framework/esm-translations/translations/lg.json
@@ -0,0 +1,60 @@
+{
+ "actions": "Actions",
+ "address": "Address",
+ "address1": "Address line 1",
+ "address2": "Address line 2",
+ "address3": "Address line 3",
+ "address4": "Address line 4",
+ "address5": "Address line 5",
+ "address6": "Address line 6",
+ "age": "Age",
+ "cancel": "Cancel",
+ "change": "Change",
+ "city": "City",
+ "cityVillage": "City",
+ "Clinic": "Clinic",
+ "close": "Close",
+ "closeAllOpenedWorkspaces": "Discard changes in {{count}} workspaces",
+ "closingAllWorkspacesPromptBody": "There are unsaved changes in the following workspaces. Do you want to discard changes in the following workspaces? {{workspaceNames}}",
+ "closingAllWorkspacesPromptTitle": "You have unsaved changes",
+ "confirm": "Confirm",
+ "contactAdministratorIfIssuePersists": "Contact your system administrator if the problem persists.",
+ "contactDetails": "Contact Details",
+ "country": "Country",
+ "countyDistrict": "District",
+ "discard": "Discard",
+ "district": "District",
+ "error": "Error",
+ "errorCopy": "Sorry, there was a problem displaying this information. You can try to reload this page, or contact the site administrator and quote the error code above.",
+ "female": "Female",
+ "hide": "Hide",
+ "loading": "Loading",
+ "male": "Male",
+ "maximize": "Maximize",
+ "minimize": "Minimize",
+ "openAnyway": "Open Anyway",
+ "other": "Other",
+ "patientIdentifierSticker": "Patient identifier sticker",
+ "patientLists": "Patient Lists",
+ "postalCode": "Postal code",
+ "print": "Print",
+ "printError": "Print error",
+ "printErrorExplainer": "An error occurred in {{errorLocation}}",
+ "printIdentifierSticker": "Print identifier sticker",
+ "printing": "Printing",
+ "relationships": "Relationships",
+ "resetOverrides": "Reset overrides",
+ "save": "Save",
+ "scriptLoadingError": "Failed to load overridden script from {{url}}. Please check that the bundled script is available at the expected URL. Click the button below to reset all import map overrides.",
+ "scriptLoadingFailed": "Error: Script failed to load",
+ "seeMoreLists": "See {{count}} more lists",
+ "sex": "Sex",
+ "showLess": "Show less",
+ "showMore": "Show more",
+ "state": "State",
+ "stateProvince": "State",
+ "unknown": "Unknown",
+ "unsavedChangesInWorkspace": "There are unsaved changes in {{workspaceName}}. Please save them before opening another workspace.",
+ "unsavedChangesTitleText": "Unsaved changes",
+ "workspaceHeader": "Workspace header"
+}
diff --git a/packages/framework/esm-translations/translations/pt_BR.json b/packages/framework/esm-translations/translations/pt_BR.json
index 6ae6e0fbe..a0a649911 100644
--- a/packages/framework/esm-translations/translations/pt_BR.json
+++ b/packages/framework/esm-translations/translations/pt_BR.json
@@ -1,60 +1,60 @@
{
- "actions": "Actions",
- "address": "Address",
- "address1": "Address line 1",
- "address2": "Address line 2",
- "address3": "Address line 3",
- "address4": "Address line 4",
- "address5": "Address line 5",
- "address6": "Address line 6",
- "age": "Age",
- "cancel": "Cancel",
- "change": "Change",
- "city": "City",
- "cityVillage": "City",
- "Clinic": "Clinic",
- "close": "Close",
- "closeAllOpenedWorkspaces": "Discard changes in {{count}} workspaces",
- "closingAllWorkspacesPromptBody": "There are unsaved changes in the following workspaces. Do you want to discard changes in the following workspaces? {{workspaceNames}}",
- "closingAllWorkspacesPromptTitle": "You have unsaved changes",
- "confirm": "Confirm",
- "contactAdministratorIfIssuePersists": "Contact your system administrator if the problem persists.",
- "contactDetails": "Contact Details",
- "country": "Country",
- "countyDistrict": "District",
- "discard": "Discard",
- "district": "District",
- "error": "Error",
- "errorCopy": "Sorry, there was a problem displaying this information. You can try to reload this page, or contact the site administrator and quote the error code above.",
- "female": "Female",
- "hide": "Hide",
- "loading": "Loading",
- "male": "Male",
- "maximize": "Maximize",
- "minimize": "Minimize",
- "openAnyway": "Open Anyway",
- "other": "Other",
- "patientIdentifierSticker": "Patient identifier sticker",
- "patientLists": "Patient Lists",
- "postalCode": "Postal code",
- "print": "Print",
- "printError": "Print error",
- "printErrorExplainer": "An error occurred in {{errorLocation}}",
- "printIdentifierSticker": "Print identifier sticker",
- "printing": "Printing",
- "relationships": "Relationships",
- "resetOverrides": "Reset overrides",
- "save": "Save",
- "scriptLoadingError": "Failed to load overridden script from {{url}}. Please check that the bundled script is available at the expected URL. Click the button below to reset all import map overrides.",
- "scriptLoadingFailed": "Error: Script failed to load",
- "seeMoreLists": "See {{count}} more lists",
- "sex": "Sex",
- "showLess": "Show less",
- "showMore": "Show more",
- "state": "State",
- "stateProvince": "State",
- "unknown": "Unknown",
- "unsavedChangesInWorkspace": "There are unsaved changes in {{workspaceName}}. Please save them before opening another workspace.",
- "unsavedChangesTitleText": "Unsaved changes",
- "workspaceHeader": "Workspace header"
+ "actions": "Ações",
+ "address": "Endereço",
+ "address1": "Linha de Endereço 1",
+ "address2": "Linha de Endereço 2",
+ "address3": "Linha de Endereço 3",
+ "address4": "Linha de endereço 4",
+ "address5": "Linha de Endereço 5",
+ "address6": "Linha de Endereço 6",
+ "age": "Idade",
+ "cancel": "Cancelar",
+ "change": "Alterar",
+ "city": "Cidade",
+ "cityVillage": "Cidade",
+ "Clinic": "Clínica",
+ "close": "Fechar",
+ "closeAllOpenedWorkspaces": "Descartar alterações em {{count}} espaços de trabalho ",
+ "closingAllWorkspacesPromptBody": "Há alterações não salvas nos seguintes espaços de trabalho. Deseja descartar as alterações nos seguintes espaços de trabalho? {{workspaceNames}}",
+ "closingAllWorkspacesPromptTitle": "Você tem alterações não salvas",
+ "confirm": "Confirmar",
+ "contactAdministratorIfIssuePersists": "Entre em contato com o administrador do sistema se o problema persistir.",
+ "contactDetails": "Detalhes de contato",
+ "country": "País",
+ "countyDistrict": "Distrito",
+ "discard": "Descarte",
+ "district": "Distrito",
+ "error": "Erro",
+ "errorCopy": "Desculpe, houve um problema ao exibir essas informações. Você pode tentar recarregar esta página ou entrar em contato com o administrador do site e informar o código de erro acima.",
+ "female": "Feminino",
+ "hide": "Esconder",
+ "loading": "Carregando",
+ "male": "Masculino",
+ "maximize": "Maximizar",
+ "minimize": "Minimizar",
+ "openAnyway": "Abrir de qualquer forma",
+ "other": "Outros",
+ "patientIdentifierSticker": "Adesivo de identificação do paciente",
+ "patientLists": "Listas de pacientes",
+ "postalCode": "Código postal",
+ "print": "Imprimir",
+ "printError": "Erro de impressão",
+ "printErrorExplainer": "Ocorreu um erro em {{errorLocation}}",
+ "printIdentifierSticker": "Imprimir adesivo identificador",
+ "printing": "Impressão",
+ "relationships": "Relacionamentos",
+ "resetOverrides": "Redefinir substituições",
+ "save": "Salvar",
+ "scriptLoadingError": "Falha ao carregar o script substituído de {{url}}. Verifique se o script empacotado está disponível no URL esperado. Clique no botão abaixo para redefinir todas as substituições do mapa de importação.",
+ "scriptLoadingFailed": "Erro: Falha ao carregar o script",
+ "seeMoreLists": "Veja mais {{count}} listas",
+ "sex": "Sexo",
+ "showLess": "Mostrar menos",
+ "showMore": "Mostrar mais",
+ "state": "Estado",
+ "stateProvince": "Estado",
+ "unknown": "Desconhecido",
+ "unsavedChangesInWorkspace": "Há alterações não salvas em {{workspaceName}}. Salve-as antes de abrir outro espaço de trabalho.",
+ "unsavedChangesTitleText": "Alterações não salvas",
+ "workspaceHeader": "Cabeçalho do espaço de trabalho"
}
diff --git a/packages/framework/esm-translations/translations/ru_RU.json b/packages/framework/esm-translations/translations/ru_RU.json
new file mode 100644
index 000000000..6ae6e0fbe
--- /dev/null
+++ b/packages/framework/esm-translations/translations/ru_RU.json
@@ -0,0 +1,60 @@
+{
+ "actions": "Actions",
+ "address": "Address",
+ "address1": "Address line 1",
+ "address2": "Address line 2",
+ "address3": "Address line 3",
+ "address4": "Address line 4",
+ "address5": "Address line 5",
+ "address6": "Address line 6",
+ "age": "Age",
+ "cancel": "Cancel",
+ "change": "Change",
+ "city": "City",
+ "cityVillage": "City",
+ "Clinic": "Clinic",
+ "close": "Close",
+ "closeAllOpenedWorkspaces": "Discard changes in {{count}} workspaces",
+ "closingAllWorkspacesPromptBody": "There are unsaved changes in the following workspaces. Do you want to discard changes in the following workspaces? {{workspaceNames}}",
+ "closingAllWorkspacesPromptTitle": "You have unsaved changes",
+ "confirm": "Confirm",
+ "contactAdministratorIfIssuePersists": "Contact your system administrator if the problem persists.",
+ "contactDetails": "Contact Details",
+ "country": "Country",
+ "countyDistrict": "District",
+ "discard": "Discard",
+ "district": "District",
+ "error": "Error",
+ "errorCopy": "Sorry, there was a problem displaying this information. You can try to reload this page, or contact the site administrator and quote the error code above.",
+ "female": "Female",
+ "hide": "Hide",
+ "loading": "Loading",
+ "male": "Male",
+ "maximize": "Maximize",
+ "minimize": "Minimize",
+ "openAnyway": "Open Anyway",
+ "other": "Other",
+ "patientIdentifierSticker": "Patient identifier sticker",
+ "patientLists": "Patient Lists",
+ "postalCode": "Postal code",
+ "print": "Print",
+ "printError": "Print error",
+ "printErrorExplainer": "An error occurred in {{errorLocation}}",
+ "printIdentifierSticker": "Print identifier sticker",
+ "printing": "Printing",
+ "relationships": "Relationships",
+ "resetOverrides": "Reset overrides",
+ "save": "Save",
+ "scriptLoadingError": "Failed to load overridden script from {{url}}. Please check that the bundled script is available at the expected URL. Click the button below to reset all import map overrides.",
+ "scriptLoadingFailed": "Error: Script failed to load",
+ "seeMoreLists": "See {{count}} more lists",
+ "sex": "Sex",
+ "showLess": "Show less",
+ "showMore": "Show more",
+ "state": "State",
+ "stateProvince": "State",
+ "unknown": "Unknown",
+ "unsavedChangesInWorkspace": "There are unsaved changes in {{workspaceName}}. Please save them before opening another workspace.",
+ "unsavedChangesTitleText": "Unsaved changes",
+ "workspaceHeader": "Workspace header"
+}
diff --git a/packages/framework/esm-translations/translations/uz.json b/packages/framework/esm-translations/translations/uz.json
new file mode 100644
index 000000000..6ae6e0fbe
--- /dev/null
+++ b/packages/framework/esm-translations/translations/uz.json
@@ -0,0 +1,60 @@
+{
+ "actions": "Actions",
+ "address": "Address",
+ "address1": "Address line 1",
+ "address2": "Address line 2",
+ "address3": "Address line 3",
+ "address4": "Address line 4",
+ "address5": "Address line 5",
+ "address6": "Address line 6",
+ "age": "Age",
+ "cancel": "Cancel",
+ "change": "Change",
+ "city": "City",
+ "cityVillage": "City",
+ "Clinic": "Clinic",
+ "close": "Close",
+ "closeAllOpenedWorkspaces": "Discard changes in {{count}} workspaces",
+ "closingAllWorkspacesPromptBody": "There are unsaved changes in the following workspaces. Do you want to discard changes in the following workspaces? {{workspaceNames}}",
+ "closingAllWorkspacesPromptTitle": "You have unsaved changes",
+ "confirm": "Confirm",
+ "contactAdministratorIfIssuePersists": "Contact your system administrator if the problem persists.",
+ "contactDetails": "Contact Details",
+ "country": "Country",
+ "countyDistrict": "District",
+ "discard": "Discard",
+ "district": "District",
+ "error": "Error",
+ "errorCopy": "Sorry, there was a problem displaying this information. You can try to reload this page, or contact the site administrator and quote the error code above.",
+ "female": "Female",
+ "hide": "Hide",
+ "loading": "Loading",
+ "male": "Male",
+ "maximize": "Maximize",
+ "minimize": "Minimize",
+ "openAnyway": "Open Anyway",
+ "other": "Other",
+ "patientIdentifierSticker": "Patient identifier sticker",
+ "patientLists": "Patient Lists",
+ "postalCode": "Postal code",
+ "print": "Print",
+ "printError": "Print error",
+ "printErrorExplainer": "An error occurred in {{errorLocation}}",
+ "printIdentifierSticker": "Print identifier sticker",
+ "printing": "Printing",
+ "relationships": "Relationships",
+ "resetOverrides": "Reset overrides",
+ "save": "Save",
+ "scriptLoadingError": "Failed to load overridden script from {{url}}. Please check that the bundled script is available at the expected URL. Click the button below to reset all import map overrides.",
+ "scriptLoadingFailed": "Error: Script failed to load",
+ "seeMoreLists": "See {{count}} more lists",
+ "sex": "Sex",
+ "showLess": "Show less",
+ "showMore": "Show more",
+ "state": "State",
+ "stateProvince": "State",
+ "unknown": "Unknown",
+ "unsavedChangesInWorkspace": "There are unsaved changes in {{workspaceName}}. Please save them before opening another workspace.",
+ "unsavedChangesTitleText": "Unsaved changes",
+ "workspaceHeader": "Workspace header"
+}
diff --git a/packages/framework/esm-translations/translations/zh_CN.json b/packages/framework/esm-translations/translations/zh_CN.json
index 9613c43a4..e9a09c111 100644
--- a/packages/framework/esm-translations/translations/zh_CN.json
+++ b/packages/framework/esm-translations/translations/zh_CN.json
@@ -3,27 +3,27 @@
"address": "地址",
"address1": "地址行1",
"address2": "地址行2",
- "address3": "Address line 3",
- "address4": "Address line 4",
- "address5": "Address line 5",
- "address6": "Address line 6",
- "age": "Age",
+ "address3": "地址行3",
+ "address4": "地址行4",
+ "address5": "地址行5",
+ "address6": "地址行6",
+ "age": "年龄",
"cancel": "取消",
"change": "更改",
"city": "城市",
"cityVillage": "城市",
- "Clinic": "Clinic",
+ "Clinic": "临床",
"close": "关闭",
"closeAllOpenedWorkspaces": "放弃 {{count}} 个工作区中的更改",
"closingAllWorkspacesPromptBody": "以下工作区中有未保存的更改。您是否要放弃这些工作区中的更改? {{workspaceNames}}",
"closingAllWorkspacesPromptTitle": "您有未保存的更改",
"confirm": "确认",
- "contactAdministratorIfIssuePersists": "Contact your system administrator if the problem persists.",
+ "contactAdministratorIfIssuePersists": "如果问题仍然存在,请与系统管理员联系。",
"contactDetails": "联系方式",
"country": "国家",
"countyDistrict": "区县",
"discard": "放弃",
- "district": "District",
+ "district": "区县",
"error": "错误",
"errorCopy": "抱歉,显示此信息时出现问题。您可以尝试重新加载此页面,或联系网站管理员并引用上面的错误代码。",
"female": "女性",
@@ -34,27 +34,27 @@
"minimize": "最小化",
"openAnyway": "仍然打开",
"other": "其他",
- "patientIdentifierSticker": "Patient identifier sticker",
+ "patientIdentifierSticker": "患者标识符标签",
"patientLists": "患者列表",
"postalCode": "邮政编码",
- "print": "Print",
- "printError": "Print error",
- "printErrorExplainer": "An error occurred in {{errorLocation}}",
- "printIdentifierSticker": "Print identifier sticker",
- "printing": "Printing",
+ "print": "打印",
+ "printError": "打印错误",
+ "printErrorExplainer": "{{errorLocation}}处发生一个错误",
+ "printIdentifierSticker": "打印标识标签",
+ "printing": "打印中",
"relationships": "关系",
"resetOverrides": "重置覆盖",
- "save": "Save",
+ "save": "保存",
"scriptLoadingError": "无法从{{url}}加载覆盖脚本。请检查捆绑脚本是否可在预期的URL上可用。点击下面的按钮重置所有导入的映射覆盖。",
"scriptLoadingFailed": "错误:脚本加载失败",
"seeMoreLists": "查看{{count}}个更多列表",
- "sex": "Sex",
- "showLess": "Show less",
- "showMore": "Show more",
+ "sex": "性别",
+ "showLess": "显示较少",
+ "showMore": "显示更多",
"state": "省份",
"stateProvince": "省份",
"unknown": "未知",
"unsavedChangesInWorkspace": "{{workspaceName}} 中有未保存的更改。请在打开另一个工作区之前保存它们。",
- "unsavedChangesTitleText": "Unsaved changes",
- "workspaceHeader": "Workspace header"
+ "unsavedChangesTitleText": "未保存的更改",
+ "workspaceHeader": "工作区标题"
}
diff --git a/packages/framework/esm-utils/src/age-helpers.test.ts b/packages/framework/esm-utils/src/age-helpers.test.ts
index 3d1ad83f9..135c901c4 100644
--- a/packages/framework/esm-utils/src/age-helpers.test.ts
+++ b/packages/framework/esm-utils/src/age-helpers.test.ts
@@ -9,6 +9,7 @@ describe('Age Helper', () => {
// https://webarchive.nationalarchives.gov.uk/ukgwa/20160921162509mp_/http://systems.digital.nhs.uk/data/cui/uig/patben.pdf
// (Table 8)
const now = dayjs('2024-07-30');
+ const test0 = now;
const test1 = now.subtract(1, 'hour').subtract(30, 'minutes');
const test2 = now.subtract(1, 'day').subtract(2, 'hours').subtract(5, 'minutes');
const test3 = now.subtract(3, 'days').subtract(17, 'hours').subtract(30, 'minutes');
@@ -22,6 +23,7 @@ describe('Age Helper', () => {
const test11 = now.subtract(18, 'year').subtract(39, 'day');
it('should render durations correctly', () => {
+ expect(age(test0, now)).toBe('0 min');
expect(age(test1, now)).toBe('90 min');
expect(age(test2, now)).toBe('26 hr');
expect(age(test3, now)).toBe('3 days');
diff --git a/packages/framework/esm-utils/src/age-helpers.ts b/packages/framework/esm-utils/src/age-helpers.ts
index f0103a25b..a6ecf3535 100644
--- a/packages/framework/esm-utils/src/age-helpers.ts
+++ b/packages/framework/esm-utils/src/age-helpers.ts
@@ -2,7 +2,7 @@
import dayjs from 'dayjs';
import { getLocale } from './omrs-dates';
import { DurationFormat } from '@formatjs/intl-durationformat';
-import { type DurationInput } from '@formatjs/intl-durationformat/src/types';
+import { type DurationFormatOptions, type DurationInput } from '@formatjs/intl-durationformat/src/types';
/**
* Gets a human readable and locale supported representation of a person's age, given their birthDate,
@@ -32,9 +32,14 @@ export function age(birthDate: dayjs.ConfigType, currentDate: dayjs.ConfigType =
const locale = getLocale();
+ const options: DurationFormatOptions = { style: 'short', localeMatcher: 'lookup' };
+
if (hourDiff < 2) {
const minuteDiff = to.diff(from, 'minutes');
duration['minutes'] = minuteDiff;
+ if (minuteDiff == 0) {
+ options.minutesDisplay = 'always';
+ }
} else if (dayDiff < 2) {
duration['hours'] = hourDiff;
} else if (weekDiff < 4) {
@@ -55,5 +60,5 @@ export function age(birthDate: dayjs.ConfigType, currentDate: dayjs.ConfigType =
duration['years'] = yearDiff;
}
- return new DurationFormat(locale, { style: 'short', localeMatcher: 'lookup' }).format(duration);
+ return new DurationFormat(locale, options).format(duration);
}
diff --git a/packages/tooling/openmrs/src/cli.ts b/packages/tooling/openmrs/src/cli.ts
index f0022aefd..931cb2e36 100644
--- a/packages/tooling/openmrs/src/cli.ts
+++ b/packages/tooling/openmrs/src/cli.ts
@@ -29,51 +29,79 @@ yargs.command(
'Starts a new debugging session of the OpenMRS app shell. This uses Webpack as a debug server with proxy middleware.',
(argv) =>
argv
- .number('port')
- .default('port', 8080)
- .describe('port', 'The port where the dev server should run.')
- .number('host')
- .default('host', 'localhost')
- .describe('host', 'The host name or IP for the server to use.')
- .string('backend')
- .default('backend', 'https://dev3.openmrs.org/')
- .describe('backend', 'The backend to proxy API requests to.')
- .string('add-cookie')
- .default('add-cookie', '')
- .describe('add-cookie', 'Additional cookies to provide when proxying.')
- .boolean('support-offline')
- .describe('support-offline', 'Determines if a service worker should be installed for offline support.')
- .default('support-offline', false)
- .string('spa-path')
- .default('spa-path', '/openmrs/spa/')
- .describe('spa-path', 'The path of the application on the target server.')
- .string('api-url')
- .default('api-url', '/openmrs/')
- .describe('api-url', 'The URL of the API. Can be a path if the API is on the same target server.')
- .string('page-title')
- .default('page-title', 'OpenMRS')
- .describe('page-title', 'The title of the web app usually displayed in the browser tab.')
- .array('config-url')
- .default('config-url', [])
- .describe('config-url', 'The URL to a valid frontend configuration. Can be used multiple times.')
- .boolean('run-project')
- .default('run-project', false)
- .describe('run-project', 'Runs the project in the current directory fusing it with the specified import map.')
- .array('sources')
- .default('sources', ['.'])
- .describe('sources', 'Runs the projects from the provided source directories. Can be used multiple times.')
- .array('shared-dependencies')
- .default('shared-dependencies', [])
- .describe('shared-dependencies', 'The additional shared dependencies besides the ones from the app shell.')
- .string('importmap')
- .default('importmap', 'importmap.json')
- .describe(
- 'importmap',
- 'The import map to use. Can be a path to a valid import map to be taken literally, an URL, or a fixed JSON object.',
- )
- .string('routes')
- .default('routes', 'routes.registry.json')
- .describe('routes', 'The routes.registry.json file to use.'),
+ .option('port', {
+ default: 8080,
+ describe: 'The port where the dev server should run.',
+ type: 'number',
+ })
+ .option('host', {
+ default: 'localhost',
+ describe: 'The host name or IP for the server to use.',
+ type: 'string',
+ })
+ .option('backend', {
+ default: 'https://dev3.openmrs.org',
+ describe: 'The backend to proxy API requests to.',
+ type: 'string',
+ coerce: (arg) => (arg.endsWith('/') ? arg.slice(0, -1) : arg),
+ })
+ .option('add-cookie', {
+ default: '',
+ describe: 'Additional cookies to provide when proxying.',
+ type: 'string',
+ })
+ .option('spa-path', {
+ default: '/openmrs/spa/',
+ describe: 'The path of the application on the target server.',
+ type: 'string',
+ })
+ .option('api-url', {
+ default: '/openmrs/',
+ describe: 'The URL of the API. Can be a path if the API is on the same target server.',
+ type: 'string',
+ })
+ .option('open', {
+ default: true,
+ describe: 'Immediately opens the SPA page URL in the browser.',
+ type: 'boolean',
+ })
+ .option('config-url', {
+ default: [],
+ describe: 'The URL to a valid frontend configuration. Can be used multiple times.',
+ type: 'array',
+ })
+ .option('config-file', {
+ default: [],
+ describe: 'The path to a frontend configuration file. Can be used multiple times.',
+ type: 'array',
+ })
+ .option('sources', {
+ default: ['.'],
+ describe: 'Runs the projects from the provided source directories. Can be used multiple times.',
+ type: 'array',
+ })
+ .option('shared-dependencies', {
+ default: [],
+ describe: 'The additional shared dependencies besides the ones from the app shell.',
+ type: 'array',
+ })
+ .option('importmap', {
+ default: 'importmap.json',
+ describe:
+ 'The import map to use. Can be a path to a valid import map to be taken literally, an URL, or a fixed JSON object.',
+ type: 'string',
+ })
+ .option('routes', {
+ default: 'routes.registry.json',
+ describe:
+ 'The routes.registry.json file to use. Can be a path to a valid routes registry to be taken literally, an URL, or a fixed JSON object.',
+ type: 'string',
+ })
+ .option('support-offline', {
+ default: false,
+ describe: 'Determines if a service worker should be installed for offline support.',
+ type: 'boolean',
+ }),
async (args) =>
runCommand('runDebug', {
configUrls: args['config-url'],
@@ -81,11 +109,10 @@ yargs.command(
...proxyImportmapAndRoutes(
await mergeImportmapAndRoutes(
await getImportmapAndRoutes(args.importmap, args.routes, args.port),
- (args['run-project'] || (args.runProject as boolean)) && (await runProject(args.port, args.sources)),
+ await runProject(args.port, args.sources),
),
args.backend,
- args.host,
- args.port,
+ args.spaPath,
),
}),
);
@@ -95,51 +122,79 @@ yargs.command(
'Starts a new frontend module development session with the OpenMRS app shell.',
(argv) =>
argv
- .number('port')
- .default('port', 8080)
- .describe('port', 'The port where the dev server should run.')
- .number('host')
- .default('host', 'localhost')
- .describe('host', 'The host name or IP for the server to use.')
- .string('backend')
- .default('backend', 'https://dev3.openmrs.org/')
- .describe('backend', 'The backend to proxy API requests to.')
- .string('add-cookie')
- .default('add-cookie', '')
- .describe('add-cookie', 'Additional cookies to provide when proxying.')
- .string('spa-path')
- .default('spa-path', '/openmrs/spa/')
- .describe('spa-path', 'The path of the application on the target server.')
- .string('api-url')
- .default('api-url', '/openmrs/')
- .describe('api-url', 'The URL of the API. Can be a path if the API is on the same target server.')
- .boolean('open')
- .default('open', true)
- .describe('open', 'Immediately opens the SPA page URL in the browser.')
- .array('config-url')
- .default('config-url', [])
- .describe('config-url', 'The URL to a valid frontend configuration. Can be used multiple times.')
- .array('config-file')
- .default('config-file', [])
- .describe('config-file', 'The path to a frontend configuration file. Can be used multiple times.')
- .array('sources')
- .default('sources', ['.'])
- .describe('sources', 'Runs the projects from the provided source directories. Can be used multiple times.')
- .array('shared-dependencies')
- .default('shared-dependencies', [])
- .describe('shared-dependencies', 'The additional shared dependencies besides the ones from the app shell.')
- .string('importmap')
- .default('importmap', 'importmap.json')
- .describe(
- 'importmap',
- 'The import map to use. Can be a path to a valid import map to be taken literally, an URL, or a fixed JSON object.',
- )
- .string('routes')
- .default('routes', 'routes.registry.json')
- .describe('routes', 'The routes.registry.json file to use.')
- .boolean('support-offline')
- .default('support-offline', false)
- .describe('support-offline', 'Determines if a service worker should be installed for offline support.'),
+ .option('port', {
+ default: 8080,
+ describe: 'The port where the dev server should run.',
+ type: 'number',
+ })
+ .option('host', {
+ default: 'localhost',
+ describe: 'The host name or IP for the server to use.',
+ type: 'string',
+ })
+ .option('backend', {
+ default: 'https://dev3.openmrs.org',
+ describe: 'The backend to proxy API requests to.',
+ type: 'string',
+ coerce: (arg) => (arg.endsWith('/') ? arg.slice(0, -1) : arg),
+ })
+ .option('add-cookie', {
+ default: '',
+ describe: 'Additional cookies to provide when proxying.',
+ type: 'string',
+ })
+ .option('spa-path', {
+ default: '/openmrs/spa/',
+ describe: 'The path of the application on the target server.',
+ type: 'string',
+ })
+ .option('api-url', {
+ default: '/openmrs/',
+ describe: 'The URL of the API. Can be a path if the API is on the same target server.',
+ type: 'string',
+ })
+ .option('open', {
+ default: true,
+ describe: 'Immediately opens the SPA page URL in the browser.',
+ type: 'boolean',
+ })
+ .option('config-url', {
+ default: [],
+ describe: 'The URL to a valid frontend configuration. Can be used multiple times.',
+ type: 'array',
+ })
+ .option('config-file', {
+ default: [],
+ describe: 'The path to a frontend configuration file. Can be used multiple times.',
+ type: 'array',
+ })
+ .option('sources', {
+ default: ['.'],
+ describe: 'Runs the projects from the provided source directories. Can be used multiple times.',
+ type: 'array',
+ })
+ .option('shared-dependencies', {
+ default: [],
+ describe: 'The additional shared dependencies besides the ones from the app shell.',
+ type: 'array',
+ })
+ .option('importmap', {
+ default: 'importmap.json',
+ describe:
+ 'The import map to use. Can be a path to a valid import map to be taken literally, an URL, or a fixed JSON object.',
+ type: 'string',
+ })
+ .option('routes', {
+ default: 'routes.registry.json',
+ describe:
+ 'The routes.registry.json file to use. Can be a path to a valid routes registry to be taken literally, an URL, or a fixed JSON object.',
+ type: 'string',
+ })
+ .option('support-offline', {
+ default: false,
+ describe: 'Determines if a service worker should be installed for offline support.',
+ type: 'boolean',
+ }),
async (args) =>
runCommand('runDevelop', {
configUrls: args['config-url'],
@@ -148,13 +203,12 @@ yargs.command(
...proxyImportmapAndRoutes(
await mergeImportmapAndRoutes(
await getImportmapAndRoutes(args.importmap, args.routes, args.port),
- (args.sources[0] as string | boolean) !== false && (await runProject(args.port, args.sources)),
+ await runProject(args.port, args.sources),
args.backend,
args.spaPath,
),
args.backend,
- args.host,
- args.port,
+ args.spaPath,
),
}),
);
diff --git a/packages/tooling/openmrs/src/commands/debug.ts b/packages/tooling/openmrs/src/commands/debug.ts
index 2132f7a6b..abe30fa66 100644
--- a/packages/tooling/openmrs/src/commands/debug.ts
+++ b/packages/tooling/openmrs/src/commands/debug.ts
@@ -6,7 +6,6 @@ export interface DebugArgs {
host: string;
backend: string;
importmap: ImportmapDeclaration;
- pageTitle: string;
supportOffline?: boolean;
spaPath: string;
apiUrl: string;
diff --git a/packages/tooling/openmrs/src/utils/importmap.ts b/packages/tooling/openmrs/src/utils/importmap.ts
index 9d4305df6..f27af51a6 100644
--- a/packages/tooling/openmrs/src/utils/importmap.ts
+++ b/packages/tooling/openmrs/src/utils/importmap.ts
@@ -226,8 +226,10 @@ export async function runProject(
}
/**
- * @param decl The initial import map declaration
- * @param additionalImports New imports to add
+ * @param importAndRoutes An ImportmapAndRoutes object that holds the current import map and routes registries
+ * @param additionalImportsAndRoutes An object containing any import map entries, routes, and watched route files to add to the setup
+ * @param backend The URL for the backend
+ * @param spaPath The spaPath for this instance
* @returns The import map declaration with the new imports added in. If
* there are new imports to add, and if the original import map declaration
* had type "url", it is downloaded and resolved to one of type "inline".
@@ -366,18 +368,15 @@ export async function getRoutes(routesPath: string): Promise
}
/**
- * @param decl An import map declaration of type "inline"
- * @param backend The backend which is being proxied by the dev server
- * @param host The dev server host
- * @param port The dev server port
- * @returns The same import map declaration but with all imports from
- * `backend` changed to import from `http://${host}:${port}`.
+ * @param importmapAndRoutes An ImportmapAndRoutes object that holds the import map and routes registry
+ * @param backend The URL for the backend
+ * @param spaPath The spaPath for this instance
+ * @returns The same import map declaration but with all imports changed to the appropriate path
*/
export function proxyImportmapAndRoutes(
importmapAndRoutes: ImportmapAndRoutesWithWatches,
backend: string,
- host: string,
- port: number,
+ spaPath: string,
) {
const { importMap: importMapDecl, routes: routesDecl, watchedRoutesPaths } = importmapAndRoutes;
if (importMapDecl.type != 'inline') {
@@ -393,11 +392,14 @@ export function proxyImportmapAndRoutes(
);
}
+ const backendUrl = new URL(backend);
const importmap = JSON.parse(importMapDecl.value);
+ const spaPathRegEx = new RegExp('^' + spaPath.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d'));
+
Object.keys(importmap.imports).forEach((key) => {
- const url = importmap.imports[key];
- if (url.startsWith(backend)) {
- importmap.imports[key] = url.replace(backend, '');
+ const url = new URL(importmap.imports[key], backendUrl);
+ if (url.protocol === backendUrl.protocol && url.host === backendUrl.host) {
+ importmap.imports[key] = `./${url.pathname.replace(spaPathRegEx, '')}${url.search}${url.hash}`;
}
});
importMapDecl.value = JSON.stringify(importmap);