@antscorp/antsomi-ui 1.3.5-beta.407 → 1.3.5-beta.409

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/es/components/molecules/ModalSelect/ModalSelect.js +3 -2
  2. package/es/components/molecules/ModalSelect/styled.js +4 -3
  3. package/es/components/molecules/ModalSelect/types.d.ts +1 -0
  4. package/es/components/organism/DataTable/components/Filter/FilterCondition/index.js +0 -1
  5. package/es/components/organism/DataTable/components/Filter/FilterConditionList.js +0 -1
  6. package/es/components/organism/DataTable/components/Filter/SavedFilterAndMetrics.js +1 -2
  7. package/es/components/organism/DataTable/components/Table/ResizableCell.js +2 -2
  8. package/es/components/organism/DataTable/components/Table/index.js +14 -17
  9. package/es/components/organism/DataTable/components/Table/styled.js +3 -2
  10. package/es/components/organism/DataTable/constants/common.d.ts +3 -2
  11. package/es/components/organism/DataTable/constants/common.js +3 -2
  12. package/es/components/organism/DataTable/hooks/useDataTableListing/types.d.ts +12 -1
  13. package/es/components/organism/DataTable/hooks/useDataTableListing/useDataTableListing.d.ts +19 -1
  14. package/es/components/organism/DataTable/hooks/useDataTableListing/useDataTableListing.js +57 -30
  15. package/es/components/organism/DataTable/stores/index.js +0 -1
  16. package/es/components/organism/LeftMenu/LeftMenu.js +22 -14
  17. package/es/components/organism/LeftMenu/components/CommonMenu/index.d.ts +5 -1
  18. package/es/components/organism/LeftMenu/components/CommonMenu/index.js +4 -2
  19. package/es/components/organism/LeftMenu/components/CustomMenu/index.d.ts +1 -0
  20. package/es/components/organism/LeftMenu/components/CustomMenu/index.js +3 -2
  21. package/es/components/organism/LeftMenu/components/HomeMenu/index.d.ts +4 -1
  22. package/es/components/organism/LeftMenu/components/HomeMenu/index.js +2 -38
  23. package/es/components/organism/LeftMenu/components/HomeMenu/useHomeMenu.d.ts +2 -1
  24. package/es/components/organism/LeftMenu/components/HomeMenu/useHomeMenu.js +8 -2
  25. package/es/components/organism/LeftMenu/components/common/ChildMenu/index.js +16 -11
  26. package/es/components/organism/LeftMenu/hooks/useLeftMenu.d.ts +2 -0
  27. package/es/components/organism/LeftMenu/hooks/useLeftMenu.js +44 -22
  28. package/es/components/organism/LeftMenu/hooks/useNavigatePath.js +5 -4
  29. package/es/components/organism/LeftMenu/stores/index.d.ts +2 -0
  30. package/es/components/organism/LeftMenu/stores/index.js +2 -0
  31. package/es/components/organism/LeftMenu/styled.d.ts +3 -1
  32. package/es/components/organism/LeftMenu/styled.js +10 -9
  33. package/es/providers/ConfigProvider/GlobalStyle.js +1 -0
  34. package/es/services/DataTable/index.js +2 -5
  35. package/es/tests/DataTableTest.js +16 -3
  36. package/es/utils/dataTable.d.ts +5 -0
  37. package/es/utils/dataTable.js +9 -0
  38. package/es/utils/index.d.ts +1 -0
  39. package/es/utils/index.js +1 -0
  40. package/package.json +1 -1
@@ -13,8 +13,9 @@ import React, { useCallback, useEffect, useState } from 'react';
13
13
  import { Menu } from 'antd';
14
14
  import { StyledModal } from './styled';
15
15
  import { isFunction } from 'lodash';
16
+ import clsx from 'clsx';
16
17
  export const ModalSelect = (props) => {
17
- const { value, content, options = [], okButtonProps = {}, cancelButtonProps = {}, title, open: openProp, menuRef: menuRefProp, onChange, onOk } = props, rest = __rest(props, ["value", "content", "options", "okButtonProps", "cancelButtonProps", "title", "open", "menuRef", "onChange", "onOk"]);
18
+ const { value, content, options = [], okButtonProps = {}, cancelButtonProps = {}, title, open: openProp, menuRef: menuRefProp, onChange, onOk, contentWrapperProps = {} } = props, rest = __rest(props, ["value", "content", "options", "okButtonProps", "cancelButtonProps", "title", "open", "menuRef", "onChange", "onOk", "contentWrapperProps"]);
18
19
  const [selected, setSelected] = useState(null);
19
20
  const [open, setOpen] = useState(false);
20
21
  const handleSetMenuRef = useCallback((ref) => {
@@ -51,5 +52,5 @@ export const ModalSelect = (props) => {
51
52
  };
52
53
  return (React.createElement(StyledModal, Object.assign({}, rest, { open: open, onOk: handleOk, okButtonProps: Object.assign(Object.assign({}, okButtonProps), { className: `${okButtonProps.className} ok-btn` }), cancelButtonProps: Object.assign(Object.assign({}, cancelButtonProps), { className: `${cancelButtonProps.className} cancel-btn` }), title: title || 'Select' }),
53
54
  React.createElement(Menu, { ref: handleSetMenuRef, items: options, selectedKeys: [selected || ''], onClick: info => handleClickItem(info.key) }),
54
- React.createElement("div", { className: "content" }, renderContent())));
55
+ React.createElement("div", Object.assign({}, contentWrapperProps, { className: clsx(contentWrapperProps === null || contentWrapperProps === void 0 ? void 0 : contentWrapperProps.className, 'ModalSelect-content') }), renderContent())));
55
56
  };
@@ -63,12 +63,14 @@ export const StyledModal = styled(Modal) `
63
63
  }
64
64
  }
65
65
 
66
- > .content {
67
- overflow: hidden;
66
+ > .ModalSelect-content {
68
67
  margin-left: 80px;
68
+ border-radius: 10px;
69
+ overflow: hidden;
69
70
 
70
71
  &:hover {
71
72
  overflow: auto;
73
+ scrollbar-width: none;
72
74
  }
73
75
  }
74
76
  }
@@ -143,7 +145,6 @@ export const CardRecommendedContainer = styled.div `
143
145
  line-height: 14px;
144
146
  font-size: 12px;
145
147
  padding: 5px 10px;
146
- border-radius: 24px;
147
148
 
