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

JNG-5504 modelled table actions #435

Merged
merged 13 commits into from
Jul 8, 2024
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 (table != null && !action.getActionDefinition().isIsBulk() && isTableAction) {
noherczeg marked this conversation as resolved.
Show resolved Hide resolved
return ((PageDefinition) action.eContainer()).getContainer().isView();
}
return false;
}
noherczeg marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -11,6 +11,7 @@
import org.eclipse.emf.ecore.EObject;
import org.springframework.util.StringUtils;

import java.lang.reflect.Array;
noherczeg marked this conversation as resolved.
Show resolved Hide resolved
import java.util.*;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -88,7 +89,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 @@ -421,10 +422,14 @@ public static String containerButtonGroupButtonDisabledConditions(Button button,
}
segments.add("isLoading");

if (container.isIsSelector() && button.getActionDefinition() instanceof CallOperationActionDefinition callOperationActionDefinition) {
if (!callOperationActionDefinition.getOperation().getInput().isIsOptional()) {
segments.add("!selectionDiff.length");
try {
if (container.isIsSelector() && button.getActionDefinition() instanceof CallOperationActionDefinition callOperationActionDefinition) {
if (!callOperationActionDefinition.getOperation().getInput().isIsOptional()) {
segments.add("!selectionDiff.length");
}
}
} catch (Exception e) {
throw e;
noherczeg marked this conversation as resolved.
Show resolved Hide resolved
}
noherczeg marked this conversation as resolved.
Show resolved Hide resolved

return String.join(" || ", segments);
Expand Down Expand Up @@ -479,4 +484,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;
}
noherczeg marked this conversation as resolved.
Show resolved Hide resolved

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);
}
noherczeg marked this conversation as resolved.
Show resolved Hide resolved
}
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
Loading
Loading