Skip to content

Commit

Permalink
JNG-5504 modelled table actions (#435)
Browse files Browse the repository at this point in the history
  • Loading branch information
noherczeg authored Jul 8, 2024
1 parent 0b2a244 commit fb80c79
Show file tree
Hide file tree
Showing 51 changed files with 2,566 additions and 2,300 deletions.
1,282 changes: 605 additions & 677 deletions judo-ui-react-itest/ActionGroupTest/model/ActionGroupTest-ui.model

Large diffs are not rendered by default.

1,282 changes: 605 additions & 677 deletions judo-ui-react-itest/ActionGroupTestPro/model/ActionGroupTestPro-ui.model

Large diffs are not rendered by default.

600 changes: 300 additions & 300 deletions judo-ui-react-itest/CRUDActionsTest/model/CRUDActionsTest-ui.model

Large diffs are not rendered by default.

Large diffs are not rendered by default.

300 changes: 150 additions & 150 deletions judo-ui-react-itest/RelationTest/model/RelationTest-ui.model

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@

import static hu.blackbelt.judo.ui.generator.react.UiPageHelper.*;
import static hu.blackbelt.judo.ui.generator.react.UiWidgetHelper.*;
import static hu.blackbelt.judo.ui.generator.typescript.rest.commons.UiCommonsHelper.classDataName;
import static hu.blackbelt.judo.ui.generator.typescript.rest.commons.UiCommonsHelper.firstToUpper;
import static hu.blackbelt.judo.ui.generator.typescript.rest.commons.UiCommonsHelper.*;

@Log
@TemplateHelper
Expand Down Expand Up @@ -65,10 +64,24 @@ public static Set<ActionDefinition> getContainerOwnActionDefinitions(PageContain
actionDefinitions.addAll(buttons.stream().map(Button::getActionDefinition).toList());
actionDefinitions.addAll(buttons.stream().map(Button::getPreFetchActionDefinition).filter(Objects::nonNull).toList());

Set<ActionDefinition> target = new HashSet<>();
Map<String, ActionDefinition> actionDefinitionMap = new HashMap<>();

for (ActionDefinition actionDefinition : flexActionDefinitions) {
OperationType operationType = actionDefinition instanceof InputFormCallOperationActionDefinition cad ? cad.getOperation() : null;
if (operationType == null) {
target.add(actionDefinition);
} else {
actionDefinitionMap.putIfAbsent(getXMIID(operationType), actionDefinition);
}
}

target.addAll(actionDefinitionMap.values());

SortedSet<ActionDefinition> sorted = new TreeSet<>(Comparator.comparing(NamedElement::getFQName));

sorted.addAll(target);
sorted.addAll(actionDefinitions);
sorted.addAll(flexActionDefinitions);

return sorted;
}
Expand Down Expand Up @@ -437,6 +450,15 @@ public static Action getRowViewActionForCreateOpenAction(Action action) {
return null;
}

public static boolean isActionInTableInViewNonBulk(Action action) {
Table table = getTableParentForActionDefinition(action.getActionDefinition());
boolean isTableAction = table != null && table.getTableActionButtonGroup().getButtons().stream().anyMatch(b -> b.getActionDefinition().equals(action.getActionDefinition()));
if (!action.getActionDefinition().isIsBulk() && isTableAction) {
return ((PageDefinition) action.eContainer()).getContainer().isView();
}
return false;
}

public static boolean isActionParentEagerElement(Action action) {
Table table = getTableParentForActionDefinition(action.getActionDefinition());
Link link = getLinkParentForActionDefinition(action.getActionDefinition());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public static String getTranslationKeyForVisualElement(VisualElement element) {
if (element instanceof PageContainer) {
return element.getName().replaceAll("::", ".");
}

String root = element.getPageContainer().getName();
VisualElement target = element;

Expand Down Expand Up @@ -276,6 +277,9 @@ public static Map<String, String> getApplicationTranslations(Application applica
return;
}
translations.put(getTranslationKeyForVisualElement(b), b.getLabel());
if (b.getConfirmation() != null) {
translations.put(getTranslationKeyForVisualElement(b) + ".confirmation", b.getConfirmation().getConfirmationMessage());
}
});
}
if (table.getRowActionButtonGroup() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public static String simpleActionDefinitionName(ActionDefinition actionDefinitio
// CallOperation actions are rolled on the form container, which could lead to method name collisions.
suffix = firstToLower(callOperationActionDefinition.getOperation().getName()) + "For" + firstToUpper(callOperationActionDefinition.getOperation().getOwnerSimpleName());
} else if (actionDefinition instanceof BulkCallOperationActionDefinition bulkCallOperationActionDefinition) {
suffix = "bulk" + firstToUpper(bulkCallOperationActionDefinition.getBulkOf().getOperation().getName());
suffix = "bulk" + firstToUpper(bulkCallOperationActionDefinition.getOperation().getName());
} else if (actionDefinition instanceof OpenOperationInputSelectorActionDefinition openOperationInputSelectorActionDefinition) {
if (openOperationInputSelectorActionDefinition.getSelectorFor() != null) {
if (openOperationInputSelectorActionDefinition.getSelectorFor() instanceof CallOperationActionDefinition callOperationActionDefinition) {
Expand Down Expand Up @@ -479,4 +479,29 @@ public static String getCustomImplementationProps(VisualElement element) {
}
return "data, validation, editMode, storeDiff, isLoading, actions";
}

public static List<PageDefinition> getOperationFormCallerPages(PageContainer container, Application application) {
List<PageDefinition> pages = new ArrayList<>();
if (!container.isForm()) {
return pages;
}
boolean hasOp = getContainerOwnActionDefinitions(container).stream().anyMatch(ActionDefinition::getIsInputFormCallOperationAction);

if (hasOp) {
pages = application.getPages().stream().filter(p -> p.getContainer().equals(container)).toList();
}
return pages;
}

public static boolean hasOperationFormCallerPages(PageContainer container, Application application) {
return !getOperationFormCallerPages(container, application).isEmpty();
}

public static PageDefinition getCallerPageForOperationFormCallButton(Button button, Application application) {
PageContainer container = button.getPageContainer();
List<PageDefinition> pages = getOperationFormCallerPages(container, application);
return pages.stream()
.filter(p -> p.getActions().stream().anyMatch(a -> a.getActionDefinition().equals(button.getActionDefinition())))
.findFirst().orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,7 @@ public static boolean tableHasBulkOperations(Table table) {
}

public static boolean tableHasSelectorColumn(Table table) {
return table.isIsSelectorTable()
|| table.getRowActionDefinitions().stream().anyMatch(a -> ((ActionDefinition) a).isIsBulkCapable())
|| table.getRowActionDefinitions().stream().anyMatch(a -> ((ActionDefinition) a).getIsDeleteAction())
|| table.getRowActionDefinitions().stream().anyMatch(a -> ((ActionDefinition) a).getIsRemoveAction());
return table.isIsSelectorTable() || tableHasBulkOperations(table);
}

public static Column getFirstTitleColumnForTable(Table table) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
columnsActionCalculator,
} from '~/components/table';
import { RowHighlightLegend } from '~/components/table';
import { useConfirmDialog } from '~/components/dialog';
import { basePageSizeOptions, baseTableConfig } from '~/config';
import { useDataStore } from '~/hooks';
import { transformRowStylings } from '~/theme/table-row-highlighting';
Expand Down Expand Up @@ -133,6 +134,7 @@ export function EagerTable<T extends GridValidRowModel, TStored extends T, S ext
const columnStateKey = `${uniqueId}-columnState`;
{{/ if }}

const { openConfirmDialog } = useConfirmDialog();
const { locale: l10nLocale } = useL10N();
const { downloadFile, extractFileNameFromToken } = fileHandling();
const { getItemParsed, getItemParsedWithDefault, setItemStringified } = useDataStore('sessionStorage');
Expand Down Expand Up @@ -464,6 +466,17 @@ export function EagerTable<T extends GridValidRowModel, TStored extends T, S ext
startIcon={<MdiIcon path={toolBarAction.startIcon ? toolBarAction.startIcon : ''} />}
variant={toolBarAction.variant}
onClick={async () => {
if (toolBarAction.confirmation && (typeof toolBarAction.confirmationCondition === 'undefined' || toolBarAction.confirmationCondition === true)) {
const result = await openConfirmDialog(
toolBarAction.id,
toolBarAction.confirmation,
t('judo.modal.confirm.confirm-title', { defaultValue: 'Confirm action' }) as string,
);

if (!result) {
return;
}
}
if (toolBarAction.name === calculateActionName(relationName, 'filterAction')) {
await filterAction(toolBarAction.id);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ StripedDataGrid,
columnsActionCalculator,
RowHighlightLegend,
} from '~/components/table';
import { useConfirmDialog } from '~/components/dialog';
import { basePageSizeOptions, baseTableConfig, filterDebounceMs } from '~/config';
import { useDataStore } from '~/hooks';
import { transformRowStylings } from '~/theme/table-row-highlighting';
Expand Down Expand Up @@ -166,6 +167,7 @@ export function LazyTable<T extends GridValidRowModel, TStored extends T, S exte
}, [rowHighlighting]);
{{/ if }}

const { openConfirmDialog } = useConfirmDialog();
const [isInternalLoading, setIsInternalLoading] = useState<boolean>(false);
const [totalCount, setTotalCount] = useState<number>(-1);
const [data, setData] = useState<GridRowModel<T>[]>(dataProp);
Expand Down Expand Up @@ -625,6 +627,17 @@ export function LazyTable<T extends GridValidRowModel, TStored extends T, S exte
startIcon={<MdiIcon path={toolBarAction.startIcon ? toolBarAction.startIcon : ''} />}
variant={toolBarAction.variant}
onClick={async () => {
if (toolBarAction.confirmation && (typeof toolBarAction.confirmationCondition === 'undefined' || toolBarAction.confirmationCondition === true)) {
const result = await openConfirmDialog(
toolBarAction.id,
toolBarAction.confirmation,
t('judo.modal.confirm.confirm-title', { defaultValue: 'Confirm action' }) as string,
);

if (!result) {
return;
}
}
if (toolBarAction.name === calculateActionName(relationName, 'filterAction')) {
await filterAction(toolBarAction.id);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,22 @@ export function {{ componentName table }}(props: {{ componentName table }}Props)
const toolBarActions: ToolBarActionProps<{{# with (getReferenceClassType table) as |classType| }}{{# if classType.isMapped }}{{ classDataName (getReferenceClassType table) 'Stored' }}{{ else }}{{ classDataName (getReferenceClassType table) '' }}{{/ if }}{{/ with }}>[] = [
{{# each table.tableActionButtonGroup.buttons as |button| }}
{
name:"{{ simpleActionDefinitionName actionDefinition }}",
id:"{{ getXMIID button }}",
name: "{{ simpleActionDefinitionName actionDefinition }}",
id: "{{ getXMIID button }}",
{{# if button.icon }}
startIcon:"{{ button.icon.iconName }}",
startIcon: "{{ button.icon.iconName }}",
{{/ if }}
variant:{{{ variantForButton button }}},
hiddenBy:{{# if button.hiddenBy }}true{{ else }}false{{/ if }},
label:{ 'translationKey': '{{ getTranslationKeyForVisualElement button }}', 'defaultValue': '{{ button.label }}' },
variant: {{{ variantForButton button }}},
hiddenBy: {{# if button.hiddenBy }}true{{ else }}false{{/ if }},
label: { 'translationKey': '{{ getTranslationKeyForVisualElement button }}', 'defaultValue': '{{ button.label }}' },
enabled: (data: {{# with (getReferenceClassType table) as |classType| }}{{# if classType.isMapped }}{{ classDataName (getReferenceClassType table) 'Stored' }}[]{{ else }}{{ classDataName (getReferenceClassType table) '' }}[]{{/ if }}{{/ with }}, selectionModel: GridRowSelectionModel, ownerData?: any, isFormUpdateable?: () => boolean): boolean => {{{ tableButtonVisibilityConditions button table container }}},
isBulk: {{ boolValue actionDefinition.isBulk }},
{{# if button.confirmation }}
confirmation: t('{{ getTranslationKeyForVisualElement button }}.confirmation', { defaultValue: '{{ button.confirmation.confirmationMessage }}' }) as string,
{{# if (shouldRenderConfirmationCondition button) }}
confirmationCondition: data?.{{ button.confirmation.confirmationCondition.name }} ?? false,
{{/ if }}
{{/ if }}
},
{{/ each }}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export interface {{ componentName table }}ActionDefinitions {
{{/ if }}
{{/ each }}
{{# each table.rowActionDefinitions as |actionDefinition| }}
{{ simpleActionDefinitionName actionDefinition }}?: (row: {{ classDataName (getReferenceClassType table) 'Stored' }}{{# if actionDefinition.isBulkCapable }}, silentMode?: boolean{{ else }}{{# if actionDefinition.isOpenPageAction }}, isDraft?: boolean{{/ if }}{{/ if }}) => Promise<void>;
{{ simpleActionDefinitionName actionDefinition }}?: (row: {{ classDataName (getReferenceClassType table) 'Stored' }}{{# if actionDefinition.isOpenPageAction }}, isDraft?: boolean{{/ if }}) => Promise<void>;
{{/ each }}
{{ table.relationType.name }}AdditionalToolbarButtons?: (
{{# with (getReferenceClassType table) as |classType| }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export default function {{ containerComponentName container }}Dialog({{# unless
const createDropdownRef = useRef<HTMLDivElement>(null);
{{/ if }}
const {
{{# if (hasOperationFormCallerPages container application) }}
formFor,
{{/ if }}
ownerData,
onClose
{{# unless (containerIsEmptyDashboard container) }},
Expand Down Expand Up @@ -150,7 +153,7 @@ export default function {{ containerComponentName container }}Dialog({{# unless
</DialogContent>
<DialogActions>
{{# each container.actionButtonGroup.buttons as |button| }}
{ {{{ containerButtonAvailable button }}} && actions.{{ simpleActionDefinitionName actionDefinition }} && (
{ {{# if button.actionDefinition.isInputFormCallOperationAction }}formFor === '{{ safeName (getCallerPageForOperationFormCallButton button application) }}' && {{/ if }}{{{ containerButtonAvailable button }}} && actions.{{ simpleActionDefinitionName actionDefinition }} && (
<Grid className="page-action" item>
{{# if button.actionDefinition.isCreateAction }}
{{# unless button.actionDefinition.autoOpenAfterCreate }}
Expand Down
32 changes: 20 additions & 12 deletions judo-ui-react/src/main/resources/actor/src/containers/types.ts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
export interface {{ pageContainerActionDefinitionTypeName container }}{{# if (containerHasRelationComponents container) }} extends {{# each (getContainerActionsExtends container) as |ext| }}{{ ext }}{{# unless @last}},{{/ unless}}{{/ each }}{{/ if }} {
getPageTitle?: ({{# unless container.table }}data: {{ classDataName container.dataElement '' }}{{/ unless }}) => string;
{{# each (getContainerOwnActionDefinitions container) as |actionDefinition| }}
{{# if actionDefinition.isCallOperationAction }}
// {{ getXMIID actionDefinition.operation }}
// {{ actionDefinition.operation.name }}
{{/ if }}
{{ simpleActionDefinitionName actionDefinition }}?: ({{{ getContainerOwnActionParameters actionDefinition container }}}) => Promise<{{{ getContainerOwnActionReturnType actionDefinition container }}}>;
{{/ each }}
{{# each (getOnBlurAttributesForContainer container) as |attributeType| }}
Expand Down Expand Up @@ -53,7 +57,9 @@
{{# if actionDefinition.isRefreshAction }}
{{ simpleActionDefinitionName actionDefinition }}?: (queryCustomizer: {{ classDataName container.dataElement 'QueryCustomizer' }}) => Promise<JudoRestResponse<{{ classDataName container.dataElement 'Stored' }}{{# if container.table }}[]{{/ if }}>>;
{{ else }}
{{ simpleActionDefinitionName actionDefinition }}?: () => Promise<void>;
{{# unless actionDefinition.isCallOperationAction }}
{{ simpleActionDefinitionName actionDefinition }}?: () => Promise<void>;
{{/ unless }}
{{/ if }}
{{/ each }}
}
Expand All @@ -79,13 +85,25 @@

export interface {{ containerComponentName container }}DialogActions extends {{ pageContainerActionDefinitionTypeName container }} {
{{# each container.pageActionDefinitions as |actionDefinition| }}
{{ simpleActionDefinitionName actionDefinition }}?: ({{{ getContainerOwnActionParameters actionDefinition container }}}) => Promise<{{{ getContainerOwnActionReturnType actionDefinition container }}}>;
{{# unless actionDefinition.isCallOperationAction }}
{{ simpleActionDefinitionName actionDefinition }}?: ({{{ getContainerOwnActionParameters actionDefinition container }}}) => Promise<{{{ getContainerOwnActionReturnType actionDefinition container }}}>;
{{/ unless }}
{{/ each }}
}

{{# if (hasOperationFormCallerPages container application) }}
export type FormFor{{ containerComponentName container }} =
{{# each (getOperationFormCallerPages container application) as |actionDefinition| }}
'{{ safeName actionDefinition }}'{{# unless @last}} | {{/ unless}}
{{/ each }};
{{/ if }}

export interface {{ containerComponentName container }}DialogProps {
ownerData: any;
onClose: () => Promise<void>;
{{# if (hasOperationFormCallerPages container application) }}
formFor: FormFor{{ containerComponentName container }};
{{/ if }}
{{# unless (containerIsEmptyDashboard container) }}
actions: {{ containerComponentName container }}DialogActions;
dataPath?: string;
Expand All @@ -109,16 +127,6 @@
isDraft?: boolean;
{{/ unless }}
};

export interface {{ containerComponentName container }}PageActions extends {{ pageContainerActionDefinitionTypeName container }} {
{{# each container.pageActionDefinitions as |actionDefinition| }}
{{# if actionDefinition.isRefreshAction }}
{{ simpleActionDefinitionName actionDefinition }}?: (queryCustomizer: {{ classDataName container.dataElement 'QueryCustomizer' }}) => Promise<JudoRestResponse<{{ classDataName container.dataElement 'Stored' }}{{# if container.table }}[]{{/ if }}>>;
{{ else }}
{{ simpleActionDefinitionName actionDefinition }}?: () => Promise<void>;
{{/ if }}
{{/ each }}
}
{{ else }}
export const _ = 'placeholder';
{{/ unless }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@ export default function {{ pageName page }}(props: {{ pageName page }}Props) {

// ViewModel setup
const viewModel: {{ containerComponentName page.container }}ViewModel = {
{{# if (hasOperationFormCallerPages page.container application) }}
formFor: '{{ safeName page }}',
{{/ if }}
onClose,
actions,
ownerData,
Expand Down Expand Up @@ -318,6 +321,9 @@ export default function {{ pageName page }}(props: {{ pageName page }}Props) {
isLoading={isLoading}
editMode={editMode}
refreshCounter={refreshCounter}
{{# if (hasOperationFormCallerPages page.container application) }}
formFor={'{{ safeName page }}'}
{{/ if }}
{{# unless (containerIsEmptyDashboard page.container) }}
{{# if page.container.isSelector }}
selectionDiff={selectionDiff}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// AddAction: {{ getXMIID action }}
const {{ simpleActionDefinitionName action.actionDefinition }} = async (selected: {{ classDataName action.actionDefinition.targetType 'Stored' }}[]) => {
onSubmit(selected);
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// AutocompleteRangeAction: {{ getXMIID action }}
const {{ simpleActionDefinitionName action.actionDefinition }} = async (queryCustomizer: {{ classDataName action.actionDefinition.targetType 'QueryCustomizer' }}): Promise<{{ classDataName action.actionDefinition.targetType 'Stored' }}[]> => {
{{# with (getLinkParentForActionDefinition action.actionDefinition) as |link| }}
try {
Expand Down
Loading

0 comments on commit fb80c79

Please sign in to comment.