Skip to content

Commit

Permalink
JNG-6015 container extra action buttons (#490)
Browse files Browse the repository at this point in the history
  • Loading branch information
noherczeg authored Nov 16, 2024
1 parent 3245636 commit f9bac01
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 14 deletions.
58 changes: 58 additions & 0 deletions docs/pages/01_ui_react.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,64 @@ const containerLevelHook: ViewGalaxyViewContainerHook = () => {
};
----

=== Adding Custom buttons to container action bars

In case we cannot model buttons on a container level which should call actions, we can add them via a component hook.

> This feature should not be confused with the one above. In this case we can add extra visual elements,
while the above is about manually implementing the corresponding actions.

*Locating interface keys:*

- We should inspect the page / dialog in dev-tools, and search for the id of the container in the `src/containers` folder.
- Afterwards look for a `const` ending in `CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY`

*Registering implementations*

Implementations can be registered in one central location: `src/custom/application-customizer.tsx`.

*src/custom/application-customizer.tsx:*
[source,typescriptjsx]
----
import { type BundleContext } from '@pandino/pandino-api';
import {
SERVICES_AUTHOR_PRODUCT_AUTHOR_PRODUCT_TABLE_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY,
ServicesAuthorProductAuthorProduct_TableContainerExtraActionsComponentProps
} from '~/containers/Services/AuthorProduct/AuthorProduct_Table/customization';
import { MdiIcon } from '~/components';
import LoadingButton from '@mui/lab/LoadingButton';
import Grid from '@mui/material/Grid';
export class DefaultApplicationCustomizer implements ApplicationCustomizer {
async customize(context: BundleContext): Promise<void> {
context.registerService(SERVICES_AUTHOR_PRODUCT_AUTHOR_PRODUCT_TABLE_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY, ExtraContainerButtons);
}
}
export function ExtraContainerButtons({ isLoading, actions, }: ServicesAuthorProductAuthorProduct_TableContainerExtraActionsComponentProps) {
// we can call other hooks here
return (
<>
<Grid className="page-action" item>
<LoadingButton
loading={isLoading}
loadingPosition="start"
variant={'contained'}
onClick={() => actions?.createProductAction?.(null as any)}
disabled={isLoading}
startIcon={<MdiIcon path="file-document-plus-outline" />}
>
Create Product
</LoadingButton>
</Grid>
</>
);
}
----

For the list of every prop available, we can check the `ServicesAuthorProductAuthorProduct_TableContainerExtraActionsComponentProps` interface
as shown above.

=== How to locate actions

Every action is implemented in Pages/Dialogs. The actions of Tables and Single Components which are inlined in a certain
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ import LoadingButton from '@mui/lab/LoadingButton';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import { OBJECTCLASS } from '@pandino/pandino-api';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { Suspense, lazy } from 'react';
import type { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { MdiIcon, PageHeader, useJudoNavigation } from '~/components';
import { useConfirmDialog } from '~/components/dialog';
import { CUSTOM_VISUAL_ELEMENT_INTERFACE_KEY } from '~/custom';
import type { Planet, PlanetStored } from '~/services/data-api/model/Planet';
import type { PlanetQueryCustomizer } from '~/services/data-api/rest/PlanetQueryCustomizer';
import { mainContainerPadding } from '~/theme';
Expand All @@ -23,6 +26,8 @@ import { getValue } from '~/utilities/helper';

import type { PlanetViewActionDefinitions, PlanetViewPageActions, PlanetViewPageProps } from './types';

import { PLANET_VIEW_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY } from './customization';

const PlanetView = lazy(() => import('~/containers/Planet/View/PlanetView'));

// Name: Planet::View
Expand Down Expand Up @@ -138,7 +143,18 @@ export default function PlanetViewPage(props: PlanetViewPageProps) {
</LoadingButton>
</Grid>
)}
<div>{/* Placeholder */}</div>
<ComponentProxy
filter={`(${OBJECTCLASS}=${PLANET_VIEW_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY})`}
editMode={editMode}
data={data}
validation={validation}
storeDiff={storeDiff}
submit={submit}
isLoading={isLoading}
actions={actions}
>
<div>{/* Placeholder */}</div>
</ComponentProxy>
</PageHeader>
<Suspense>
<Box sx={mainContainerPadding}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,23 @@ import MenuItem from '@mui/material/MenuItem';
import MenuList from '@mui/material/MenuList';
import Paper from '@mui/material/Paper';
import Popper from '@mui/material/Popper';
import { OBJECTCLASS } from '@pandino/pandino-api';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { Suspense, lazy, useCallback, useRef, useState } from 'react';
import type { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { MdiIcon, useJudoNavigation } from '~/components';
import { useConfirmDialog } from '~/components/dialog';
import { CUSTOM_VISUAL_ELEMENT_INTERFACE_KEY } from '~/custom';
import type { ViewGalaxy, ViewGalaxyStored } from '~/services/data-api/model/ViewGalaxy';
import type { ViewGalaxyQueryCustomizer } from '~/services/data-api/rest/ViewGalaxyQueryCustomizer';
import { processQueryCustomizer } from '~/utilities';
import { getValue } from '~/utilities/helper';

import type { ViewGalaxyFormActionDefinitions, ViewGalaxyFormDialogActions, ViewGalaxyFormDialogProps } from './types';

import { VIEW_GALAXY_FORM_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY } from './customization';

const ViewGalaxyForm = lazy(() => import('~/containers/View/Galaxy/Form/ViewGalaxyForm'));

// Name: View::Galaxy::Form
Expand Down Expand Up @@ -194,6 +199,16 @@ export default function ViewGalaxyFormDialog(props: ViewGalaxyFormDialogProps) {
</Popper>
</Grid>
)}
<ComponentProxy
filter={`(${OBJECTCLASS}=${VIEW_GALAXY_FORM_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY})`}
editMode={editMode}
data={data}
validation={validation}
storeDiff={storeDiff}
submit={submit}
isLoading={isLoading}
actions={actions}
></ComponentProxy>
</DialogActions>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,23 @@ import DialogContent from '@mui/material/DialogContent';
import DialogTitle from '@mui/material/DialogTitle';
import Grid from '@mui/material/Grid';
import IconButton from '@mui/material/IconButton';
import { OBJECTCLASS } from '@pandino/pandino-api';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { Suspense, lazy } from 'react';
import type { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { MdiIcon, useJudoNavigation } from '~/components';
import { useConfirmDialog } from '~/components/dialog';
import { CUSTOM_VISUAL_ELEMENT_INTERFACE_KEY } from '~/custom';
import type { ViewGalaxy, ViewGalaxyStored } from '~/services/data-api/model/ViewGalaxy';
import type { ViewGalaxyQueryCustomizer } from '~/services/data-api/rest/ViewGalaxyQueryCustomizer';
import { processQueryCustomizer } from '~/utilities';
import { getValue } from '~/utilities/helper';

import type { ViewGalaxyViewActionDefinitions, ViewGalaxyViewDialogActions, ViewGalaxyViewDialogProps } from './types';

import { VIEW_GALAXY_VIEW_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY } from './customization';

const ViewGalaxyView = lazy(() => import('~/containers/View/Galaxy/View/ViewGalaxyView'));

// Name: View::Galaxy::View
Expand Down Expand Up @@ -181,6 +186,16 @@ export default function ViewGalaxyViewDialog(props: ViewGalaxyViewDialogProps) {
</LoadingButton>
</Grid>
)}
<ComponentProxy
filter={`(${OBJECTCLASS}=${VIEW_GALAXY_VIEW_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY})`}
editMode={editMode}
data={data}
validation={validation}
storeDiff={storeDiff}
submit={submit}
isLoading={isLoading}
actions={actions}
></ComponentProxy>
</DialogActions>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ import LoadingButton from '@mui/lab/LoadingButton';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import { OBJECTCLASS } from '@pandino/pandino-api';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { Suspense, lazy } from 'react';
import type { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { MdiIcon, PageHeader, useJudoNavigation } from '~/components';
import { useConfirmDialog } from '~/components/dialog';
import { CUSTOM_VISUAL_ELEMENT_INTERFACE_KEY } from '~/custom';
import type { ViewGalaxy, ViewGalaxyStored } from '~/services/data-api/model/ViewGalaxy';
import type { ViewGalaxyQueryCustomizer } from '~/services/data-api/rest/ViewGalaxyQueryCustomizer';
import { mainContainerPadding } from '~/theme';
Expand All @@ -23,6 +26,8 @@ import { getValue } from '~/utilities/helper';

import type { ViewGalaxyViewActionDefinitions, ViewGalaxyViewPageActions, ViewGalaxyViewPageProps } from './types';

import { VIEW_GALAXY_VIEW_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY } from './customization';

const ViewGalaxyView = lazy(() => import('~/containers/View/Galaxy/View/ViewGalaxyView'));

// Name: View::Galaxy::View
Expand Down Expand Up @@ -138,7 +143,18 @@ export default function ViewGalaxyViewPage(props: ViewGalaxyViewPageProps) {
</LoadingButton>
</Grid>
)}
<div>{/* Placeholder */}</div>
<ComponentProxy
filter={`(${OBJECTCLASS}=${VIEW_GALAXY_VIEW_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY})`}
editMode={editMode}
data={data}
validation={validation}
storeDiff={storeDiff}
submit={submit}
isLoading={isLoading}
actions={actions}
>
<div>{/* Placeholder */}</div>
</ComponentProxy>
</PageHeader>
<Suspense>
<Box sx={mainContainerPadding}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
{{# each (getEnumDataTypesForContainer container) as |imp| }}
import type { {{ restParamName imp }} } from '~/services/data-api/model/{{ restParamName imp }}';
{{/ each }}
import type { {{ pageContainerActionDefinitionTypeName container }} } from './types';
import type { {{ pageContainerActionDefinitionTypeName container }}, {{ containerComponentName container }}PageActions } from './types';
{{/ unless }}

{{# unless (containerIsEmptyDashboard container) }}
Expand All @@ -25,6 +25,17 @@
{{/ unless }}
) => {{ pageContainerActionDefinitionTypeName container }};

export const {{ camelCaseNameToInterfaceKey (containerComponentName container) }}_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY = '{{~ camelCaseNameToInterfaceKey (containerComponentName container) }}_CONTAINER_EXTRA_ACTIONS_HOOK';
export interface {{ containerComponentName container }}ContainerExtraActionsComponentProps {
{{# unless container.table }}
data: {{ classDataName container.dataElement 'Stored' }},
storeDiff: (attributeName: keyof {{ classDataName container.dataElement '' }}, value: any) => void,
{{/ unless }}
editMode?: boolean,
isLoading?: boolean,
actions?: {{ containerComponentName container }}PageActions,
}

{{ else }}
export const _ = 'placeholder';
{{/ unless }}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

import { lazy, Suspense{{# if (containerHasCreateAction container) }}, useRef, useState, useCallback{{/ if }} } from 'react';
import type { Dispatch, SetStateAction } from 'react';
{{# if (containerHasActionsWithCustomImplementation container) }}
import { OBJECTCLASS } from '@pandino/pandino-api';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { CUSTOM_VISUAL_ELEMENT_INTERFACE_KEY } from '~/custom';
{{/ if }}
import { OBJECTCLASS } from '@pandino/pandino-api';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { CUSTOM_VISUAL_ELEMENT_INTERFACE_KEY } from '~/custom';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import DialogTitle from '@mui/material/DialogTitle';
Expand Down Expand Up @@ -52,6 +50,7 @@ import { useConfirmDialog } from '~/components/dialog';
{{/ each }}
} from './customization';
{{/ if }}
import { {{ camelCaseNameToInterfaceKey (containerComponentName container) }}_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY } from './customization';
{{/ unless }}

{{# unless (containerIsEmptyDashboard container) }}
Expand Down Expand Up @@ -290,6 +289,22 @@ export default function {{ containerComponentName container }}Dialog({{# unless
</Grid>
)}
{{/ each }}
<ComponentProxy
filter={`(${OBJECTCLASS}=${ {{~ camelCaseNameToInterfaceKey (containerComponentName container) }}_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY})`}
editMode={editMode}
{{# unless container.table }}
data={data}
validation={validation}
storeDiff={storeDiff}
submit={submit}
{{/ unless }}
{{# if container.isSelector }}
selectionDiff={selectionDiff}
{{/ if }}
isLoading={isLoading}
actions={actions}
>
</ComponentProxy>
</DialogActions>
{{/ unless }}
</>
Expand Down
24 changes: 18 additions & 6 deletions judo-ui-react/src/main/resources/actor/src/containers/page.tsx.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

import { lazy, Suspense } from 'react';
import type { Dispatch, SetStateAction } from 'react';
{{# if (containerHasActionsWithCustomImplementation container) }}
import { OBJECTCLASS } from '@pandino/pandino-api';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { CUSTOM_VISUAL_ELEMENT_INTERFACE_KEY } from '~/custom';
{{/ if }}
import { OBJECTCLASS } from '@pandino/pandino-api';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { CUSTOM_VISUAL_ELEMENT_INTERFACE_KEY } from '~/custom';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
Expand Down Expand Up @@ -41,6 +39,7 @@ import { mainContainerPadding } from '~/theme';
{{/ each }}
} from './customization';
{{/ if }}
import { {{ camelCaseNameToInterfaceKey (containerComponentName container) }}_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY } from './customization';
{{/ unless }}

{{# unless (containerIsEmptyDashboard container) }}
Expand Down Expand Up @@ -118,7 +117,20 @@ export default function {{ containerComponentName container }}Page ({{# unless (
</Grid>
)}
{{/ each }}
<div>{/* Placeholder */}</div>
<ComponentProxy
filter={`(${OBJECTCLASS}=${ {{~ camelCaseNameToInterfaceKey (containerComponentName container) }}_CONTAINER_EXTRA_ACTIONS_HOOK_INTERFACE_KEY})`}
editMode={editMode}
{{# unless container.table }}
data={data}
validation={validation}
storeDiff={storeDiff}
submit={submit}
{{/ unless }}
isLoading={isLoading}
actions={actions}
>
<div>{/* Placeholder */}</div>
</ComponentProxy>
</PageHeader>
<Suspense>
<Box sx={mainContainerPadding}>
Expand Down

0 comments on commit f9bac01

Please sign in to comment.