148
149
  &.antsomi-tag-borderless {
149
150
  border-width: 0;
@@ -6,6 +6,7 @@ export type ModalSelectProps = {
6
6
  value?: string;
7
7
  options?: MenuProps['items'];
8
8
  content?: (active: string | null) => React.ReactNode;
9
+ contentWrapperProps?: React.ComponentProps<'div'>;
9
10
  onChange?: (active: string) => void;
10
11
  menuRef?: RefCallback<HTMLUListElement>;
11
12
  onOk?: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>, active: string | null) => void;
@@ -12,7 +12,6 @@ const { BETWEEN, EXISTS, NOT_EXISTS } = OPERATORS_OPTION;
12
12
  export const FilterCondition = props => {
13
13
  // Props
14
14
  const { filterMetric, filterCondition, onCancel, onApply } = props;
15
- console.log('🚀 ~ filterMetric, filterCondition:', filterMetric, filterCondition);
16
15
  // Hooks
17
16
  const [form] = Form.useForm();
18
17
  // Form
@@ -23,7 +23,6 @@ const { t } = i18nInstance;
23
23
  export const FilterConditionList = memo(() => {
24
24
  // Store
25
25
  const { filterMetrics, filters, isFilterActive, onChangeFilters = () => { }, } = useDataTableContext(store => store.filter);
26
- console.log('🚀 ~ constFilterConditionList:React.FC<FilterConditionListProps>=memo ~ filters:', filters, filterMetrics);
27
26
  const setFilter = useDataTableContext(store => store.setFilter);
28
27
  // State
29
28
  /* Reserve for handle popover open per filter condition */
@@ -81,8 +81,7 @@ export const SavedFilterAndMetrics = memo(props => {
81
81
  return new Promise((resolve, reject) => {
82
82
  if (onRemove) {
83
83
  onRemove(savedFilter)
84
- .then(response => {
85
- console.log({ response });
84
+ .then(() => {
86
85
  resolve(true);
87
86
  })
88
87
  .catch(() => reject());
@@ -29,7 +29,7 @@ export const ResizableCell = props => {
29
29
  var _a, _b;
30
30
  (_b = (_a = tableRef === null || tableRef === void 0 ? void 0 : tableRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.antsomi-table-row')) === null || _b === void 0 ? void 0 : _b.forEach(rowEl => {
31
31
  var _a;
32
- const cell = (_a = rowEl.querySelectorAll(`.antsomi-table-cell`)) === null || _a === void 0 ? void 0 : _a[1];
32
+ const cell = (_a = rowEl.querySelectorAll(`.antsomi-table-cell`)) === null || _a === void 0 ? void 0 : _a[(index !== null && index !== void 0 ? index : 0) + 1];
33
33
  if (cell) {
34
34
  cell.classList.toggle(className);
35
35
  }
@@ -37,7 +37,7 @@ export const ResizableCell = props => {
37
37
  };
38
38
  return (React.createElement(Resizable, { width: width || 0, height: 0, minConstraints: [MIN_COLUMN_WIDTH, 0], handle: React.createElement("div", { className: "resizable-handle-wrapper", onClick: e => {
39
39
  e.stopPropagation();
40
- } },
40
+ }, onMouseEnter: () => toggleCellClass(), onMouseLeave: () => toggleCellClass() },
41
41
  React.createElement("span", Object.assign({ className: "resizable-handle" }, handleProps))), onResize: (...args) => onResize && onResize(...args), draggableOpts: { enableUserSelectHack: true } },
42
42
  React.createElement("th", Object.assign({}, restProps, { style: columnStyle }),
43
43
  React.createElement(Typography.Text, { ellipsis: { tooltip: true } }, children))));
@@ -59,7 +59,7 @@ export const Table = memo(() => {
59
59
  });
60
60
  }
61
61
  }, [tableProps.columns]);
62
- return (React.createElement(StyledTable, Object.assign({}, tableProps, { ref: ref => {
62
+ return (React.createElement(StyledTable, Object.assign({}, tableProps, { virtual: true, ref: ref => {
63
63
  tableRef.current = ref === null || ref === void 0 ? void 0 : ref.nativeElement;
64
64
  }, scroll: Object.assign(Object.assign({}, scroll), { y: (scroll === null || scroll === void 0 ? void 0 : scroll.y) || '500px', x: (scroll === null || scroll === void 0 ? void 0 : scroll.x) || '100%' }), components: {
65
65
  header: Object.assign({ cell: ResizableCell }, (_a = tableProps === null || tableProps === void 0 ? void 0 : tableProps.components) === null || _a === void 0 ? void 0 : _a.header),
@@ -71,22 +71,19 @@ export const Table = memo(() => {
71
71
  });
72
72
  (_b = (_a = tableProps === null || tableProps === void 0 ? void 0 : tableProps.rowSelection) === null || _a === void 0 ? void 0 : _a.onChange) === null || _b === void 0 ? void 0 : _b.call(_a, selectedRowKeys, selectedRows, info);
73
73
  } }),
74
- }), { columns: columns === null || columns === void 0 ? void 0 : columns.map((col, index) => (Object.assign(Object.assign({}, col), { onHeaderCell: (column) => {
75
- var _a;
76
- return ({
77
- tableRef,
78
- disableResize: index === ((columns === null || columns === void 0 ? void 0 : columns.length) || 1) - 1,
79
- fixed: column.fixed,
80
- width: column.width,
81
- index,
82
- handleProps: {
83
- style: {
84
- height: (_a = tableRef === null || tableRef === void 0 ? void 0 : tableRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight,
85
- },
86
- },
87
- onResize: handleResize(index),
88
- });
89
- } }))), bordered: true, pagination: false, loading: {
74
+ }), { columns: columns === null || columns === void 0 ? void 0 : columns.map((col, index) => (Object.assign(Object.assign({}, col), { onHeaderCell: (column) => ({
75
+ tableRef,
76
+ disableResize: index === ((columns === null || columns === void 0 ? void 0 : columns.length) || 1) - 1,
77
+ fixed: column.fixed,
78
+ width: column.width,
79
+ index,
80
+ // handleProps: {
81
+ // style: {
82
+ // height: tableRef?.current?.clientHeight,
83
+ // },
84
+ // },
85
+ onResize: handleResize(index),
86
+ }) }))), bordered: true, pagination: false, loading: {
90
87
  indicator: React.createElement(Spin, null),
91
88
  spinning: !!tableProps.loading,
92
89
  }, tableLayout: "fixed" })));
@@ -19,7 +19,7 @@ export const StyledTable = styled(Table) `
19
19
  }
20
20
  }
21
21
 
22
- .antsomi-table-body {
22
+ .antsomi-table-tbody-virtual {
23
23
  .antsomi-table-row {
24
24
  .antsomi-table-cell {
25
25
  &.resizable-cell {
@@ -39,8 +39,9 @@ export const StyledTable = styled(Table) `
39
39
  .resizable-handle-wrapper {
40
40
  position: absolute;
41
41
  top: 0px;
42
- right: -10.5px;
42
+ right: -10px;
43
43
  width: 20px;
44
+ height: 100%;
44
45
  display: flex;
45
46
  justify-content: center;
46
47
  z-index: 10;
@@ -1,7 +1,8 @@
1
1
  declare const DATA_TABLE_PREFIX = "data-table";
2
2
  declare const DATA_TABLE_DEFAULT_NAME = "default";
3
3
  declare const DEFAULT_COLUMN_WIDTH = 200;
4
- declare const MIN_COLUMN_WIDTH = 100;
4
+ declare const MIN_COLUMN_WIDTH = 55;
5
5
  declare const DEFAULT_ROW_SELECTION_WIDTH = 47;
6
+ declare const DEFAULT_TOGGLE_WIDTH = 55;
6
7
  declare const DEFAULT_COLUMN_WIDTHS: number[];
7
- export { DATA_TABLE_DEFAULT_NAME, DATA_TABLE_PREFIX, DEFAULT_COLUMN_WIDTH, DEFAULT_ROW_SELECTION_WIDTH, MIN_COLUMN_WIDTH, DEFAULT_COLUMN_WIDTHS, };
8
+ export { DATA_TABLE_DEFAULT_NAME, DATA_TABLE_PREFIX, DEFAULT_COLUMN_WIDTH, DEFAULT_ROW_SELECTION_WIDTH, MIN_COLUMN_WIDTH, DEFAULT_COLUMN_WIDTHS, DEFAULT_TOGGLE_WIDTH, };
@@ -1,8 +1,9 @@
1
1
  const DATA_TABLE_PREFIX = 'data-table';
2
2
  const DATA_TABLE_DEFAULT_NAME = 'default';
3
3
  const DEFAULT_COLUMN_WIDTH = 200;
4
- const MIN_COLUMN_WIDTH = 100;
4
+ const MIN_COLUMN_WIDTH = 55;
5
5
  const DEFAULT_FIRST_COLUMN_WIDTH = 200;
6
6
  const DEFAULT_ROW_SELECTION_WIDTH = 47;
7
+ const DEFAULT_TOGGLE_WIDTH = 55;
7
8
  const DEFAULT_COLUMN_WIDTHS = [DEFAULT_FIRST_COLUMN_WIDTH].concat(Array.from({ length: 20 }, () => DEFAULT_COLUMN_WIDTH));
8
- export { DATA_TABLE_DEFAULT_NAME, DATA_TABLE_PREFIX, DEFAULT_COLUMN_WIDTH, DEFAULT_ROW_SELECTION_WIDTH, MIN_COLUMN_WIDTH, DEFAULT_COLUMN_WIDTHS, };
9
+ export { DATA_TABLE_DEFAULT_NAME, DATA_TABLE_PREFIX, DEFAULT_COLUMN_WIDTH, DEFAULT_ROW_SELECTION_WIDTH, MIN_COLUMN_WIDTH, DEFAULT_COLUMN_WIDTHS, DEFAULT_TOGGLE_WIDTH, };
@@ -3,6 +3,7 @@ import { TEnv } from '@antscorp/antsomi-ui/es/types/config';
3
3
  import { AxiosRequestConfig } from 'axios';
4
4
  import { FilterItem, TableProps } from '../../types';
5
5
  import { PaginationProps } from '../../components';
6
+ import { ColumnType } from 'antd/es/table';
6
7
  export type TApiGlobal = AxiosRequestConfig<any> & {
7
8
  enabled?: boolean;
8
9
  };
@@ -19,11 +20,20 @@ export type TConfig = {
19
20
  objectId: number;
20
21
  };
21
22
  };
23
+ type TToggleColumnType<TTableType> = ColumnType<TTableType> & {
24
+ value?: ((record: TTableType) => boolean) | boolean;
25
+ valueKey?: keyof TTableType;
26
+ onChange?: (checked: boolean, record: TTableType) => void;
27
+ };
28
+ type TTableColumnType<TTableType, K extends keyof TTableType | 'toggle'> = K extends 'toggle' ? TToggleColumnType<TTableType> : ColumnType<TTableType>;
22
29
  export interface UseDataTableListingProps<TTableType = any> {
23
30
  config: TConfig;
24
31
  name?: string;
25
- table?: TableProps<TTableType> & {
32
+ table?: Omit<TableProps<TTableType>, 'columns'> & {
26
33
  mainColumnKey: keyof TTableType;
34
+ columns?: {
35
+ [K in keyof TTableType | 'toggle']?: TTableColumnType<TTableType, K>;
36
+ };
27
37
  };
28
38
  }
29
39
  export interface DataTableLocalStorage {
@@ -33,3 +43,4 @@ export interface DataTableLocalStorage {
33
43
  };
34
44
  pagination?: PaginationProps;
35
45
  }
46
+ export {};
@@ -1,11 +1,29 @@
1
+ import React from 'react';
2
+ import { useGetColumnMetrics, useGetFilterMetricList, useGetModifyColumnList, useGetSavedFilterList, useGetTableListing } from '@antscorp/antsomi-ui/es/queries';
1
3
  import { UseDataTableListingProps } from './types';
2
- import { FilterProps, TColumnActionButton, TableProps } from '../../types';
4
+ import { FilterItem, FilterProps, TColumnActionButton, TableProps } from '../../types';
3
5
  import { PaginationProps } from '../../components';
4
6
  interface TUseDataTableListing<TTableType = any> {
5
7
  modifyColumn: TColumnActionButton;
6
8
  filter: FilterProps;
7
9
  pagination: PaginationProps;
8
10
  table: TableProps<TTableType>;
11
+ selectedRowKeys: React.Key[];
12
+ queries: {
13
+ getTableListing: ReturnType<typeof useGetTableListing>;
14
+ getModifyColumnList: ReturnType<typeof useGetModifyColumnList>;
15
+ getSavedFilterList: ReturnType<typeof useGetSavedFilterList>;
16
+ getColumnMetrics: ReturnType<typeof useGetColumnMetrics>;
17
+ getFilterMetricList: ReturnType<typeof useGetFilterMetricList>;
18
+ };
19
+ setDatTableListingState: React.Dispatch<React.SetStateAction<TState<TTableType>>>;
9
20
  }
21
+ type TState<TTableType = any> = {
22
+ filters?: FilterItem[];
23
+ selectedFilterId?: string | number;
24
+ pagination: PaginationProps;
25
+ table: TableProps<TTableType>;
26
+ selectedRowKeys: React.Key[];
27
+ };
10
28
  export declare function useDataTableListing<TTableType = Record<string, any>>(props: UseDataTableListingProps<TTableType>): TUseDataTableListing<TTableType>;
11
29
  export {};
@@ -24,7 +24,7 @@ import { isEmpty } from 'lodash';
24
24
  // Types
25
25
  import { useAppConfigContext } from '@antscorp/antsomi-ui/es/providers';
26
26
  // Components
27
- import { Typography } from '@antscorp/antsomi-ui/es/components/atoms';
27
+ import { Typography, Switch, Flex } from '@antscorp/antsomi-ui/es/components/atoms';
28
28
  // Constants
29
29
  import { COLUMN_DOMAIN } from '@antscorp/antsomi-ui/es/constants';
30
30
  import { MODIFY_COLUMN_DISABLE_EDITABLE, MODIFY_COLUMN_DISABLE_REMOVE, SAVED_FILTER_DEFAULT, TABLE_LISTING_PREFIX, } from './constants';
@@ -35,6 +35,7 @@ import { useCreateModifyColumn, useDeleteModifyColumn, useDeleteSavedFilter, use
35
35
  import { flatTree, safeParseJson } from '@antscorp/antsomi-ui/es/utils';
36
36
  import { METRIC_MAP_NUMBER_TYPE } from '../../constants/filter';
37
37
  import { mapFiltersToApiFilters, mapFiltersToRules, mapRulesToFilters } from '../../utils';
38
+ import { DEFAULT_TOGGLE_WIDTH } from '../../constants';
38
39
  const { Text } = Typography;
39
40
  const initialState = {
40
41
  filters: [],
@@ -47,6 +48,7 @@ const initialState = {
47
48
  table: {
48
49
  loading: false,
49
50
  },
51
+ selectedRowKeys: [],
50
52
  };
51
53
  export function useDataTableListing(props) {
52
54
  // Props
@@ -61,7 +63,7 @@ export function useDataTableListing(props) {
61
63
  const _a = apiColumn || {}, { url: columnUrl = `${COLUMN_DOMAIN[env || 'development']}/api/column`, enabled: enabledApiColumn = true } = _a, restOfApiColumnRequest = __rest(_a, ["url", "enabled"]);
62
64
  const _b = apiFilter || {}, { url: filterUrl = `${COLUMN_DOMAIN[env || 'development']}/api/filter`, enabled: enabledApiFilter = true } = _b, restOfApiFilterRequest = __rest(_b, ["url", "enabled"]);
63
65
  const _c = apiListing || {}, { url: listingUrl = '', enabled: enabledApiListing = true } = _c, restOfApiListingRequest = __rest(_c, ["url", "enabled"]);
64
- const { filters, selectedFilterId, pagination } = state;
66
+ const { filters, selectedFilterId, pagination, selectedRowKeys } = state;
65
67
  const modifyColumnAuth = Object.assign(Object.assign({}, auth), { url: columnUrl });
66
68
  const filterAuth = Object.assign(Object.assign({}, auth), { url: filterUrl });
67
69
  const listingAuth = Object.assign(Object.assign({}, auth), { url: listingUrl });
@@ -77,7 +79,7 @@ export function useDataTableListing(props) {
77
79
  return jsonValues;
78
80
  }, [localStorageKey]);
79
81
  // Queries
80
- const { data: columnMetricsData } = useGetColumnMetrics({
82
+ const getColumnMetrics = useGetColumnMetrics({
81
83
  args: {
82
84
  auth: modifyColumnAuth,
83
85
  params: mapObject,
@@ -87,7 +89,7 @@ export function useDataTableListing(props) {
87
89
  enabled: enabledApiColumn,
88
90
  },
89
91
  });
90
- const { data: modifyColumnsData, isLoading: isModifyColumnsLoading } = useGetModifyColumnList({
92
+ const getModifyColumnList = useGetModifyColumnList({
91
93
  args: {
92
94
  auth: modifyColumnAuth,
93
95
  params: mapObject,
@@ -97,7 +99,7 @@ export function useDataTableListing(props) {
97
99
  enabled: enabledApiColumn,
98
100
  },
99
101
  });
100
- const { data: savedFiltersData } = useGetSavedFilterList({
102
+ const getSavedFilterList = useGetSavedFilterList({
101
103
  args: {
102
104
  auth: filterAuth,
103
105
  params: mapObject,
@@ -107,7 +109,7 @@ export function useDataTableListing(props) {
107
109
  enabled: enabledApiFilter,
108
110
  },
109
111
  });
110
- const { data: filterMetricsData } = useGetFilterMetricList({
112
+ const getFilterMetricList = useGetFilterMetricList({
111
113
  args: {
112
114
  auth: filterAuth,
113
115
  params: mapObject,
@@ -117,7 +119,7 @@ export function useDataTableListing(props) {
117
119
  enabled: enabledApiFilter,
118
120
  },
119
121
  });
120
- const { data: tableListing, isLoading: isTableListingLoading, isRefetching: isTableListingRefetching, refetch: refetchTableListing, } = useGetTableListing({
122
+ const getTableListing = useGetTableListing({
121
123
  args: {
122
124
  auth: listingAuth,
123
125
  params: {
@@ -132,6 +134,11 @@ export function useDataTableListing(props) {
132
134
  },
133
135
  });
134
136
  // Variables
137
+ const { data: columnMetricsData } = getColumnMetrics || {};
138
+ const { data: modifyColumnsData, isLoading: isModifyColumnsLoading } = getModifyColumnList || {};
139
+ const { data: savedFiltersData } = getSavedFilterList || {};
140
+ const { data: filterMetricsData } = getFilterMetricList || {};
141
+ const { data: tableListing, isLoading: isTableListingLoading, isRefetching: isTableListingRefetching, refetch: refetchTableListing, } = getTableListing || {};
135
142
  const { body: tableBody, header: tableHeader, total } = tableListing || {};
136
143
  // Mutations
137
144
  const { mutateAsync: updateModifyColumn } = useUpdateModifyColumn({
@@ -198,30 +205,34 @@ export function useDataTableListing(props) {
198
205
  name: filterName,
199
206
  removable: true,
200
207
  }))) || []), [savedFiltersData]);
201
- const tableColumns = useDeepCompareMemo(() => {
208
+ const tableColumns = useMemo(() => {
202
209
  let data = [];
203
- data =
204
- (tableHeader === null || tableHeader === void 0 ? void 0 : tableHeader.map(headerCol => {
205
- const { name, label, fixColumn } = headerCol;
206
- return {
207
- key: name,
208
- dataIndex: name,
209
- title: label,
210
- fixed: fixColumn ? 'left' : undefined,
211
- render(value, record, index) {
212
- return React.createElement(Text, { ellipsis: { tooltip: true } }, value);
213
- },
214
- // render(value, record, index) {
215
- // return (
216
- // <Text ellipsis={{ tooltip: true }} style={{ width: 'fit-content' }}>
217
- // {value}
218
- // </Text>
219
- // );
220
- // },
221
- };
222
- })) || [];
210
+ const { columns } = tableProps || {};
211
+ // Check if has column toggle then add toggle column
212
+ if (columns === null || columns === void 0 ? void 0 : columns.toggle) {
213
+ const { key, dataIndex, valueKey, title, value, onChange } = columns.toggle || {};
214
+ data.push(Object.assign({ key: 'toggle' || key, fixed: 'left', align: 'center', dataIndex: 'toggle' || dataIndex, title: 'Toggle' || title, render: (_, record) => {
215
+ const checked = value
216
+ ? typeof value === 'function'
217
+ ? value(record)
218
+ : value
219
+ : !!record[valueKey];
220
+ return (React.createElement(Flex, { align: "center", justify: "center" },
221
+ React.createElement(Switch, { checked: checked, onChange: checked => {
222
+ if (onChange) {
223
+ onChange(checked, record);
224
+ }
225
+ } })));
226
+ }, width: DEFAULT_TOGGLE_WIDTH }, columns.toggle));
227
+ }
228
+ data = data.concat((tableHeader === null || tableHeader === void 0 ? void 0 : tableHeader.map(headerCol => {
229
+ const { name, label, fixColumn } = headerCol;
230
+ return Object.assign({ key: name, dataIndex: name, title: label, fixed: fixColumn ? 'left' : undefined, render(value) {
231
+ return (React.createElement(Text, { ellipsis: { tooltip: true } }, typeof value !== 'object' ? value : null));
232
+ } }, columns === null || columns === void 0 ? void 0 : columns[name]);
233
+ })) || []);
223
234
  return data;
224
- }, [tableHeader]);
235
+ }, [tableHeader, tableProps]);
225
236
  const tableData = useDeepCompareMemo(() => (tableBody === null || tableBody === void 0 ? void 0 : tableBody.map((row) => (Object.assign(Object.assign({}, row), { key: row === null || row === void 0 ? void 0 : row[tableProps === null || tableProps === void 0 ? void 0 : tableProps.mainColumnKey] })))) || [], [tableBody]);
226
237
  // Effects
227
238
  /**
@@ -414,7 +425,23 @@ export function useDataTableListing(props) {
414
425
  loading: isTableListingLoading || isTableListingRefetching,
415
426
  columns: tableColumns,
416
427
  dataSource: tableData,
417
- rowSelection: {},
428
+ rowSelection: {
429
+ selectedRowKeys,
430
+ onChange(selectedRowKeys) {
431
+ setState(prev => (Object.assign(Object.assign({}, prev), { selectedRowKeys })));
432
+ },
433
+ },
434
+ },
435
+ selectedRowKeys,
436
+ /* Queries */
437
+ queries: {
438
+ getTableListing,
439
+ getModifyColumnList,
440
+ getSavedFilterList,
441
+ getColumnMetrics,
442
+ getFilterMetricList,
418
443
  },
444
+ // Handles
445
+ setDatTableListingState: setState,
419
446
  };
420
447
  }
@@ -8,6 +8,5 @@ export const createDataTableStore = (initProps) => createStore()(set => (Object.
8
8
  setState: newState => set(store => merge(cloneDeep(store), cloneDeep(newState))), setFilter: filter => {
9
9
  set(store => (Object.assign(Object.assign({}, store), { filter: Object.assign(Object.assign({}, store.filter), filter) })));
10
10
  }, setModifyColumn: modifyColumn => set(store => (Object.assign(Object.assign({}, store), { modifyColumn: Object.assign(Object.assign({}, store.modifyColumn), modifyColumn) }))), setTable: table => set(store => (Object.assign(Object.assign({}, store), { table: Object.assign(Object.assign({}, store.table), table) }))), setToolbar: toolbar => set(store => (Object.assign(Object.assign({}, store), { toolbar: Object.assign(Object.assign({}, store.toolbar), toolbar) }))), setPagination: pagination => {
11
- console.log('🚀 ~ pagination:', pagination);
12
11
  set(store => (Object.assign(Object.assign({}, store), { pagination: Object.assign(Object.assign({}, store.pagination), pagination) })));
13
12
  } })));
@@ -5,6 +5,7 @@ import { Typography } from 'antd';
5
5
  import classNames from 'classnames';
6
6
  import { isNil, isString } from 'lodash';
7
7
  import { Link } from 'react-router-dom';
8
+ import isEqual from 'react-fast-compare';
8
9
  // Styled
9
10
  import { ChildMenuWrapper, ExpandWrapper, FeatureMenu, FeatureMenuItem, LeftMenuNav, LeftMenuNavWrapper, PopoverWrapper, NavLogoWrapper, FeatureMenuWrapper, IconWrapper, } from './styled';
10
11
  // Constants
@@ -17,14 +18,10 @@ const SubLogoAntsomi = 'https://st-media-template.antsomi.com/icons/antsomi/ants
17
18
  export const LeftMenuComponent = memo(props => {
18
19
  const { style, className, customization, showLogo = true } = props;
19
20
  const { isExpandable = true, isCustomized, isRecommendation, items = [], onMenuItemClick, } = customization || {};
20
- const { state, activeAppCode, permissionMenu, customActiveAppKey, onToggleChildMenu, onMouseEnter, onMouseLeave, onHoverMenuBar, } = useLeftMenu(props);
21
+ const { state, activeAppCode, permissionMenu, customActiveAppKey, onToggleChildMenu, onMouseEnter, onMouseLeave, onHoverMenuBar, onShowPopover, } = useLeftMenu(props);
21
22
  const { isPushDifferentDomain, getPath, navigatePath } = useNavigatePath();
22
- const childMenu = useMemo(() => {
23
- const appActiveKey = state.hoverItem
24
- ? state.hoverItem
25
- : isCustomized || isRecommendation
26
- ? customActiveAppKey
27
- : activeAppCode;
23
+ const childActiveMenu = useMemo(() => {
24
+ const appActiveKey = isCustomized || isRecommendation ? customActiveAppKey : activeAppCode;
28
25
  if (isCustomized)
29
26
  return React.createElement(CustomMenu, null);
30
27
  switch (appActiveKey) {
@@ -33,7 +30,18 @@ export const LeftMenuComponent = memo(props => {
33
30
  default:
34
31
  return React.createElement(CommonMenu, null);
35
32
  }
36
- }, [activeAppCode, customActiveAppKey, isCustomized, isRecommendation, state.hoverItem]);
33
+ }, [activeAppCode, customActiveAppKey, isCustomized, isRecommendation]);
34
+ const childHoverMenu = useMemo(() => {
35
+ const appActiveKey = state.hoverItem;
36
+ if (isCustomized)
37
+ return React.createElement(CustomMenu, { isHover: true });
38
+ switch (appActiveKey) {
39
+ case isRecommendation ? 'DASHBOARD' : APP_KEYS.HOME:
40
+ return React.createElement(HomeMenu, { isHover: true });
41
+ default:
42
+ return React.createElement(CommonMenu, { isHover: true });
43
+ }
44
+ }, [isCustomized, isRecommendation, state.hoverItem]);
37
45
  const renderFeatureMenuItem = useCallback((item) => {
38
46
  const { menu_item_name, menu_item, icon_name, menu_item_code, menu_item_path, menu_item_domain, } = item;
39
47
  const isActive = activeAppCode === menu_item_code;
@@ -90,15 +98,15 @@ export const LeftMenuComponent = memo(props => {
90
98
  };
91
99
  return (React.createElement(LeftMenuNavWrapper, { style: style, "$isExpandMenu": state.isExpandMenu, className: className },
92
100
  React.createElement(LeftMenuNav, { className: "left-menu-nav" },
93
- React.createElement(FeatureMenuWrapper, { vertical: true },
101
+ React.createElement(FeatureMenuWrapper, { vertical: true, onMouseEnter: () => onShowPopover(), onMouseLeave: onMouseLeave },
94
102
  showLogo && (React.createElement(NavLogoWrapper, { align: "center", justify: "center", onMouseEnter: onHoverMenuBar },
95
103
  React.createElement("div", { className: "image-wrapper" },
96
104
  React.createElement("img", { src: SubLogoAntsomi, alt: "Antsomi sub logo" })))),
97
- React.createElement(FeatureMenu, { role: "menu", className: "antsomi-scroll-box", onMouseLeave: onMouseLeave },
105
+ React.createElement(FeatureMenu, { role: "menu", className: "antsomi-scroll-box" },
98
106
  React.createElement("div", { className: "menu-content scroll-content" }, renderAppMenuItems()),
99
107
  React.createElement("div", { className: "nav-blank", onMouseEnter: onHoverMenuBar }),
100
- React.createElement(PopoverWrapper, { className: "antsomi-scroll-box antsomi-child-menu-popover", onMouseLeave: onMouseLeave },
101
- React.createElement("div", { className: "scroll-content", style: { width: '200px', maxHeight: '100%' } }, childMenu))),
108
+ React.createElement(PopoverWrapper, { show: state.isShowPopover && isExpandable, className: "antsomi-scroll-box antsomi-child-menu-popover" },
109
+ React.createElement("div", { className: "scroll-content", style: { width: '200px', maxHeight: '100%' } }, childHoverMenu))),
102
110
  React.createElement("div", { style: { flexShrink: 0 } }, renderSettings())),
103
111
  isExpandable && !isRecommendation && (React.createElement(ExpandWrapper, { onMouseEnter: onMouseLeave },
104
112
  React.createElement(Icon, { type: "icon-ants-expand-more", style: {
@@ -107,5 +115,5 @@ export const LeftMenuComponent = memo(props => {
107
115
  transform: `rotate(${state.isExpandMenu ? '90deg' : '270deg'})`,
108
116
  }, onClick: onToggleChildMenu })))),
109
117
  React.createElement(ChildMenuWrapper, { isExpand: state.isExpandMenu && isExpandable, isMarginTop: showLogo, className: "antsomi-scroll-box" },
110
- React.createElement("div", { className: "scroll-content", style: { width: '200px', maxHeight: '100%' } }, childMenu))));
111
- });
118
+ React.createElement("div", { className: "scroll-content", style: { width: '200px', maxHeight: '100%' } }, childActiveMenu))));
119
+ }, (prevProps, nextProps) => isEqual(prevProps, nextProps));
@@ -1,2 +1,6 @@
1
1
  import React from 'react';
2
- export declare const CommonMenu: React.FC;
2
+ interface CommonMenuProps {
3
+ isHover?: boolean;
4
+ }
5
+ export declare const CommonMenu: React.FC<CommonMenuProps>;
6
+ export {};
@@ -6,9 +6,11 @@ import { ChildMenu } from '../common';
6
6
  import { useLeftMenuContext } from '../../contexts';
7
7
  // Utils
8
8
  import { getMenuItem } from '../../utils';
9
- export const CommonMenu = memo(() => {
9
+ export const CommonMenu = memo(({ isHover }) => {
10
10
  const appMenuChildren = useLeftMenuContext(store => store.appMenuChildren);
11
+ const appHoverMenuChildren = useLeftMenuContext(store => store.appHoverMenuChildren);
11
12
  const onMenuClick = useLeftMenuContext(store => store.onMenuClick);
12
13
  const customChildren = useMemo(() => appMenuChildren === null || appMenuChildren === void 0 ? void 0 : appMenuChildren.map(item => getMenuItem(item)), [appMenuChildren]);
13
- return React.createElement(ChildMenu, { items: customChildren, onMenuClick: onMenuClick });
14
+ const customHoverChildren = useMemo(() => appHoverMenuChildren === null || appHoverMenuChildren === void 0 ? void 0 : appHoverMenuChildren.map(item => getMenuItem(item)), [appHoverMenuChildren]);
15
+ return (React.createElement(ChildMenu, { items: isHover ? customHoverChildren : customChildren, onMenuClick: onMenuClick }));
14
16
  });
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  interface CustomMenuProps {
3
+ isHover?: boolean;
3
4
  }
4
5
  export declare const CustomMenu: React.FC<CustomMenuProps>;
5
6
  export {};
@@ -4,8 +4,9 @@ import React, { memo } from 'react';
4
4
  import { ChildMenu } from '../common';
5
5
  // Hooks
6
6
  import { useLeftMenuContext } from '../../contexts';
7
- export const CustomMenu = memo(() => {
7
+ export const CustomMenu = memo(({ isHover }) => {
8
8
  const appCustomMenuChildren = useLeftMenuContext(store => store.customMenuChildren);
9
+ const appCustomHoverMenuChildren = useLeftMenuContext(store => store.customHoverMenuChildren);
9
10
  const onMenuClick = useLeftMenuContext(store => store.onMenuClick);
10
- return React.createElement(ChildMenu, { items: appCustomMenuChildren, onMenuClick: onMenuClick });
11
+ return (React.createElement(ChildMenu, { items: isHover ? appCustomHoverMenuChildren : appCustomMenuChildren, onMenuClick: onMenuClick }));
11
12
  });
@@ -1,2 +1,5 @@
1
1
  import React from 'react';
2
- export declare const HomeMenu: React.FC;
2
+ export interface HomeMenuProps {
3
+ isHover?: boolean;
4
+ }
5
+ export declare const HomeMenu: React.FC<HomeMenuProps>;
@@ -9,44 +9,8 @@ import Icon from '@antscorp/icons';
9
9
  import { CreateButton, HomeMenuWrapper, ModalWrapper } from './styled';
10
10
  // Hooks
11
11
  import { useHomeMenu } from './useHomeMenu';
12
- // const MAP_TITLE = {
13
- // REMOVE_ACCESS: {
14
- // HEADING: getTranslateMessage(TRANSLATE_KEY._TITL_REMOV_ACCESS_TAB, 'Remove access to this tab'),
15
- // BODY: getTranslateMessage(
16
- // TRANSLATE_KEY.REMOV_ACCESS_TAB,
17
- // 'This action will remove your access to this tab. You will not see it anymore. Are you sure you want to continue?',
18
- // ),
19
- // HEADING_DASHBOARD: getTranslateMessage(
20
- // TRANSLATE_KEY._TITL_REMOV_ACCESS_DB,
21
- // 'Remove access to this dashboard',
22
- // ),
23
- // BODY_DASHBOARD: getTranslateMessage(
24
- // TRANSLATE_KEY.REMOV_ACCESS_DB,
25
- // 'This action will remove your access to selected dashboard. You will not see it anymore. Are you sure you want to continue?',
26
- // ),
27
- // },
28
- // DELETE_TAB: {
29
- // HEADING: getTranslateMessage(TRANSLATE_KEY._TITL_DELETE_TAB, 'Remove this tab'),
30
- // BODY: getTranslateMessage(
31
- // TRANSLATE_KEY.DELETE_TAB_MESS,
32
- // 'Removing this tab will delete it permanently. Are you sure you want to perform this action?',
33
- // ),
34
- // HEADING_DASHBOARD: getTranslateMessage(TRANSLATE_KEY._TITL_DELETE_DB, 'Remove this dashboard'),
35
- // BODY_DASHBOARD: getTranslateMessage(
36
- // TRANSLATE_KEY.DELETE_DB_MESS,
37
- // 'Removing this dashboard will delete it permanently. Are you sure you want to perform this action?',
38
- // ),
39
- // },
40
- // 'my-report-template': {
41
- // HEADING: getTranslateMessage(TRANSLATE_KEY._TITL_SHARE_RP, 'Share Report'),
42
- // BODY: getTranslateMessage(
43
- // TRANSLATE_KEY._SHARE_RP_MESS,
44
- // 'Sharing this tab with Public access will make your report public for everyone on the portal.',
45
- // ),
46
- // },
47
- // };
48
- export const HomeMenu = memo(() => {
49
- const { children, removedDashboardId, isDashboardRemoving, isRecommendation, setRemovedDashboardId, onCreateNewReport, onMenuClick, onRemoveDashboard, } = useHomeMenu();
12
+ export const HomeMenu = memo(props => {
13
+ const { children, removedDashboardId, isDashboardRemoving, isRecommendation, setRemovedDashboardId, onCreateNewReport, onMenuClick, onRemoveDashboard, } = useHomeMenu(props);
50
14
  return (React.createElement(React.Fragment, null,
51
15
  React.createElement(HomeMenuWrapper, { gap: 10, vertical: true },
52
16
  !isRecommendation && (React.createElement(CreateButton, { type: "primary", onClick: onCreateNewReport },
@@ -1,5 +1,6 @@
1
1
  /// <reference types="react" />
2
- export declare const useHomeMenu: () => {
2
+ import { HomeMenuProps } from '.';
3
+ export declare const useHomeMenu: (props: HomeMenuProps) => {
3
4
  children: import("../../types").TMenuItem[];
4
5
  removedDashboardId: string;
5
6
  isDashboardRemoving: boolean;
@@ -21,10 +21,12 @@ import { useLayoutStore } from '@antscorp/antsomi-ui/es/components/template';
21
21
  import { useCustomRouter } from '@antscorp/antsomi-ui/es/hooks';
22
22
  // Queries
23
23
  import { useRemoveDashboard } from '@antscorp/antsomi-ui/es/queries/LeftMenu';
24
- export const useHomeMenu = () => {
24
+ export const useHomeMenu = (props) => {
25
+ const { isHover } = props;
25
26
  const { pathname, search } = window.location;
26
27
  const { navigate, replace } = useCustomRouter();
27
28
  const appMenuChildren = useLeftMenuContext(store => store.appMenuChildren);
29
+ const appHoverMenuChildren = useLeftMenuContext(store => store.appHoverMenuChildren);
28
30
  const isRecommendation = useLeftMenuContext(store => store.isRecommendation);
29
31
  const auth = useLeftMenuContext(store => { var _a; return (_a = store.appConfig) === null || _a === void 0 ? void 0 : _a.auth; });
30
32
  const env = useLeftMenuContext(store => { var _a; return (_a = store.appConfig) === null || _a === void 0 ? void 0 : _a.env; });
@@ -55,6 +57,10 @@ export const useHomeMenu = () => {
55
57
  var _a;
56
58
  return getMenuItem(Object.assign(Object.assign({}, appMenuItem), { children: (_a = appMenuItem === null || appMenuItem === void 0 ? void 0 : appMenuItem.children) === null || _a === void 0 ? void 0 : _a.map(item => (Object.assign(Object.assign({}, item), { options: Object.values(CONFIG_OPTIONS), optionCallback: onOptionCallback }))) }));
57
59
  }), [appMenuChildren, onOptionCallback]);
60
+ const customHoverChildren = useMemo(() => appHoverMenuChildren === null || appHoverMenuChildren === void 0 ? void 0 : appHoverMenuChildren.map(appMenuItem => {
61
+ var _a;
62
+ return getMenuItem(Object.assign(Object.assign({}, appMenuItem), { children: (_a = appMenuItem === null || appMenuItem === void 0 ? void 0 : appMenuItem.children) === null || _a === void 0 ? void 0 : _a.map(item => (Object.assign(Object.assign({}, item), { options: Object.values(CONFIG_OPTIONS), optionCallback: onOptionCallback }))) }));
63
+ }), [appHoverMenuChildren, onOptionCallback]);
58
64
  const onCreateNewReport = useCallback(e => {
59
65
  if (onClickCreateDashboard) {
60
66
  onClickCreateDashboard(e);
@@ -110,7 +116,7 @@ export const useHomeMenu = () => {
110
116
  navigate,
111
117
  ]);
112
118
  return {
113
- children: customChildren,
119
+ children: isHover ? customHoverChildren : customChildren,
114
120
  removedDashboardId,
115
121
  isDashboardRemoving,
116
122
  isRecommendation,
@@ -1,9 +1,10 @@
1
1
  // Libraries
2
- import React, { memo, useLayoutEffect, useState } from 'react';
2
+ import React, { memo, useLayoutEffect, useMemo, useState } from 'react';
3
3
  import Icon from '@antscorp/icons';
4
4
  import { isEmpty, isNil, uniq } from 'lodash';
5
5
  import classNames from 'classnames';
6
6
  import { Link } from 'react-router-dom';
7
+ import { Cookies } from 'react-cookie';
7
8
  // Components
8
9
  import { Dropdown, Menu } from 'antd';
9
10
  import { MenuItemImage } from './components';
@@ -18,10 +19,10 @@ import { findActiveAppCodeByUrl, findLastMatchedItemByUrl, getMenuItem } from '.
18
19
  import { findItemByPermissionCode, recursiveFindItemByKey, recursiveFindParentOfActiveItem, } from './utils';
19
20
  // Hooks
20
21
  import { useNavigatePath } from '../../../hooks';
22
+ import { useDeepCompareEffect } from '@antscorp/antsomi-ui/es/hooks';
21
23
  // Contexts
22
24
  import { useLeftMenuContext } from '../../../contexts';
23
25
  import { MARKETING_CHANNEL_CODE } from '@antscorp/antsomi-ui/es/components/template/Layout/constants';
24
- import { useDeepCompareEffect } from '@antscorp/antsomi-ui/es/hooks';
25
26
  const noDashboardItem = {
26
27
  key: 'no_dashboard',
27
28
  label: 'No dashboard available',
@@ -38,8 +39,9 @@ const styles = {
38
39
  menuItemTitle: { flex: '1 1 0%', maxWidth: '100%', overflow: 'hidden' },
39
40
  };
40
41
  export const ChildMenu = memo(props => {
41
- var _a;
42
+ var _a, _b;
42
43
  const { items = [], onMenuClick } = props;
44
+ const cookies = useMemo(() => new Cookies(), []);
43
45
  const auth = useLeftMenuContext(store => { var _a; return (_a = store.appConfig) === null || _a === void 0 ? void 0 : _a.auth; });
44
46
  const env = useLeftMenuContext(store => { var _a; return (_a = store.appConfig) === null || _a === void 0 ? void 0 : _a.env; });
45
47
  const activeAppCode = useLeftMenuContext(store => store.activeAppCode);
@@ -47,17 +49,20 @@ export const ChildMenu = memo(props => {
47
49
  const customItems = useLeftMenuContext(store => store.customItems);
48
50
  const isCustomized = useLeftMenuContext(store => store.isCustomized);
49
51
  const isRecommendation = useLeftMenuContext(store => store.isRecommendation);
52
+ const customActiveAppKey = useLeftMenuContext(store => store.customActiveAppKey);
50
53
  const customActiveCurrentKey = useLeftMenuContext(store => store.customActiveCurrentKey);
51
54
  const setLeftMenuState = useLeftMenuContext(store => store.setState);
52
- const layout = JSON.parse(localStorage.getItem('layout') || '{}');
53
- const openMenuKeys = ((_a = layout === null || layout === void 0 ? void 0 : layout.leftMenu) === null || _a === void 0 ? void 0 : _a.openMenuKeys) || [];
55
+ const activeApp = useMemo(() => (isCustomized ? customActiveAppKey : activeAppCode), [activeAppCode, customActiveAppKey, isCustomized]);
56
+ const leftMenuCookies = cookies.get('_leftmenu_state');
57
+ const openMenuKeys = ((_b = (_a = cookies.get('_leftmenu_state')) === null || _a === void 0 ? void 0 : _a.openMenuKeys) === null || _b === void 0 ? void 0 : _b[activeApp]) || [];
54
58
  const [currentActiveItem, setCurrentActiveItem] = useState('');
55
59
  const [openKeys, setOpenKeys] = useState(openMenuKeys);
56
60
  const { pathname, hash } = window.location;
57
61
  const { isPushDifferentDomain, getPath, navigatePath } = useNavigatePath();
58
62
  useLayoutEffect(() => {
59
- localStorage.setItem('layout', JSON.stringify(Object.assign(Object.assign({}, layout), { leftMenu: Object.assign(Object.assign({}, layout === null || layout === void 0 ? void 0 : layout.leftMenu), { openMenuKeys: uniq(openKeys) }) })));
60
- }, [layout, openKeys]);
63
+ if (activeApp)
64
+ cookies.set('_leftmenu_state', Object.assign(Object.assign({}, leftMenuCookies), { openMenuKeys: Object.assign(Object.assign({}, leftMenuCookies === null || leftMenuCookies === void 0 ? void 0 : leftMenuCookies.openMenuKeys), { [activeApp]: uniq(openKeys === null || openKeys === void 0 ? void 0 : openKeys.filter(item => item !== activeApp)) }) }));
65
+ }, [activeApp, cookies, leftMenuCookies, openKeys]);
61
66
  useDeepCompareEffect(() => {
62
67
  var _a;
63
68
  switch (true) {
@@ -69,7 +74,7 @@ export const ChildMenu = memo(props => {
69
74
  menuItems: customItems,
70
75
  });
71
76
  if (parentKey) {
72
- setOpenKeys(prev => [...prev, parentKey]);
77
+ setOpenKeys(prev => uniq([...prev, parentKey]));
73
78
  }
74
79
  break;
75
80
  }
@@ -129,7 +134,7 @@ export const ChildMenu = memo(props => {
129
134
  menuItems: menuItems === null || menuItems === void 0 ? void 0 : menuItems.map(item => (Object.assign(Object.assign({}, getMenuItem(item)), { key: (item === null || item === void 0 ? void 0 : item.permission_code) || '' }))),
130
135
  });
131
136
  if (parentKey) {
132
- setOpenKeys(prev => [...prev, parentKey]);
137
+ setOpenKeys(prev => uniq([...prev, parentKey]));
133
138
  }
134
139
  }
135
140
  break;
@@ -151,7 +156,7 @@ export const ChildMenu = memo(props => {
151
156
  menuItems: menuItems === null || menuItems === void 0 ? void 0 : menuItems.map(item => getMenuItem(item)),
152
157
  });
153
158
  if (parentKey) {
154
- setOpenKeys(prev => [...prev, parentKey]);
159
+ setOpenKeys(prev => uniq([...prev, parentKey]));
155
160
  }
156
161
  // Active App Item having code matching url
157
162
  const matchAppCode = findActiveAppCodeByUrl({ menuItems, url, auth });
@@ -247,6 +252,6 @@ export const ChildMenu = memo(props => {
247
252
  };
248
253
  return (React.createElement(MenuWrapper, null,
249
254
  React.createElement(Menu, { selectedKeys: [currentActiveItem], defaultOpenKeys: [currentActiveItem], openKeys: uniq(openKeys), mode: "inline", items: customMenuItems({ items }), inlineIndent: 12, onOpenChange: openKeys => {
250
- setOpenKeys(openKeys);
255
+ setOpenKeys(uniq(openKeys));
251
256
  }, expandIcon: ({ isOpen }) => (React.createElement(Icon, { type: "icon-ants-expand-more", style: Object.assign(Object.assign({}, styles.expandIcon), { transform: `rotate(${isOpen ? '180deg' : '0deg'})` }) })), onClick: onClick })));
252
257
  });
@@ -2,6 +2,7 @@ import { LeftMenuProps } from '..';
2
2
  interface TState {
3
3
  hoverItem: string;
4
4
  isExpandMenu: boolean;
5
+ isShowPopover: boolean;
5
6
  }
6
7
  export declare const useLeftMenu: (props: LeftMenuProps) => {
7
8
  state: TState;
@@ -12,5 +13,6 @@ export declare const useLeftMenu: (props: LeftMenuProps) => {
12
13
  onMouseEnter: (key: string) => void;
13
14
  onMouseLeave: () => void;
14
15
  onHoverMenuBar: () => void;
16
+ onShowPopover: (hoverItem?: string) => void;
15
17
  };
16
18
  export {};
@@ -1,6 +1,7 @@
1
1
  // Libraries
2
- import { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { isArray, isNil } from 'lodash';
4
+ import { Cookies } from 'react-cookie';
4
5
  // Utils
5
6
  import { findActiveAppCodeByChild, findActiveAppCodeByUrl, recursiveGetMenuItemByPermission, } from '../utils';
6
7
  // Store
@@ -9,12 +10,11 @@ import { useLeftMenuContext } from '../contexts';
9
10
  import { DASHBOARD_MODULE_CONFIG } from '../../../template/Layout/constants';
10
11
  // Hooks
11
12
  import { usePermission } from './usePermission';
12
- import { Cookies } from 'react-cookie';
13
13
  import { useDeepCompareEffect } from '@antscorp/antsomi-ui/es/hooks';
14
14
  export const useLeftMenu = (props) => {
15
15
  // Props
16
16
  const { objectType = DASHBOARD_MODULE_CONFIG.objectType, objectId = DASHBOARD_MODULE_CONFIG.objectId, isGrouped = DASHBOARD_MODULE_CONFIG.isGrouped, appConfig, customization, onActiveMenuCodeChange, } = props;
17
- const { isExpandable = true, expandMenu = false, isCustomized = false, isRecommendation = false, items, activeKey, onMenuItemClick, } = customization || {};
17
+ const { expandMenu = false, isCustomized = false, isRecommendation = false, items, activeKey, onMenuItemClick, } = customization || {};
18
18
  const mappedActiveKey = useMemo(() => {
19
19
  if (!isRecommendation)
20
20
  return activeKey;
@@ -32,16 +32,18 @@ export const useLeftMenu = (props) => {
32
32
  return activeKey;
33
33
  }
34
34
  }, [activeKey, isRecommendation]);
35
- const cookie = new Cookies();
35
+ const cookies = new Cookies();
36
36
  const { pathname, hash, origin } = window.location;
37
37
  const activeAppCode = useLeftMenuContext(store => store.activeAppCode);
38
38
  const customActiveAppKey = useLeftMenuContext(store => store.customActiveAppKey);
39
39
  const setLeftMenuContextState = useLeftMenuContext(store => store.setState);
40
40
  const { auth, env } = appConfig || {};
41
- const leftMenuCookies = cookie.get('_leftmenu_state');
41
+ const timeoutPopover = useRef(null);
42
+ const leftMenuCookies = cookies.get('_leftmenu_state');
42
43
  const isOpenMenu = !isNil(leftMenuCookies === null || leftMenuCookies === void 0 ? void 0 : leftMenuCookies.expand) ? leftMenuCookies === null || leftMenuCookies === void 0 ? void 0 : leftMenuCookies.expand : true;
43
44
  const [state, setState] = useState({
44
45
  hoverItem: '',
46
+ isShowPopover: false,
45
47
  isExpandMenu: expandMenu || isOpenMenu,
46
48
  });
47
49
  const { mappingChildrenMenu, flattenMenuPermission, permissionMenu, activeItemPath } = usePermission();
@@ -53,7 +55,7 @@ export const useLeftMenu = (props) => {
53
55
  }, [customActiveAppKey, isRecommendation, onMenuItemClick, setLeftMenuContextState]);
54
56
  useDeepCompareEffect(() => {
55
57
  if (!expandMenu) {
56
- cookie.set('_leftmenu_state', Object.assign(Object.assign({}, leftMenuCookies), { expand: state.isExpandMenu }));
58
+ cookies.set('_leftmenu_state', Object.assign(Object.assign({}, leftMenuCookies), { expand: state.isExpandMenu }));
57
59
  // const domain = '.antsomi.com';
58
60
  // const cookieValue = {
59
61
  // ...leftMenuCookies,
@@ -119,25 +121,27 @@ export const useLeftMenu = (props) => {
119
121
  ]);
120
122
  // Change list menu children when hovering or activating items, giving priority to hovering items
121
123
  useDeepCompareEffect(() => {
122
- var _a, _b, _c;
123
- const appActiveKey = state.hoverItem
124
- ? state.hoverItem
125
- : isCustomized || isRecommendation
126
- ? customActiveAppKey
127
- : activeAppCode;
124
+ var _a, _b, _c, _d, _e, _f;
125
+ const appActiveKey = isCustomized || isRecommendation ? customActiveAppKey : activeAppCode;
128
126
  switch (true) {
129
127
  case isCustomized: {
130
128
  setLeftMenuContextState({
131
129
  customItems: items,
132
130
  customMenuChildren: ((_a = items === null || items === void 0 ? void 0 : items.find(item => item.key === appActiveKey)) === null || _a === void 0 ? void 0 : _a.children) || [],
131
+ customHoverMenuChildren: state.hoverItem
132
+ ? ((_b = items === null || items === void 0 ? void 0 : items.find(item => item.key === state.hoverItem)) === null || _b === void 0 ? void 0 : _b.children) || []
133
+ : [],
133
134
  });
134
135
  break;
135
136
  }
136
137
  case isRecommendation: {
137
138
  setLeftMenuContextState({
138
139
  menuItems: mappingChildrenMenu,
139
- appMenuChildren: ((_b = mappingChildrenMenu === null || mappingChildrenMenu === void 0 ? void 0 : mappingChildrenMenu.find(item => item.permission_code === appActiveKey)) === null || _b === void 0 ? void 0 : _b.children) ||
140
+ appMenuChildren: ((_c = mappingChildrenMenu === null || mappingChildrenMenu === void 0 ? void 0 : mappingChildrenMenu.find(item => item.permission_code === appActiveKey)) === null || _c === void 0 ? void 0 : _c.children) ||
140
141
  [],
142
+ appHoverMenuChildren: state.hoverItem
143
+ ? ((_d = mappingChildrenMenu === null || mappingChildrenMenu === void 0 ? void 0 : mappingChildrenMenu.find(item => item.permission_code === state.hoverItem)) === null || _d === void 0 ? void 0 : _d.children) || []
144
+ : [],
141
145
  });
142
146
  break;
143
147
  }
@@ -145,8 +149,11 @@ export const useLeftMenu = (props) => {
145
149
  if (isArray(mappingChildrenMenu)) {
146
150
  setLeftMenuContextState({
147
151
  menuItems: mappingChildrenMenu,
148
- appMenuChildren: ((_c = mappingChildrenMenu === null || mappingChildrenMenu === void 0 ? void 0 : mappingChildrenMenu.find(item => item.menu_item_code === appActiveKey)) === null || _c === void 0 ? void 0 : _c.children) ||
152
+ appMenuChildren: ((_e = mappingChildrenMenu === null || mappingChildrenMenu === void 0 ? void 0 : mappingChildrenMenu.find(item => item.menu_item_code === appActiveKey)) === null || _e === void 0 ? void 0 : _e.children) ||
149
153
  [],
154
+ appHoverMenuChildren: state.hoverItem
155
+ ? ((_f = mappingChildrenMenu === null || mappingChildrenMenu === void 0 ? void 0 : mappingChildrenMenu.find(item => item.menu_item_code === state.hoverItem)) === null || _f === void 0 ? void 0 : _f.children) || []
156
+ : [],
150
157
  });
151
158
  }
152
159
  break;
@@ -204,24 +211,38 @@ export const useLeftMenu = (props) => {
204
211
  isRecommendation,
205
212
  onActiveMenuCodeChange,
206
213
  ]);
214
+ useEffect(() => clearTimeout(timeoutPopover === null || timeoutPopover === void 0 ? void 0 : timeoutPopover.current), [timeoutPopover]);
215
+ const onShowPopover = useCallback((hoverItem) => {
216
+ if (timeoutPopover)
217
+ clearTimeout(timeoutPopover === null || timeoutPopover === void 0 ? void 0 : timeoutPopover.current);
218
+ if (!state.isShowPopover)
219
+ setState(prev => (Object.assign(Object.assign({}, prev), { isShowPopover: true })));
220
+ if (hoverItem)
221
+ setState(prev => (Object.assign(Object.assign({}, prev), { hoverItem })));
222
+ }, [state.isShowPopover]);
207
223
  const onToggleChildMenu = useCallback(() => {
208
224
  setState(prev => (Object.assign(Object.assign({}, prev), { isExpandMenu: !prev.isExpandMenu })));
209
225
  }, []);
210
226
  const onMouseEnter = useCallback((key) => {
211
- setState(prev => (Object.assign(Object.assign({}, prev), { hoverItem: key })));
212
- // if (!state.isExpandMenu || !isExpandable) {
213
- // setState(prev => ({ ...prev, hoverItem: key }));
214
- // }
215
- }, []);
227
+ if (state.hoverItem !== key) {
228
+ onShowPopover(key);
229
+ // if (!state.isExpandMenu || !isExpandable) {
230
+ // setState(prev => ({ ...prev, hoverItem: key }));
231
+ // }
232
+ }
233
+ }, [state.hoverItem, onShowPopover]);
216
234
  const onMouseLeave = useCallback(() => {
217
- setState(prev => (Object.assign(Object.assign({}, prev), { hoverItem: '' })));
235
+ timeoutPopover.current = setTimeout(() => {
236
+ setState(prev => (Object.assign(Object.assign({}, prev), { hoverItem: '' })));
237
+ setState(prev => (Object.assign(Object.assign({}, prev), { isShowPopover: false })));
238
+ }, 500);
218
239
  // if (!state.isExpandMenu || !isExpandable) {
219
240
  // setState(prev => ({ ...prev, hoverItem: '' }));
220
241
  // }
221
242
  }, []);
222
- const onHoverMenuBar = () => {
243
+ const onHoverMenuBar = useCallback(() => {
223
244
  onMouseEnter(isCustomized ? customActiveAppKey : activeAppCode);
224
- };
245
+ }, [activeAppCode, customActiveAppKey, isCustomized, onMouseEnter]);
225
246
  return {
226
247
  state,
227
248
  activeAppCode,
@@ -231,5 +252,6 @@ export const useLeftMenu = (props) => {
231
252
  onMouseEnter,
232
253
  onMouseLeave,
233
254
  onHoverMenuBar,
255
+ onShowPopover,
234
256
  };
235
257
  };
@@ -1,10 +1,10 @@
1
1
  // Libraries
2
- import { useContextSelector } from 'use-context-selector';
3
2
  import { useCallback, useMemo } from 'react';
4
3
  import { isNil } from 'lodash';
5
4
  import { useLocation } from 'react-router-dom';
5
+ import { useDeepCompareMemo } from '@antscorp/antsomi-ui/es/hooks';
6
6
  // Contexts
7
- import { AppConfigContext } from '@antscorp/antsomi-ui/es/providers';
7
+ import { useLeftMenuContext } from '../contexts';
8
8
  // Utils
9
9
  import { getGeneratePath } from '../utils';
10
10
  import { hasSelectAccountPermission } from '../../../template/Layout/utils';
@@ -13,11 +13,12 @@ import { ENV } from '@antscorp/antsomi-ui/es/config';
13
13
  // Hooks
14
14
  import { usePermission } from './usePermission';
15
15
  export const useNavigatePath = () => {
16
- const { auth, env } = useContextSelector(AppConfigContext, state => state);
16
+ const appConfig = useLeftMenuContext(store => store.appConfig);
17
+ const { auth, env } = appConfig || {};
17
18
  const { search } = useLocation();
18
19
  const isDev = env === ENV.DEV;
19
20
  const { activeItemPath, flattenMenuPermission } = usePermission();
20
- const hasRole = useMemo(() => hasSelectAccountPermission(activeItemPath, flattenMenuPermission), [activeItemPath, flattenMenuPermission]);
21
+ const hasRole = useDeepCompareMemo(() => hasSelectAccountPermission(activeItemPath, flattenMenuPermission), [activeItemPath, flattenMenuPermission]);
21
22
  const urlParams = useMemo(() => new URLSearchParams(search), [search]);
22
23
  const oidParam = hasRole ? urlParams.get('oid') : null;
23
24
  const searchParams = oidParam ? `?oid=${oidParam}` : '';
@@ -8,7 +8,9 @@ export interface LeftMenuStoreProps {
8
8
  menuItems: TFeatureMenu[];
9
9
  customItems: TMenuItem[];
10
10
  customMenuChildren: TMenuItem[];
11
+ customHoverMenuChildren: TMenuItem[];
11
12
  appMenuChildren: TFeatureMenu[];
13
+ appHoverMenuChildren: TFeatureMenu[];
12
14
  appConfig?: AppConfigProviderProps;
13
15
  isCustomized?: boolean;
14
16
  isRecommendation?: boolean;
@@ -6,8 +6,10 @@ const DEFAULT_PROPS = {
6
6
  customActiveCurrentKey: '',
7
7
  menuItems: [],
8
8
  appMenuChildren: [],
9
+ appHoverMenuChildren: [],
9
10
  customItems: [],
10
11
  customMenuChildren: [],
12
+ customHoverMenuChildren: [],
11
13
  isCustomized: false,
12
14
  isRecommendation: false,
13
15
  dashboardParams: {
@@ -1,6 +1,8 @@
1
1
  /// <reference types="react" />
2
2
  export declare const IconWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
3
- export declare const PopoverWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
3
+ export declare const PopoverWrapper: import("styled-components").StyledComponent<"div", any, {
4
+ show: boolean;
5
+ }, never>;
4
6
  export declare const FeatureMenuWrapper: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("antd/es/flex/interface").FlexProps<import("antd/es/_util/type").AnyObject> & import("react").RefAttributes<HTMLElement>>, any, {}, never>;
5
7
  export declare const ExpandWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
6
8
  export declare const LeftMenuNavWrapper: import("styled-components").StyledComponent<"div", any, {
@@ -19,8 +19,16 @@ export const IconWrapper = styled.div `
19
19
  }
20
20
  `;
21
21
  export const PopoverWrapper = styled.div `
22
- opacity: 0;
23
- visibility: hidden;
22
+ ${({ show }) => show
23
+ ? `
24
+ opacity: 1;
25
+ visibility: visible;
26
+ `
27
+ : `
28
+ opacity: 0;
29
+ visibility: hidden;
30
+ `}
31
+
24
32
  position: absolute;
25
33
  background-color: white;
26
34
  left: 65px;
@@ -36,13 +44,6 @@ export const PopoverWrapper = styled.div `
36
44
  export const FeatureMenuWrapper = styled(Flex) `
37
45
  flex: 1 1 0%;
38
46
  overflow: hidden;
39
-
40
- &:hover {
41
- ${PopoverWrapper} {
42
- visibility: visible;
43
- opacity: 1;
44
- }
45
- }
46
47
  `;
47
48
  export const ExpandWrapper = styled.div `
48
49
  height: 35px;
@@ -35,6 +35,7 @@ export const GlobalStyle = () => {
35
35
 
36
36
  .rc-virtual-list-scrollbar {
37
37
  width: 4px !important;
38
+ height: 4px !important;
38
39
  }
39
40
 
40
41
  /* Custom */
@@ -23,6 +23,7 @@ import axios from 'axios';
23
23
  import { get } from 'lodash';
24
24
  // Constants
25
25
  import { COLUMN_API_TYPE, FILTER_API_TYPE } from '../../constants/dataTable';
26
+ import { mapResponseListingToGeneral } from '../../utils';
26
27
  const { GET_COLUMNS, GET_LIST_MODIFY_COLUMN, UPDATE_MODIFY_COLUMN, ADD_MODIFY_COLUMN } = COLUMN_API_TYPE;
27
28
  const { GET_SAVED_FILTER, GET_LIST_FILTER, SAVE_FILTER, UPDATE_FILTER } = FILTER_API_TYPE;
28
29
  /* ---------- END OF LISTING ---------- */
@@ -185,11 +186,7 @@ export const dataTableServices = {
185
186
  return __awaiter(this, arguments, void 0, function* ({ auth, params, request, }) {
186
187
  try {
187
188
  const response = yield axios(Object.assign(Object.assign({}, request), { url: `${auth === null || auth === void 0 ? void 0 : auth.url}`, method: 'GET', params: Object.assign(Object.assign(Object.assign({}, request === null || request === void 0 ? void 0 : request.params), mapAuth(auth)), params) }));
188
- return get(response, 'data.data', {
189
- body: [],
190
- header: [],
191
- total: 0,
192
- });
189
+ return mapResponseListingToGeneral(get(response, 'data.data', {}));
193
190
  }
194
191
  catch (error) {
195
192
  return Promise.reject(error);
@@ -1,9 +1,9 @@
1
1
  // Libraries
2
2
  import React, { useCallback, useMemo, useState } from 'react';
3
- import { BrowserRouter } from 'react-router-dom';
3
+ import { BrowserRouter, Link } from 'react-router-dom';
4
4
  // Components
5
5
  import { DataTable, } from '../components/organism/DataTable';
6
- import { Popover } from '../components';
6
+ import { Popover, Typography } from '../components';
7
7
  // Styled
8
8
  import { TableTestWrapper } from './styled';
9
9
  // Constants
@@ -46,7 +46,7 @@ export const DataTableTest = () => {
46
46
  // Variables
47
47
  const { tableCollapsed } = state;
48
48
  // Hooks
49
- const { modifyColumn, filter, pagination, table } = useDataTableListing({
49
+ const { modifyColumn, filter, pagination, table, selectedRowKeys } = useDataTableListing({
50
50
  config: {
51
51
  // auth: {}, // Default is get from AppConfigProvider
52
52
  api: {
@@ -65,6 +65,19 @@ export const DataTableTest = () => {
65
65
  name: 'survey',
66
66
  table: {
67
67
  mainColumnKey: 'survey_id',
68
+ columns: {
69
+ survey_name: {
70
+ render: (value, record) => (React.createElement(Link, { to: `/survey/${record.survey_id}` },
71
+ React.createElement(Typography.Link, null, value))),
72
+ },
73
+ // toggle: {
74
+ // title: 'Status',
75
+ // valueKey: 'responses',
76
+ // onChange: (checked, record) => {
77
+ // console.log({ checked, record });
78
+ // },
79
+ // },
80
+ },
68
81
  },
69
82
  });
70
83
  const searchList = useMemo(() => {
@@ -0,0 +1,5 @@
1
+ export declare const mapResponseListingToGeneral: (response: Record<string, any>) => {
2
+ body: any;
3
+ header: any;
4
+ total: any;
5
+ };
@@ -0,0 +1,9 @@
1
+ // NOTES: Improve typescript
2
+ export const mapResponseListingToGeneral = (response) => {
3
+ const { body, header, total, entries, column_defs, rows, total_records } = response || {};
4
+ return {
5
+ body: body || entries || rows || [],
6
+ header: header || column_defs || [],
7
+ total: total || total_records || 0,
8
+ };
9
+ };
@@ -5,3 +5,4 @@ export * from './templateListing';
5
5
  export * from './styles';
6
6
  export * from './variables';
7
7
  export * from './actionButtons';
8
+ export * from './dataTable';
package/es/utils/index.js CHANGED
@@ -5,3 +5,4 @@ export * from './templateListing';
5
5
  export * from './styles';
6
6
  export * from './variables';
7
7
  export * from './actionButtons';
8
+ export * from './dataTable';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antscorp/antsomi-ui",
3
- "version": "1.3.5-beta.407",
3
+ "version": "1.3.5-beta.409",
4
4
  "description": "An enterprise-class UI design language and React UI library.",
5
5
  "sideEffects": [
6
6
  "dist/*",