Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove full reload of Preview (v4) #12534

Merged
merged 48 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
454ea60
Invalidate queries of Preview instead of reloading it
mlqn Mar 18, 2024
eaf6c7f
Revert v3 changes
mlqn Mar 19, 2024
f611d76
Refactor invalidate/refetch functions
mlqn Mar 19, 2024
7ab33e2
Move refetch to mutations
mlqn Mar 19, 2024
909d388
Remove store & reducers
mlqn Mar 19, 2024
26bed0f
Remove layout from storage
mlqn Mar 20, 2024
dfc6526
New hook to handle selectedLayoutSetName
mlqn Mar 20, 2024
0ad0261
Cleanup imports
mlqn Mar 20, 2024
d29edcd
Refactoring
mlqn Mar 20, 2024
97b768e
Cleanup useSelectedFormLayoutSetName hook
mlqn Mar 20, 2024
030e608
Remove warning
mlqn Mar 20, 2024
de07d8b
Revert changes of useSelectedFormLayoutSetName
mlqn Mar 21, 2024
6d9cbdd
Merge remote-tracking branch 'origin/main' into 12517-remove-full-rel…
mlqn Mar 21, 2024
0c80fd2
Fix preview when updating layout name
mlqn Mar 21, 2024
967b85f
Remove redux
mlqn Mar 21, 2024
1073033
Refactor preview path
mlqn Mar 21, 2024
a11b1c9
Fix tests
mlqn Mar 21, 2024
ba4a446
Remove applicationMetadataSagas
mlqn Mar 21, 2024
bc21c19
Fix unit tests
mlqn Mar 21, 2024
515a075
Merge branch 'main' into 12517-remove-full-reload-of-preview
mlqn Mar 21, 2024
0822303
Fix tests
mlqn Mar 24, 2024
4ee30d5
Merge branch 'main' into 12517-remove-full-reload-of-preview
mlqn Mar 24, 2024
54686e2
Fix tests
mlqn Mar 24, 2024
9cdc619
Fix warnings
mlqn Mar 24, 2024
6e00648
Move useSelectedFromLayoutName in AppContext
mlqn Mar 25, 2024
af93553
Cleanup
mlqn Mar 25, 2024
464b2f7
Add tests for AppContext
mlqn Mar 25, 2024
f07dda4
Add missing tests
mlqn Mar 25, 2024
9539671
Add missing tests for AppContext
mlqn Mar 25, 2024
e8ac2f3
Merge remote-tracking branch 'origin/main' into 12517-remove-full-rel…
mlqn Mar 25, 2024
e5bda9a
Cleanup tests
mlqn Mar 25, 2024
bb35a5b
Fix Preview for v3
mlqn Mar 25, 2024
c02a306
Fix extra reloads
mlqn Mar 26, 2024
57b40cd
Update landing page to open right layout
mlqn Mar 26, 2024
2ebafe5
Merge branch 'main' into 12517-remove-full-reload-of-preview
mlqn Mar 26, 2024
a66f1f2
Remove extra refetch
mlqn Mar 26, 2024
f2ebb27
Fix refetch/reload of preview when deleting a component
mlqn Mar 27, 2024
eaac17f
Merge branch 'main' into 12517-remove-full-reload-of-preview
mlqn Mar 27, 2024
004e314
Fix comments
mlqn Mar 27, 2024
a21e3c9
Remove removeSelectedFormLayoutSetName
mlqn Apr 1, 2024
3fda3d3
Fix unit tests
mlqn Apr 1, 2024
64a374d
Fix unit tests
mlqn Apr 1, 2024
be27ec6
Changes after cr
mlqn Apr 4, 2024
54c9e5b
Merge remote-tracking branch 'origin/main' into 12517-remove-full-rel…
mlqn Apr 4, 2024
29e0c59
Add missing changes
mlqn Apr 4, 2024
5298aaa
Merge branch 'main' into 12517-remove-full-reload-of-preview
mlqn Apr 4, 2024
d104b54
Add tests for TextResourceValueEditor
mlqn Apr 4, 2024
b79bd23
Merge remote-tracking branch 'origin/main' into 12517-remove-full-rel…
mlqn Apr 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/dashboard/hooks/useReposSearch/useRepoSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState } from 'react';
import type { GridSortModel } from '@mui/x-data-grid';
import { useSearchReposQuery } from '../queries';
import type { SearchRepositoryResponse } from 'app-shared/types/api/SearchRepositoryResponse';
import { useSearchParamsState } from '../useSearchParamsState';
import { useSearchParamsState } from '../../../packages/shared/src/hooks/useSearchParamsState';
import type { DATAGRID_PAGE_SIZE_TYPE } from '../../constants';
import { DATAGRID_PAGE_SIZE_OPTIONS, DATAGRID_DEFAULT_PAGE_SIZE } from '../../constants';

