Skip to content

Commit

Permalink
JNG-5914 table tag representation
Browse files Browse the repository at this point in the history
  • Loading branch information
noherczeg committed Sep 6, 2024
1 parent bf1d007 commit 16fa6c9
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,20 @@ export default function ViewGalaxyView(props: ViewGalaxyViewProps) {
alignItems="stretch"
justifyContent="flex-start"
>
{'LMAO'}
<ViewGalaxyViewStarsComponent
uniqueId={
'God/(esm/_8AxbAE7tEeycO-gUAWxcVg)/TabularReferenceFieldRelationDefinedTable'
}
actions={actions}
dataPath={dataPath ? dataPath + '.stars' : 'stars'}
isOwnerLoading={isLoading}
isDraft={isDraft}
validationError={validation.get('stars')}
ownerData={data}
editMode={editMode}
isFormUpdateable={isFormUpdateable}
storeDiff={storeDiff}
/>
</Grid>
</Grid>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public static List<Table> getTablesForPageContainers(Application application) {

public static List<Table> getTagsForPageContainers(Application application) {
return application.getPageContainers().stream().flatMap(c -> ((List<Table>) c.getTables()).stream())
.filter(t -> TableRepresentation.TAG.equals(t.getRepresentationComponent()))
.filter(UiWidgetHelper::isTableTag)
.collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,8 @@ public static List<Column> customizableColumns(Table table) {
public static boolean checkboxSelectionEnabled(Table table) {
return table.getCheckboxSelection() == null || table.getCheckboxSelection() != CheckboxSelection.DISABLED;
}

public static boolean isTableTag(Table table) {
return TableRepresentation.TAG.equals(table.getRepresentationComponent());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ public static Column getFirstAutocompleteColumnForLink(Link link) {
return column.orElse(null);
}

public static Column getFirstAutocompleteColumnForTable(Table table) {
Optional<Column> column = table.getColumns().stream()
.filter(c -> c.getAttributeType().getDataType() instanceof StringType && !c.getAttributeType().getIsMemberTypeTransient())
.findFirst();
return column.orElse(null);
}

public static boolean isAutocompleteAvailable(Link link) {
if (link.getParts().isEmpty()) {
return false;
Expand Down Expand Up @@ -445,6 +452,10 @@ public static Integer calculateLinkAutocompleteRows(Link link) {
return defaultValue != null ? defaultValue : 10;
}

public static Integer calculateTableAutocompleteRows(Table table) {
return 10;
}

public static boolean flexParentIsNotTab(Flex flex) {
return !(flex.eContainer() instanceof Tab);
}
Expand All @@ -468,6 +479,13 @@ public static Column getSortColumnForLink(Link link) {
return getFirstAutocompleteColumnForLink(link);
}

public static Column getSortColumnForTable(Table table) {
if (table.getDefaultSortColumn() != null) {
return table.getDefaultSortColumn();
}
return getFirstAutocompleteColumnForTable(table);
}

public static boolean isLinkAssociation(Link link) {
return link.getRelationType().getIsRelationKindAssociation();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ export interface TagsProps<P, T> {
editMode?: boolean;
autoCompleteAttribute: keyof T;
identifierAttribute: string | keyof T;
onAutoCompleteSearch: (searchText: string, preparedQueryCustomizer: QueryCustomizer<T>) => Promise<T[]>;
onAutoCompleteSearch?: (searchText: string, preparedQueryCustomizer: QueryCustomizer<T>) => Promise<T[]>;
additionalMaskAttributes?: string[];
limitOptions?: number;
onValueChange: (target: T[]) => Promise<void>;
onValueChange?: (target: T[]) => Promise<void>;
onItemClick?: (target: T) => void;
onSearchDialogsClick?: () => void;
searchDialogTitle?: string;
Expand Down Expand Up @@ -76,7 +76,6 @@ export function Tags<P, T>(props: TagsProps<P, T>) {
} = props;
const [options, setOptions] = useState<any[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const prevValues = useRef<T[]>(ownerData[name] as T[]);

const handleSearch = async (searchText: string) => {
try {
Expand All @@ -101,7 +100,7 @@ export function Tags<P, T>(props: TagsProps<P, T>) {
limit: limitOptions,
},
};
const response = await onAutoCompleteSearch(searchText, queryCustomizer);
const response = await onAutoCompleteSearch!(searchText, queryCustomizer);
setOptions(response);
} catch (error) {
console.error(error);
Expand All @@ -123,9 +122,9 @@ export function Tags<P, T>(props: TagsProps<P, T>) {

const onChange = useCallback(
(event: SyntheticEvent, value: (string | any)[]) => {
// prevent useEffect below from triggering recursion
prevValues.current = value;
onValueChange(value as any);
if (typeof onValueChange === 'function') {
onValueChange(value as any);
}
},
[ownerData, onValueChange],
);
Expand All @@ -143,14 +142,6 @@ export function Tags<P, T>(props: TagsProps<P, T>) {
[ownerData, onItemClick],
);

useEffect(() => {
// prevent recursion
if (prevValues.current !== ownerData[name]) {
prevValues.current = ownerData[name] as T[];
onValueChange(ownerData[name] as any);
}
}, [ownerData[name]]);

return (
<Autocomplete
multiple
Expand All @@ -166,10 +157,10 @@ export function Tags<P, T>(props: TagsProps<P, T>) {
getOptionKey={(option) => option[identifierAttribute]}
getOptionLabel={(option) => option[autoCompleteAttribute] ?? ''}
isOptionEqualToValue={(option, value) => option[identifierAttribute] === value[identifierAttribute]}
onOpen={ () => {
onOpen={ onAutoCompleteSearch ? () => {
setOptions([]); // always start with a clean slate
handleSearch('');
} }
} : undefined }
onInputChange={onInputChange}
onChange={onChange}
renderInput={(params) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ import { useL10N } from '~/l10n/l10n-context';
import {
TABLE_COLUMN_CUSTOMIZER_HOOK_INTERFACE_KEY,
randomUtils,
createActionName,
actionsHasCapability,
{{# if container.isSelector }}
isRowSelectable,
{{ else }}
Expand Down Expand Up @@ -117,30 +119,48 @@ export function {{ componentName table }}(props: {{ componentName table }}Props)
ownerData,
editMode,
isFormUpdateable,
storeDiff,
} = props;

const { t } = useTranslation();

const hasRangeCapability = useMemo<boolean>(() => {
return actionsHasCapability(actions, '{{ table.relationName }}', 'AutocompleteRangeAction');
}, [actions]);
const hasAutocompleteAddCapability = useMemo<boolean>(() => {
return actionsHasCapability(actions, '{{ table.relationName }}', 'AutocompleteAddAction');
}, [actions]);
const hasOpenAddCapability = useMemo<boolean>(() => {
return actionsHasCapability(actions, '{{ table.relationName }}', 'OpenAddSelectorAction');
}, [actions]);
const hasCreateCapability = useMemo<boolean>(() => {
return actionsHasCapability(actions, '{{ table.relationName }}', 'OpenCreateFormAction');
}, [actions]);

return (
<div id="{{ getXMIID table }}" data-table-name="{{ table.name }}">
<Tags<{{ classDataName container.dataElement '' }}, {{ classDataName (getReferenceClassType table) 'Stored' }}>
id="{{ getXMIID table }}"
label={'KUKAC'}
label={ {{# if (elementHasLabel table) }}t('{{ getTranslationKeyForVisualElement table }}', { defaultValue: '{{ table.label }}' }){{ else }}'{{ table.relationName }}'{{/ if }} }
helperText={validationError}
error={!!validationError}
editMode={editMode}
ownerData={ownerData}
name="{{ table.relationName }}"
disabled={!isFormUpdateable()}
autoCompleteAttribute="{{ table.columns.[0].attributeType.name }}"
onAutoCompleteSearch={ async (searchText, preparedQueryCustomizer) => {
alert('lol');
return Promise.resolve([]);
} }
onValueChange={ async (values) => {
console.log(values);
} }
onItemClick={(target) => alert('A')}
onSearchDialogsClick={() => alert('B')}
onClearDialogsClick={() => alert('C')}
disabled={ {{# if table.enabledBy }}!ownerData.{{ table.enabledBy.name }} || {{/ if }}isOwnerLoading || !isFormUpdateable()}
readOnly={ {{ boolValue table.relationType.isReadOnly }} || !isFormUpdateable() }
{{# with (getFirstAutocompleteColumnForTable table) as |column| }}
autoCompleteAttribute="{{ column.attributeType.name }}"
{{/ with }}
onAutoCompleteSearch={ hasRangeCapability ? async (searchText, preparedQueryCustomizer) => {
const values = await (actions as any)[createActionName('{{ table.relationName }}', 'AutocompleteRangeAction')](preparedQueryCustomizer);
return values;
} : undefined }
onSearchDialogsClick={hasOpenAddCapability ? () => (actions as any)[createActionName('{{ table.relationName }}', 'OpenAddSelectorAction')]() : undefined}
onValueChange={async (values) => storeDiff('{{ table.relationName }}', values)}
onItemClick={actions.{{ table.relationName }}OpenPageAction ? (target) => actions.{{ table.relationName }}OpenPageAction!(target) : undefined}
onCreateDialogsClick={hasCreateCapability ? () => (actions as any)[createActionName('{{ table.relationName }}', 'OpenCreateFormAction')]() : undefined}
onClearDialogsClick={() => storeDiff('{{ table.relationName }}', [])}
identifierAttribute="__identifier"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ import type { DialogResult } from '~/utilities';
export interface {{ componentName table }}ActionDefinitions {
get{{ firstToUpper table.relationName }}Mask?: () => string;
get{{ firstToUpper table.relationName }}RowRepresentation?: (row: {{ classDataName (getReferenceClassType table) 'Stored' }}) => string;
{{# if table.autocompleteRangeActionDefinition }}
{{ simpleActionDefinitionName table.autocompleteRangeActionDefinition }}?: (queryCustomizer: {{ classDataName (getReferenceClassType table) 'QueryCustomizer' }}) => Promise<{{ classDataName (getReferenceClassType table) 'Stored' }}[]>;
{{/ if }}
{{# if table.autocompleteAddActionDefinition }}
{{ simpleActionDefinitionName table.autocompleteAddActionDefinition }}?: (values: {{ classDataName (getReferenceClassType table) 'Stored' }}[]) => Promise<void>;
{{/ if }}
{{# each table.tableActionDefinitions as |actionDefinition| }}
{{# if actionDefinition.isFilterAction }}
{{ simpleActionDefinitionName actionDefinition }}?: (id: string, filterOptions: FilterOption[], model?: GridFilterModel, filters?: Filter[]) => Promise<{ model?: GridFilterModel; filters?: Filter[] }>;
Expand Down Expand Up @@ -69,4 +75,5 @@ export interface {{ componentName table }}Props {
ownerData: {{ classDataName container.dataElement 'Stored' }};
editMode: boolean;
isFormUpdateable: () => boolean;
storeDiff: (attributeName: keyof {{ classDataName container.dataElement '' }}, value: any) => void,
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,18 @@
isOwnerLoading={isLoading}
/>
{{ else }}
{'LMAO'}
<{{ componentName child }}
uniqueId={'{{ getXMIID child }}'}
actions={actions}
dataPath={dataPath ? (dataPath + '.{{ child.dataElement.name }}') : '{{ child.dataElement.name }}'}
isOwnerLoading={isLoading}
isDraft={isDraft}
validationError={validation.get('{{ child.dataElement.name }}')}
ownerData={data}
editMode={editMode}
isFormUpdateable={isFormUpdateable}
storeDiff={storeDiff}
/>
{{/ unless }}
</Grid>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// AutocompleteAddAction: {{ getXMIID action }}
const {{ simpleActionDefinitionName action.actionDefinition }} = async (values: {{ classDataName action.actionDefinition.targetType 'Stored' }}[]) => {
{{# with (getTableParentForActionDefinition action.actionDefinition) as |table| }}
try {
{{# if table.isEager }}
storeDiff('{{ table.relationName }}', values);
{{/ if }}
} catch (error) {
handleError(error);
return Promise.reject(error);
}
{{/ with }}
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,13 @@ const {{ simpleActionDefinitionName action.actionDefinition }} = async (queryCus
return Promise.resolve([]);
}
{{/ with }}
{{# with (getTableParentForActionDefinition action.actionDefinition) as |table| }}
try {
const { data: result } = await {{ getServiceImplForPage page }}.getRange{{# if (isActionOnOperationInput action) }}On{{ firstToUpper (getOperationNameForActionOnInput action) }}{{/ if }}For{{ firstToUpper table.relationName }}(data, queryCustomizer);
return result;
} catch (error: any) {
handleError(error);
return Promise.resolve([]);
}
{{/ with }}
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { isEqual, compareAsc } from 'date-fns';
import type { Filter, FilterOption, Operation } from '../components-api';
import { FilterType } from '../components-api';
import type { Serializer } from '~/services/data-api/common/Serializer';
import { simpleCloneDeep } from './helper';
import { simpleCloneDeep, ucFirst } from './helper';

type FilterBy = {
value: any;
Expand Down Expand Up @@ -101,11 +101,6 @@ export const isFilterWithoutValue = (filter: Filter) => {
return ['isNotEmpty', 'isEmpty'].includes(getOperationEnumValue(filter, filter.filterBy.operator));
};

export const ucFirst = (str: string): string => {
if (!str) return str;
return str.charAt(0).toUpperCase() + str.slice(1);
}

export const mapFiltersToQueryCustomizerProperty = (filters: Filter[], property: string): FilterBy[] | undefined => {
if (!filters.some((filter) => filter.filterOption.attributeName === property)) return undefined;

Expand Down
38 changes: 34 additions & 4 deletions judo-ui-react/src/main/resources/actor/src/utilities/helper.ts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,42 @@ import type { RandomUtils } from './interfaces';
export const exists = (element: any) => element !== undefined && element !== null;
export const simpleCloneDeep = <T>(input: T): T => {
export const ucFirst = (str: string): string => {
if (!str) return str;
return str.charAt(0).toUpperCase() + str.slice(1);
}
export const lcFirst = (str: string): string => {
if (!str) return str;
return str.charAt(0).toLowerCase() + str.slice(1);
}
export const simpleCloneDeep = <T>(input: T, excludeKeys: string[] = []): T => {
if (input === null || input === undefined) {
return input;
} else if (Array.isArray(input)) {
return input.map(simpleCloneDeep) as T;
return input.map((v) => simpleCloneDeep(v, excludeKeys)) as T;
} else if (input instanceof Date) {
return input;
} else if (input instanceof Set) {
return new Set(Array.from(input).map(simpleCloneDeep)) as T;
return new Set(Array.from(input).map((v) => simpleCloneDeep(v, excludeKeys))) as T;
} else if (typeof input === 'object') {
let payload: Record<string, any> = {};
for (const key in input) {
payload[key] = simpleCloneDeep(input[key]);
if (!excludeKeys.includes(key)) {
payload[key] = simpleCloneDeep(input[key], excludeKeys);
}
}
return payload as T;
}
return input;
};
export const deepEquals = (a: any, b: any, excludeKeys: string[] = []) => {
// This is a pretty resource intensive function, consider using other methods for large inputs!
return JSON.stringify(simpleCloneDeep(a, excludeKeys)) === JSON.stringify(simpleCloneDeep(b, excludeKeys));
};
export const stringToBooleanSelect = (booleanString?: string | null): boolean | null => {
if (!booleanString || !booleanString.trim()) {
return null;
Expand Down Expand Up @@ -136,3 +153,16 @@ export function setValue(target: any, path: string, value: any): void {
}
}
export type reservedActionSuffixes = 'OpenCreateFormAction' | 'OpenAddSelectorAction' | 'AutocompleteAddAction' | 'AutocompleteRangeAction';
export const createActionName = (relationName: string, suffix: reservedActionSuffixes) => {
return relationName + (relationName ? ucFirst(suffix) : lcFirst(suffix));
};
export const actionsHasCapability = (actions: any, relationName: string, suffix: reservedActionSuffixes) => {
try {
return typeof actions[createActionName(relationName, suffix)] === 'function';
} catch (_) {
return false;
}
};
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<node-version>18.14.2</node-version>
<pnpm-version>8.9.2</pnpm-version>

<judo-meta-ui-version>1.1.0.20240905_151408_4d3b9bd0_feature_JNG_5914_table_tag_representation</judo-meta-ui-version>
<judo-meta-ui-version>1.1.0-SNAPSHOT</judo-meta-ui-version>
<judo-generator-commons-version>1.0.0.20240712_085217_8319ce27_develop</judo-generator-commons-version>
<judo-ui-typescript-rest-version>1.0.0.20240823_165725_58575058_feature_JNG_5888_filter_context</judo-ui-typescript-rest-version>

Expand Down

0 comments on commit 16fa6c9

Please sign in to comment.