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

feat(Actions): re-implemented action with new UI #12982

Merged
merged 59 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
513119e
work in progress to migrate existing logic to classes to ecaptulate a…
framitdavid Jun 11, 2024
f2d3b1f
work in progress to migrate existing logic to classes to ecaptulate a…
framitdavid Jun 11, 2024
b62050c
work in progress
framitdavid Jun 14, 2024
e9eb7d5
Merge branch 'main' of https://github.com/Altinn/altinn-studio
framitdavid Jun 18, 2024
bdd2adb
Merge branch 'main' into feat/reImplementActions
framitdavid Jun 18, 2024
43079eb
work in progress with predefined actions
framitdavid Jun 18, 2024
59f66d0
work in progress: added custom action
framitdavid Jun 19, 2024
368856e
remove dead code
framitdavid Jun 19, 2024
b589e9e
added support of update action type from StudioActionModeler
framitdavid Jun 19, 2024
44de617
code cleanups
framitdavid Jun 20, 2024
e2b0592
Styled the action-card to match UX-design
framitdavid Jun 20, 2024
8455931
language
framitdavid Jun 20, 2024
128b0ff
added unit-test for custom-actions
framitdavid Jun 21, 2024
bebe252
add more unit-tests
framitdavid Jun 21, 2024
185c40f
added a few more tests and some lint issues
framitdavid Jun 21, 2024
6627cfd
removed 're', test is work in progress
framitdavid Jun 21, 2024
00dc6bc
added test for ActionsEditor
framitdavid Jun 21, 2024
23daf8b
ensure that server action option is enabled only for custom actions
framitdavid Jun 21, 2024
2aa968d
added comments to explain the bad code
framitdavid Jun 21, 2024
d61ccc8
Merge branch 'main' into feat/reImplementActions
framitdavid Jun 21, 2024
7135a94
revert unsued component
framitdavid Jun 21, 2024
dc2d835
revert unsued component
framitdavid Jun 21, 2024
23a59d5
helptext for action type
framitdavid Jun 21, 2024
5aca1ae
eslint
framitdavid Jun 21, 2024
00a714a
added unit-tests for actionUtils
framitdavid Jun 21, 2024
b7fc08a
renamed actionUtils and fixed import to be releative
framitdavid Jun 21, 2024
0332a67
clean ups
framitdavid Jun 21, 2024
c2b2d12
updated import paths after renaming file
framitdavid Jun 22, 2024
8baeba7
removed one abstraction that was not needed
framitdavid Jun 22, 2024
8823986
moved process-actions utils to utils folder
framitdavid Jun 22, 2024
6047980
added unit-tests for action view/edit mode
framitdavid Jun 22, 2024
fa7a3be
code clean up
framitdavid Jun 22, 2024
7ca25d0
increase test coverage
framitdavid Jun 23, 2024
c03beae
ensure that predefined action select is blank, if aciton name is custom
framitdavid Jun 23, 2024
8a4f596
fixed nullcheck within the test
framitdavid Jun 23, 2024
d2c6d4a
unused variables
framitdavid Jun 23, 2024
8eaa4a8
added more tests
framitdavid Jun 23, 2024
e1d025e
removed unused language keys
framitdavid Jun 23, 2024
d6b9a7b
Merge branch 'main' of https://github.com/Altinn/altinn-studio
framitdavid Jun 24, 2024
383a961
Merge branches 'main' and 'main' of https://github.com/Altinn/altinn-…
framitdavid Jun 24, 2024
324f487
merge main into feature
framitdavid Jun 24, 2024
4018eb5
Merge branch 'main' into feat/reImplementActions
framitdavid Jun 24, 2024
dc21d8c
added e2e-tests for actions
framitdavid Jun 24, 2024
2c4f683
forgotten to add some files on prev commit, e2e-tests
framitdavid Jun 24, 2024
f24e4ac
fixed eslint and renamed a test to be more accurate
framitdavid Jun 24, 2024
839f565
Merge branch 'main' into feat/reImplementActions
framitdavid Jun 25, 2024
590bb4f
Merge branch 'main' into feat/reImplementActions
framitdavid Jun 25, 2024
9471512
Merge branch 'feat/reImplementActions' of https://github.com/Altinn/a…
framitdavid Jun 25, 2024
5aaacbe
refactor actions test to follow same pattern as dataModelConfig
framitdavid Jun 25, 2024
843c59c
lint issue
framitdavid Jun 25, 2024
1df123f
merge main into feature
framitdavid Jun 27, 2024
614f2fc
clean up e2e-tests to be more readable
framitdavid Jun 27, 2024
e3cd481
change texts due to feeback from ux/text-designers
framitdavid Jun 27, 2024
22b304f
PR feedbacks
framitdavid Jun 27, 2024
b78417a
Merge branch 'main' into feat/reImplementActions
framitdavid Jun 27, 2024
c622e1c
Merge branch 'main' into feat/reImplementActions
framitdavid Jun 27, 2024
f852b64
PR feedback
framitdavid Jun 27, 2024
d0576a8
PR feedback
framitdavid Jun 27, 2024
31d3cb4
Merge branch 'main' into feat/reImplementActions
framitdavid Jun 27, 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/app-development/layout/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const PageLayout = (): React.ReactNode => {

const { data: orgs, isPending: orgsPending } = useOrgListQuery();
const { data: repository } = useRepoMetadataQuery(org, app);
const repoOwnerIsOrg = !orgsPending && Object.keys(orgs).includes(repository?.owner.login);
const repoOwnerIsOrg = !orgsPending && Object.keys(orgs).includes(repository?.owner?.login);
framitdavid marked this conversation as resolved.
Show resolved Hide resolved

const {
data: repoStatus,
Expand Down
5 changes: 5 additions & 0 deletions frontend/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,12 @@
"process_editor.configuration_panel.edit_policy_alert_message": "Du må ha tilgangsregler som dekker alle oppgaver. Gå til Tilganger for å sjekke om du har en regel som dekker denne oppgaven. Hvis du ikke har en regel for oppgaven, kan du enten lage en ny regel eller inkludere denne oppgaven i en regel som allerede finnes.",
"process_editor.configuration_panel.edit_policy_open_policy_editor_button": "Gå til Tilganger",
"process_editor.configuration_panel.edit_policy_open_policy_editor_heading": "Åpne Tilganger for å redigere tilgangsregler",
"process_editor.configuration_panel_actions_action_card_custom": "Lag egendefinert handling",
"process_editor.configuration_panel_actions_action_card_custom_label": "Skriv inn navnet på handlingen du vil lage",
"process_editor.configuration_panel_actions_action_card_title": "Handling {{ actionIndex }}",
"process_editor.configuration_panel_actions_action_label": "Handling {{ actionIndex }}: {{ actionName }}",
"process_editor.configuration_panel_actions_action_selector_label": "Velg en handling fra listen",
"process_editor.configuration_panel_actions_action_tab_predefined": "Velg standard handling",
"process_editor.configuration_panel_actions_action_type_help_text": "Hjelpetekst for valg av handlingstype",
"process_editor.configuration_panel_actions_add_new": "Legg til ny handling",
"process_editor.configuration_panel_actions_combobox_description": "Velg en predefinert handling eller definer din egen ved å skrive inn navnet som fritekst i feltet",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Card as StudioCard, type CardProps as StudioCardProps } from '@digdir/design-system-react';
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export {
Divider as StudioDivider,
type DividerProps as StudioDividerProps,
} from '@digdir/design-system-react';
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export {
Heading as StudioHeading,
type HeadingProps as HeadingProps,
} from '@digdir/design-system-react';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Paragraph as StudioParagraph } from '@digdir/design-system-react';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Tabs as StudioTabs, type TabsProps as StudioTabsProps } from '@digdir/design-system-react';
5 changes: 5 additions & 0 deletions frontend/libs/studio-components/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './StudioBooleanToggleGroup';
export * from './StudioButton';
export * from './StudioCenter';
export * from './StudioCodeFragment';
export * from './StudioCard';
export * from './StudioDecimalInput';
export * from './StudioDeleteButton';
export * from './StudioDropdownMenu';
Expand All @@ -15,6 +16,7 @@ export * from './StudioLabelWrapper';
export * from './StudioModal';
export * from './StudioNativeSelect';
export * from './StudioNotFoundPage';
export * from './StudioParagraph';
export * from './StudioPageSpinner';
export * from './StudioPopover';
export * from './StudioProperty';
Expand All @@ -27,3 +29,6 @@ export * from './StudioTextfield';
export * from './StudioToggleableTextfield';
export * from './StudioToggleableTextfieldSchema';
export * from './StudioTreeView';
export * from './StudioTabs';
export * from './StudioHeading';
export * from './StudioDivider';
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ import { BPMNEditor } from './BPMNEditor';
import { VersionHelpText } from './VersionHelpText';