Expand Down
1 change: 0 additions & 1 deletion frontend/dashboard/hooks/useSearchParamsState/index.ts

This file was deleted.

4 changes: 2 additions & 2 deletions frontend/packages/shared/src/api/paths.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { stringify as s } from 'qs';
import { APP_DEVELOPMENT_BASENAME } from '../constants';
import { APP_DEVELOPMENT_BASENAME, PREVIEW_MOCK_PARTY_ID, PREVIEW_MOCK_INSTANCE_GUID, PREVIEW_MOCK_TASK_ID } from '../constants';

// Base path
const basePath = '/designer/api';
Expand Down Expand Up @@ -64,7 +64,7 @@ export const orgsListPath = () => `${basePath}/orgs`; // Get

// Preview
export const instanceIdForPreviewPath = (org, app) => `${basePath}/${org}/${app}/mock-instance-id`; // Get
export const previewPage = (org, app, selectedLayoutSet) => `/app-specific-preview/${org}/${app}?${s({ selectedLayoutSet })}`;
export const previewPage = (org, app, selectedLayout) => `/app-specific-preview/${org}/${app}#/instance/${PREVIEW_MOCK_PARTY_ID}/${PREVIEW_MOCK_INSTANCE_GUID}/${PREVIEW_MOCK_TASK_ID}/${selectedLayout}`;

// Preview - SignalR Hub
export const previewSignalRHubSubPath = () => `/previewHub`;
Expand Down
3 changes: 3 additions & 0 deletions frontend/packages/shared/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ export const DEFAULT_SELECTED_LAYOUT_NAME = 'default';
export const TASKID_FOR_STATELESS_APPS = 'Task_1';
export const MAX_NESTED_GROUP_LEVEL = 2;
export const PROTECTED_TASK_NAME_CUSTOM_RECEIPT = 'CustomReceipt';
export const PREVIEW_MOCK_PARTY_ID = '51001';
export const PREVIEW_MOCK_INSTANCE_GUID = 'f1e23d45-6789-1bcd-8c34-56789abcdef0';
export const PREVIEW_MOCK_TASK_ID = 'Task_1';
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ const NoSelectedPageMessage = () => {
const PreviewFrame = () => {
const { org, app } = useStudioUrlParams();
const [viewportToSimulate, setViewportToSimulate] = useState<SupportedView>('desktop');
const { selectedLayoutSet } = useAppContext();
const { t } = useTranslation();
const { previewIframeRef } = useAppContext();
const layoutName = useSelector(selectedLayoutNameSelector);
Expand All @@ -80,7 +79,7 @@ const PreviewFrame = () => {
ref={previewIframeRef}
className={cn(classes.iframe, classes[viewportToSimulate])}
title={t('ux_editor.preview')}
src={previewPage(org, app, selectedLayoutSet)}
src={previewPage(org, app, layoutName)}
/>
</div>
<PreviewLimitationsInfo />
Expand Down
4 changes: 0 additions & 4 deletions frontend/packages/ux-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"author": "Altinn",
"dependencies": {
"@mui/material": "5.15.13",
"@reduxjs/toolkit": "1.9.7",
"@studio/icons": "workspace:^",
"axios": "1.6.8",
"classnames": "2.5.1",
Expand All @@ -14,15 +13,12 @@
"react-dnd-html5-backend": "16.0.1",
"react-dom": "18.2.0",
"react-modal": "3.16.1",
"react-redux": "8.1.3",
"react-select": "5.8.0",
"redux": "4.2.1",
"reselect": "4.1.8",
"typescript": "5.4.2",
"uuid": "9.0.1"
},
"devDependencies": {
"@redux-devtools/extension": "3.3.0",
"jest": "29.7.0"
},
"license": "3-Clause BSD",
Expand Down
5 changes: 2 additions & 3 deletions frontend/packages/ux-editor/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import { App } from './App';
import { textMock } from '../../../testing/mocks/i18nMock';
import { typedLocalStorage } from 'app-shared/utils/webStorage';
import type { ServicesContextProps } from 'app-shared/contexts/ServicesContext';
import { appStateMock } from './testing/stateMocks';
import type { AppContextProps } from './AppContext';
import ruleHandlerMock from './testing/ruleHandlerMock';
import { layoutSetsMock } from './testing/layoutMock';
import { layoutSetsMock, layout1NameMock } from './testing/layoutMock';
import { createQueryClientMock } from 'app-shared/mocks/queryClientMock';

const { selectedLayoutSet } = appStateMock.formDesigner.layout;
const selectedLayoutSet = layout1NameMock;
const mockQueries: Partial<ServicesContextProps> = {
getInstanceIdForPreview: jest.fn().mockImplementation(() => Promise.resolve('test')),
getRuleModel: jest.fn().mockImplementation(() => Promise.resolve(ruleHandlerMock)),
Expand Down
34 changes: 13 additions & 21 deletions frontend/packages/ux-editor/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';
import { FormDesigner } from './containers/FormDesigner';
import { useText } from './hooks';
import { useText, useAppContext, useSelectedFormLayoutName } from './hooks';
import { StudioPageSpinner } from '@studio/components';
import { ErrorPage } from './components/ErrorPage';
import { useDatamodelMetadataQuery } from './hooks/queries/useDatamodelMetadataQuery';
import { selectedLayoutNameSelector } from './selectors/formLayoutSelectors';
import { useWidgetsQuery } from './hooks/queries/useWidgetsQuery';
import { useTextResourcesQuery } from 'app-shared/hooks/queries/useTextResourcesQuery';
import { useLayoutSetsQuery } from './hooks/queries/useLayoutSetsQuery';
import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams';
import { useAppContext } from './hooks/useAppContext';
import { FormItemContextProvider } from './containers/FormItemContext';

/**
Expand All @@ -22,27 +19,26 @@ import { FormItemContextProvider } from './containers/FormItemContext';
export function App() {
const t = useText();
const { org, app } = useStudioUrlParams();
const selectedLayout = useSelector(selectedLayoutNameSelector);
const { selectedLayoutSet, setSelectedLayoutSet, removeSelectedLayoutSet } = useAppContext();
const { selectedFormLayoutSetName, removeFormSelectedLayoutSetName } = useAppContext();
const { selectedFormLayoutName } = useSelectedFormLayoutName();
const { data: layoutSets, isSuccess: areLayoutSetsFetched } = useLayoutSetsQuery(org, app);
const { isSuccess: areWidgetsFetched, isError: widgetFetchedError } = useWidgetsQuery(org, app);
const { isSuccess: isDatamodelFetched, isError: dataModelFetchedError } =
useDatamodelMetadataQuery(org, app, selectedLayoutSet);
useDatamodelMetadataQuery(org, app, selectedFormLayoutSetName);
const { isSuccess: areTextResourcesFetched } = useTextResourcesQuery(org, app);

useEffect(() => {
if (
areLayoutSetsFetched &&
selectedLayoutSet &&
(!layoutSets || !layoutSets.sets.map((set) => set.id).includes(selectedLayoutSet))
selectedFormLayoutSetName &&
(!layoutSets || !layoutSets.sets.map((set) => set.id).includes(selectedFormLayoutSetName))
)
removeSelectedLayoutSet();
removeFormSelectedLayoutSetName();
}, [
areLayoutSetsFetched,
layoutSets,
selectedLayoutSet,
setSelectedLayoutSet,
removeSelectedLayoutSet,
selectedFormLayoutSetName,
removeFormSelectedLayoutSetName,
]);

const componentIsReady =
Expand All @@ -69,13 +65,6 @@ export function App() {
return createErrorMessage(t('general.unknown_error'));
};

useEffect(() => {
if (selectedLayoutSet === null && layoutSets) {
// Only set layout set if layout sets exists and there is no layout set selected yet
setSelectedLayoutSet(layoutSets.sets[0].id);
}
}, [setSelectedLayoutSet, selectedLayoutSet, layoutSets, app]);

if (componentHasError) {
const mappedError = mapErrorToDisplayError();
return <ErrorPage title={mappedError.title} message={mappedError.message} />;
Expand All @@ -84,7 +73,10 @@ export function App() {
if (componentIsReady) {
return (
<FormItemContextProvider>
<FormDesigner selectedLayout={selectedLayout} selectedLayoutSet={selectedLayoutSet} />
<FormDesigner
selectedLayout={selectedFormLayoutName}
selectedLayoutSet={selectedFormLayoutSetName}
/>
</FormItemContextProvider>
);
}
Expand Down
11 changes: 0 additions & 11 deletions frontend/packages/ux-editor/src/AppContext.ts

This file was deleted.

97 changes: 97 additions & 0 deletions frontend/packages/ux-editor/src/AppContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type { MutableRefObject } from 'react';
import React, { useMemo, useRef, createContext, useCallback } from 'react';
import type { QueryClient, QueryKey } from '@tanstack/react-query';
import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams';
import { useSelectedFormLayoutName, useSelectedFormLayoutSetName } from './hooks';
Fixed Show fixed Hide fixed
import { previewPage } from 'app-shared/api/paths';

export interface WindowWithQueryClient extends Window {
queryClient?: QueryClient;
}

export interface AppContextProps {
previewIframeRef: MutableRefObject<HTMLIFrameElement>;
selectedFormLayoutSetName: string;
setSelectedFormLayoutSetName: (layoutSet: string) => void;
removeFormSelectedLayoutSetName: () => void;
refetchLayouts: () => Promise<void>;
refetchLayoutSettings: () => Promise<void>;
refetchTexts: (language: string) => Promise<void>;
reloadPreview: (layoutName: string) => void;
}

export const AppContext = createContext<AppContextProps>(null);

type AppContextProviderProps = {
children: React.ReactNode;
};

export const AppContextProvider = ({ children }: AppContextProviderProps): React.JSX.Element => {
const previewIframeRef = useRef<HTMLIFrameElement>(null);
const { org, app } = useStudioUrlParams();
const {
selectedFormLayoutSetName,
setSelectedFormLayoutSetName,
removeFormSelectedLayoutSetName,
} = useSelectedFormLayoutSetName();

const refetch = useCallback(async (queryKey: QueryKey): Promise<void> => {
const contentWindow: WindowWithQueryClient = previewIframeRef?.current?.contentWindow;

await contentWindow?.queryClient?.invalidateQueries({
queryKey,
});
}, []);

const refetchLayouts = useCallback(async (): Promise<void> => {
return await refetch(['formLayouts', selectedFormLayoutSetName]);
}, [refetch, selectedFormLayoutSetName]);

const refetchLayoutSettings = useCallback(async (): Promise<void> => {
return await refetch(['layoutSettings', selectedFormLayoutSetName]);
}, [refetch, selectedFormLayoutSetName]);

const refetchTexts = useCallback(
async (language: string): Promise<void> => {
return await refetch(['fetchTextResources', language]);
},
[refetch],
);

const reloadPreview = useCallback(
(layoutName: string) => {
if (previewIframeRef?.current?.contentWindow) {
previewIframeRef.current.contentWindow.window.location.href = previewPage(
org,
app,
layoutName,
);
}
},
[app, org],
);

const value = useMemo(
() => ({
previewIframeRef,
selectedFormLayoutSetName,
setSelectedFormLayoutSetName,
removeFormSelectedLayoutSetName,
refetchLayouts,
refetchLayoutSettings,
refetchTexts,
reloadPreview,
}),
[
selectedFormLayoutSetName,
setSelectedFormLayoutSetName,
removeFormSelectedLayoutSetName,
refetchLayouts,
refetchLayoutSettings,
refetchTexts,
reloadPreview,
],
);

return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
};
30 changes: 5 additions & 25 deletions frontend/packages/ux-editor/src/SubApp.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,12 @@
import React, { useRef } from 'react';
import { Provider } from 'react-redux';
import React from 'react';
import { App } from './App';
import { setupStore } from './store';
import './styles/index.css';
import { AppContext } from './AppContext';
import { useReactiveLocalStorage } from 'app-shared/hooks/useReactiveLocalStorage';
import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams';

const store = setupStore();
import { AppContextProvider } from './AppContext';

export const SubApp = () => {
const previewIframeRef = useRef<HTMLIFrameElement>(null);
const { app } = useStudioUrlParams();
const [selectedLayoutSet, setSelectedLayoutSet, removeSelectedLayoutSet] =
useReactiveLocalStorage('layoutSet/' + app, null);

return (
<Provider store={store}>
<AppContext.Provider
value={{
previewIframeRef,
selectedLayoutSet,
setSelectedLayoutSet,
removeSelectedLayoutSet,
}}
>
<App />
</AppContext.Provider>
</Provider>
<AppContextProvider>
<App />
</AppContextProvider>
);
};
15 changes: 7 additions & 8 deletions frontend/packages/ux-editor/src/components/Elements/Elements.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { ConfPageToolbar } from './ConfPageToolbar';
import { DefaultToolbar } from './DefaultToolbar';
import { Heading, Paragraph } from '@digdir/design-system-react';
import { useText } from '../../hooks';
import { selectedLayoutNameSelector } from '../../selectors/formLayoutSelectors';
import { useText, useAppContext, useSelectedFormLayoutName } from '../../hooks';
import { LayoutSetsContainer } from './LayoutSetsContainer';

import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams';
import classes from './Elements.module.css';
import { useAppContext } from '../../hooks/useAppContext';

import { useCustomReceiptLayoutSetName } from 'app-shared/hooks/useCustomReceiptLayoutSetName';

export const Elements = () => {
const { org, app } = useStudioUrlParams();
const selectedLayout: string = useSelector(selectedLayoutNameSelector);
const { selectedLayoutSet } = useAppContext();
const { selectedFormLayoutName } = useSelectedFormLayoutName();
const { selectedFormLayoutSetName } = useAppContext();
const existingCustomReceiptName: string | undefined = useCustomReceiptLayoutSetName(org, app);

const hideComponents = selectedLayout === 'default' || selectedLayout === undefined;
const hideComponents =
selectedFormLayoutName === 'default' || selectedFormLayoutName === undefined;

const t = useText();

Expand All @@ -32,7 +31,7 @@ export const Elements = () => {
<Paragraph className={classes.noPageSelected} size='small'>
{t('left_menu.no_components_selected')}
</Paragraph>
) : existingCustomReceiptName === selectedLayoutSet ? (
) : existingCustomReceiptName === selectedFormLayoutSetName ? (
<ConfPageToolbar />
) : (
<DefaultToolbar />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,16 @@ import userEvent from '@testing-library/user-event';
import { LayoutSetsContainer } from './LayoutSetsContainer';
import { queryClientMock } from 'app-shared/mocks/queryClientMock';
import { renderWithMockStore } from '../../testing/mocks';
import { layoutSetsMock } from '../../testing/layoutMock';
import { layoutSetsMock, layout1NameMock } from '../../testing/layoutMock';
import type { AppContextProps } from '../../AppContext';
import { appStateMock } from '../../testing/stateMocks';
import { QueryKey } from 'app-shared/types/QueryKey';

jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: jest.fn(),
}));
// Test data
const org = 'org';
const app = 'app';
const layoutSetName1 = layoutSetsMock.sets[0].id;
const layoutSetName2 = layoutSetsMock.sets[1].id;
const { selectedLayoutSet } = appStateMock.formDesigner.layout;
const selectedLayoutSet = layout1NameMock;
const setSelectedLayoutSetMock = jest.fn();

describe('LayoutSetsContainer', () => {
Expand Down Expand Up @@ -48,5 +43,5 @@ const render = () => {
selectedLayoutSet: selectedLayoutSet,
setSelectedLayoutSet: setSelectedLayoutSetMock,
};
return renderWithMockStore({}, {}, undefined, appContextProps)(<LayoutSetsContainer />);
return renderWithMockStore({}, undefined, appContextProps)(<LayoutSetsContainer />);
};
Loading
Loading