export const Canvas = (): React.ReactElement => {
const { isEditAllowed, bpmnXml } = useBpmnContext();
const { isEditAllowed } = useBpmnContext();

return (
<>
{!isEditAllowed && <VersionHelpText />}
<div className={classes.wrapper} key={bpmnXml}>
{isEditAllowed ? <BPMNEditor /> : <BPMNViewer />}
</div>
<div className={classes.wrapper}>{isEditAllowed ? <BPMNEditor /> : <BPMNViewer />}</div>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* Needs important to be able to override designsystem. Can be removed after we upgrade to latest version */

.cardHeader {
padding: var(--fds-spacing-2) !important;
}

.cardFooter {
padding: 0 0 var(--fds-spacing-3) var(--fds-spacing-3) !important;
gap: var(--fds-spacing-3);
}

.cardDivider {
margin: 0 !important;
}

.cardContent {
padding-left: var(--fds-spacing-3) !important;
padding-right: var(--fds-spacing-3) !important;
}

.tabsContainer {
border: 0;
}

.tabsContent {
padding: var(--fds-spacing-2) 0 !important;
}

.actionView {
margin-bottom: var(--fds-spacing-3);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { render } from '@testing-library/react';
import { BpmnContext } from '@altinn/process-editor/contexts/BpmnContext';
import { mockBpmnContextValue } from '../../../../../../test/mocks/bpmnContextMock';
import { BpmnConfigPanelFormContextProvider } from '@altinn/process-editor/contexts/BpmnConfigPanelContext';
import { PredefinedActions } from '@altinn/process-editor/components/ConfigPanel/ConfigContent/EditActions/ActionsEditor/PredefinedActions';
import React from 'react';

describe('ActionsEditor', () => {
it('should be possible to add new action', () => {
re;
Fixed Show fixed Hide fixed
});
});

const renderActionsEditor = () => {
Fixed Show fixed Hide fixed
return render(
<BpmnContext.Provider value={mockBpmnContextValue}>
<BpmnConfigPanelFormContextProvider>
<PredefinedActions actionElement={actionElementMock} />
</BpmnConfigPanelFormContextProvider>
</BpmnContext.Provider>,
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import {
StudioCard,
StudioTabs,
StudioDivider,
StudioButton,
StudioDeleteButton,
StudioProperty,
StudioParagraph,
} from '@studio/components';
import { CheckmarkIcon } from '@studio/icons';
import { PredefinedActions } from './PredefinedActions';
import { CustomActions } from './CustomActions';
import { type Action, BpmnActionModeler } from '../../../../../utils/bpmn/BpmnActionModeler';
import { useBpmnContext } from '../../../../../contexts/BpmnContext';
import { getPredefinedActions, isActionRequiredForTask } from '../ActionsUtils';

wrt95 marked this conversation as resolved.
Show resolved Hide resolved
import classes from './ActionsEditor.module.css';

enum TabIds {
Predefined = 'predefined',
Custom = 'custom',
}

type ComponentMode = 'edit' | 'view';

type ActionsEditorProps = {
actionElement: Action;
actionIndex: number;
mode?: ComponentMode;
};
export const ActionsEditor = ({
actionElement,
actionIndex,
mode,
}: ActionsEditorProps): React.ReactElement => {
const [componentMode, setComponentMode] = React.useState<ComponentMode>(mode || 'view');
const { t } = useTranslation();
const { bpmnDetails } = useBpmnContext();
const bpmnActionModeler = new BpmnActionModeler(bpmnDetails.element);

const actionLabel = t('process_editor.configuration_panel_actions_action_label', {
actionIndex: actionIndex + 1,
actionName: actionElement.action,
});

if (componentMode === 'edit') {
return (
<ActionEditable
actionElement={actionElement}
actionIndex={actionIndex}
onClose={() => setComponentMode('view')}
onDelete={() => bpmnActionModeler.deleteActionFromTask(actionElement)}
/>
);
}

return (
<StudioProperty.Button
aria-label={actionLabel}
readOnly={isActionRequiredForTask(actionElement.action, bpmnDetails.taskType)}
onClick={() => setComponentMode('edit')}
property={actionLabel}
value={actionElement.action}
className={classes.actionView}
/>
);
};

type ActionEditableProps = {
actionElement: Action;
actionIndex: number;
onClose: () => void;
onDelete: () => void;
};
const ActionEditable = ({
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
actionElement,
actionIndex,
onClose,
onDelete,
}: ActionEditableProps): React.ReactElement => {
const { t } = useTranslation();
const { bpmnDetails } = useBpmnContext();

const isCustomAction =
actionElement.action !== undefined &&
!getPredefinedActions(bpmnDetails.taskType).includes(actionElement.action);

return (
<StudioCard>
<StudioCard.Header className={classes.cardHeader}>
<StudioParagraph size='small'>
{t('process_editor.configuration_panel_actions_action_card_title', {
actionIndex: actionIndex + 1,
})}
</StudioParagraph>
</StudioCard.Header>
<StudioDivider color='subtle' className={classes.cardDivider} />
<StudioCard.Content className={classes.cardContent}>
<StudioTabs
defaultValue={isCustomAction ? TabIds.Custom : TabIds.Predefined}
size='small'
className={classes.tabsContainer}
>
<StudioTabs.List>
<StudioTabs.Tab value={TabIds.Predefined}>
{t('process_editor.configuration_panel_actions_action_tab_predefined')}
</StudioTabs.Tab>
<StudioTabs.Tab value={TabIds.Custom}>
{t('process_editor.configuration_panel_actions_action_card_custom')}
</StudioTabs.Tab>
</StudioTabs.List>
<StudioTabs.Content value={TabIds.Predefined} className={classes.tabsContent}>
<PredefinedActions actionElement={actionElement} />
</StudioTabs.Content>
<StudioTabs.Content value={TabIds.Custom} className={classes.tabsContent}>
<CustomActions actionElement={actionElement} />
</StudioTabs.Content>
</StudioTabs>
</StudioCard.Content>
<StudioCard.Footer className={classes.cardFooter}>
<StudioButton
size='small'
variant='secondary'
color='success'
icon={<CheckmarkIcon />}
onClick={onClose}
/>
<StudioDeleteButton size='small' onDelete={onDelete} />
</StudioCard.Footer>
</StudioCard>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from 'react';
import { userEvent } from '@testing-library/user-event';
import { textMock } from '@studio/testing/mocks/i18nMock';
import { render, screen, waitFor } from '@testing-library/react';
import { CustomActions } from './CustomActions';
import { useActionHandler } from '../hooks/useOnActionChange';
import { BpmnContext } from '../../../../../../contexts/BpmnContext';
import { mockBpmnContextValue } from '../../../../../../../test/mocks/bpmnContextMock';
import { type Action, BpmnActionModeler } from '../../../../../../utils/bpmn/BpmnActionModeler';
import { BpmnConfigPanelFormContextProvider } from '../../../../../../contexts/BpmnConfigPanelContext';

jest.mock('../hooks/useOnActionChange');
jest.mock('../../../../../../utils/bpmn/BpmnActionModeler');

const actionElementMock: Action = {
$type: 'altinn:Action',
};

describe('CustomActions', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should be possible to add new custom action', async () => {
const user = userEvent.setup();

const handeOnActionChangeMock = jest.fn();
(useActionHandler as jest.Mock).mockImplementation(() => ({
handleOnActionChange: handeOnActionChangeMock,
}));

renderCustomAction();

const inputField = screen.getByLabelText(
textMock('process_editor.configuration_panel_actions_action_card_custom_label'),
);

await user.type(inputField, 'My custom action');
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
await waitFor(() => expect(handeOnActionChangeMock).toHaveBeenCalledTimes(1));
expect(handeOnActionChangeMock).toHaveBeenCalledWith(
expect.objectContaining({
target: expect.objectContaining({
value: 'My custom action',
}),
}),
);
});

it('should be possible to change action type', async () => {
const user = userEvent.setup();

const updateTypeForActionMock = jest.fn();
(BpmnActionModeler as jest.Mock).mockImplementation(() => ({
updateTypeForAction: updateTypeForActionMock,
getTypeForAction: jest.fn().mockReturnValue('Process'),
}));

renderCustomAction();

const actionTypeSwitch = screen.getByLabelText(
textMock('process_editor.configuration_panel_actions_set_server_action_label'),
);
await user.click(actionTypeSwitch);

expect(updateTypeForActionMock).toHaveBeenCalledTimes(1);
expect(updateTypeForActionMock).toHaveBeenCalledWith(actionElementMock, 'serverAction');
});
});

const renderCustomAction = () => {
return render(
<BpmnContext.Provider value={mockBpmnContextValue}>
<BpmnConfigPanelFormContextProvider>
<CustomActions actionElement={actionElementMock} />
</BpmnConfigPanelFormContextProvider>
</BpmnContext.Provider>,
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.customActionTextfield {
margin-bottom: var(--fds-spacing-2);
}
Loading
Loading