@akinon/ai-modal-table 1.0.1 → 1.0.3

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 (59) hide show
  1. package/dist/cjs/ai-modal-table/__tests__/index.test.js +36 -2
  2. package/dist/cjs/ai-modal-table/__tests__/index.test.tsx +74 -2
  3. package/dist/cjs/ai-modal-table/index.d.ts +1 -1
  4. package/dist/cjs/ai-modal-table/index.d.ts.map +1 -1
  5. package/dist/cjs/ai-modal-table/index.js +2 -2
  6. package/dist/cjs/ai-table/__tests__/index.test.js +23 -0
  7. package/dist/cjs/ai-table/__tests__/index.test.tsx +39 -0
  8. package/dist/cjs/ai-table/components/__tests__/content.test.js +61 -9
  9. package/dist/cjs/ai-table/components/__tests__/content.test.tsx +77 -9
  10. package/dist/cjs/ai-table/components/content.d.ts +2 -1
  11. package/dist/cjs/ai-table/components/content.d.ts.map +1 -1
  12. package/dist/cjs/ai-table/components/content.js +25 -15
  13. package/dist/cjs/ai-table/components/footer.js +1 -1
  14. package/dist/cjs/ai-table/components/mapper.js +1 -1
  15. package/dist/cjs/ai-table/constants/index.d.ts +4 -0
  16. package/dist/cjs/ai-table/constants/index.d.ts.map +1 -1
  17. package/dist/cjs/ai-table/constants/index.js +5 -1
  18. package/dist/cjs/ai-table/index.d.ts +1 -1
  19. package/dist/cjs/ai-table/index.d.ts.map +1 -1
  20. package/dist/cjs/ai-table/index.js +3 -3
  21. package/dist/cjs/ai-table/utils/render-edit-fields/__tests__/index.test.d.ts +2 -0
  22. package/dist/cjs/ai-table/utils/render-edit-fields/__tests__/index.test.d.ts.map +1 -0
  23. package/dist/cjs/ai-table/utils/render-edit-fields/__tests__/index.test.js +220 -0
  24. package/dist/cjs/ai-table/utils/render-edit-fields/__tests__/index.test.tsx +283 -0
  25. package/dist/cjs/ai-table/utils/render-edit-fields/index.d.ts +13 -0
  26. package/dist/cjs/ai-table/utils/render-edit-fields/index.d.ts.map +1 -0
  27. package/dist/cjs/ai-table/utils/render-edit-fields/index.js +65 -0
  28. package/dist/cjs/types/index.d.ts +24 -4
  29. package/dist/cjs/types/index.d.ts.map +1 -1
  30. package/dist/esm/ai-modal-table/__tests__/index.test.js +36 -2
  31. package/dist/esm/ai-modal-table/__tests__/index.test.tsx +74 -2
  32. package/dist/esm/ai-modal-table/index.d.ts +1 -1
  33. package/dist/esm/ai-modal-table/index.d.ts.map +1 -1
  34. package/dist/esm/ai-modal-table/index.js +2 -2
  35. package/dist/esm/ai-table/__tests__/index.test.js +23 -0
  36. package/dist/esm/ai-table/__tests__/index.test.tsx +39 -0
  37. package/dist/esm/ai-table/components/__tests__/content.test.js +61 -9
  38. package/dist/esm/ai-table/components/__tests__/content.test.tsx +77 -9
  39. package/dist/esm/ai-table/components/content.d.ts +2 -1
  40. package/dist/esm/ai-table/components/content.d.ts.map +1 -1
  41. package/dist/esm/ai-table/components/content.js +25 -15
  42. package/dist/esm/ai-table/components/footer.js +1 -1
  43. package/dist/esm/ai-table/components/mapper.js +1 -1
  44. package/dist/esm/ai-table/constants/index.d.ts +4 -0
  45. package/dist/esm/ai-table/constants/index.d.ts.map +1 -1
  46. package/dist/esm/ai-table/constants/index.js +4 -0
  47. package/dist/esm/ai-table/index.d.ts +1 -1
  48. package/dist/esm/ai-table/index.d.ts.map +1 -1
  49. package/dist/esm/ai-table/index.js +3 -3
  50. package/dist/esm/ai-table/utils/render-edit-fields/__tests__/index.test.d.ts +2 -0
  51. package/dist/esm/ai-table/utils/render-edit-fields/__tests__/index.test.d.ts.map +1 -0
  52. package/dist/esm/ai-table/utils/render-edit-fields/__tests__/index.test.js +218 -0
  53. package/dist/esm/ai-table/utils/render-edit-fields/__tests__/index.test.tsx +283 -0
  54. package/dist/esm/ai-table/utils/render-edit-fields/index.d.ts +13 -0
  55. package/dist/esm/ai-table/utils/render-edit-fields/index.d.ts.map +1 -0
  56. package/dist/esm/ai-table/utils/render-edit-fields/index.js +60 -0
  57. package/dist/esm/types/index.d.ts +24 -4
  58. package/dist/esm/types/index.d.ts.map +1 -1
  59. package/package.json +13 -13
@@ -17,8 +17,32 @@ const react_2 = require("react");
17
17
  const vitest_1 = require("vitest");
18
18
  vitest_1.vi.mock('@akinon/ui-theme', async (importOriginal) => {
19
19
  const actual = (await importOriginal());
20
- return Object.assign(Object.assign({}, actual), { useToken: () => ({ token: {}, hashId: 'hash123' }) });
20
+ return Object.assign(Object.assign({}, actual), { useToken: () => ({
21
+ token: {
22
+ fontWeight: 400,
23
+ fontWeightStrong: 600,
24
+ fontSizeSM: 12,
25
+ colorTextBase: '#000000',
26
+ colorBgBase: '#ffffff',
27
+ fontSize: 14,
28
+ borderRadius: 4,
29
+ colorPrimary: '#1890ff'
30
+ },
31
+ hashId: 'hash123'
32
+ }) });
21
33
  });
34
+ vitest_1.vi.mock('@akinon/ui-select', () => ({
35
+ Select: (_a) => {
36
+ var { children } = _a, props = __rest(_a, ["children"]);
37
+ return (react_2.default.createElement("select", Object.assign({ "data-testid": "select" }, props), children));
38
+ }
39
+ }));
40
+ vitest_1.vi.mock('@akinon/ui-button', () => ({
41
+ Button: (_a) => {
42
+ var { children } = _a, props = __rest(_a, ["children"]);
43
+ return (react_2.default.createElement("button", Object.assign({}, props), children));
44
+ }
45
+ }));
22
46
  vitest_1.vi.mock('@akinon/ui-layout', () => ({
23
47
  Flex: ({ children }) => react_2.default.createElement("div", { "data-testid": "flex" }, children)
24
48
  }));
@@ -35,7 +59,8 @@ vitest_1.vi.mock('../ai-table', () => ({
35
59
  react_2.default.createElement("pre", { "data-testid": "ai-table-props" }, JSON.stringify({
36
60
  columns: props.columns,
37
61
  data: props.data,
38
- isLoading: props.isLoading
62
+ isLoading: props.isLoading,
63
+ emptyText: props.emptyText
39
64
  })))),
40
65
  DEFAULT_ROW_KEY: 'id'
41
66
  }));
@@ -56,4 +81,13 @@ const index_1 = require("../index");
56
81
  react_1.fireEvent.click(react_1.screen.getByTestId('close-button'));
57
82
  (0, vitest_1.expect)(onCancel).toHaveBeenCalledTimes(1);
58
83
  });
84
+ (0, vitest_1.it)('passes emptyText prop to AiTable when provided', () => {
85
+ const columns = [{ title: 'Name', dataIndex: 'name' }];
86
+ const data = [{ id: 1, name: 'Alice' }];
87
+ const { rerender } = (0, react_1.render)(react_2.default.createElement(index_1.AiModalTable, { description: "My description", columns: columns, data: data, isLoading: true, submitAllLabel: "Submit All", submitSelectedLabel: "Submit Selected", filters: [], selectedRows: [], onChangeSelectedRows: () => { }, isSubmitting: false, onSubmitAllData: () => { }, onSubmitSelectedData: () => { } }));
88
+ (0, vitest_1.expect)(react_1.screen.getByText('My description')).toBeInTheDocument();
89
+ // Re-render with emptyText prop
90
+ rerender(react_2.default.createElement(index_1.AiModalTable, { description: "My description", columns: columns, data: data, isLoading: true, submitAllLabel: "Submit All", submitSelectedLabel: "Submit Selected", filters: [], selectedRows: [], onChangeSelectedRows: () => { }, isSubmitting: false, onSubmitAllData: () => { }, onSubmitSelectedData: () => { }, emptyText: "No data available" }));
91
+ (0, vitest_1.expect)(react_1.screen.getByText('My description')).toBeInTheDocument();
92
+ });
59
93
  });
@@ -8,10 +8,36 @@ vi.mock('@akinon/ui-theme', async importOriginal => {
8
8
 
9
9
  return {
10
10
  ...actual,
11
- useToken: () => ({ token: {}, hashId: 'hash123' })
11
+ useToken: () => ({
12
+ token: {
13
+ fontWeight: 400,
14
+ fontWeightStrong: 600,
15
+ fontSizeSM: 12,
16
+ colorTextBase: '#000000',
17
+ colorBgBase: '#ffffff',
18
+ fontSize: 14,
19
+ borderRadius: 4,
20
+ colorPrimary: '#1890ff'
21
+ },
22
+ hashId: 'hash123'
23
+ })
12
24
  };
13
25
  });
14
26
 
27
+ vi.mock('@akinon/ui-select', () => ({
28
+ Select: ({ children, ...props }: any) => (
29
+ <select data-testid="select" {...props}>
30
+ {children}
31
+ </select>
32
+ )
33
+ }));
34
+
35
+ vi.mock('@akinon/ui-button', () => ({
36
+ Button: ({ children, ...props }: any) => (
37
+ <button {...props}>{children}</button>
38
+ )
39
+ }));
40
+
15
41
  vi.mock('@akinon/ui-layout', () => ({
16
42
  Flex: ({ children }: any) => <div data-testid="flex">{children}</div>
17
43
  }));
@@ -32,7 +58,8 @@ vi.mock('../ai-table', () => ({
32
58
  {JSON.stringify({
33
59
  columns: props.columns,
34
60
  data: props.data,
35
- isLoading: props.isLoading
61
+ isLoading: props.isLoading,
62
+ emptyText: props.emptyText
36
63
  })}
37
64
  </pre>
38
65
  </div>
@@ -95,4 +122,49 @@ describe('AiModalTable', () => {
95
122
  fireEvent.click(screen.getByTestId('close-button'));
96
123
  expect(onCancel).toHaveBeenCalledTimes(1);
97
124
  });
125
+
126
+ it('passes emptyText prop to AiTable when provided', () => {
127
+ const columns = [{ title: 'Name', dataIndex: 'name' }];
128
+ const data = [{ id: 1, name: 'Alice' }];
129
+
130
+ const { rerender } = render(
131
+ <AiModalTable
132
+ description="My description"
133
+ columns={columns}
134
+ data={data}
135
+ isLoading={true}
136
+ submitAllLabel="Submit All"
137
+ submitSelectedLabel="Submit Selected"
138
+ filters={[]}
139
+ selectedRows={[]}
140
+ onChangeSelectedRows={() => {}}
141
+ isSubmitting={false}
142
+ onSubmitAllData={() => {}}
143
+ onSubmitSelectedData={() => {}}
144
+ />
145
+ );
146
+
147
+ expect(screen.getByText('My description')).toBeInTheDocument();
148
+
149
+ // Re-render with emptyText prop
150
+ rerender(
151
+ <AiModalTable
152
+ description="My description"
153
+ columns={columns}
154
+ data={data}
155
+ isLoading={true}
156
+ submitAllLabel="Submit All"
157
+ submitSelectedLabel="Submit Selected"
158
+ filters={[]}
159
+ selectedRows={[]}
160
+ onChangeSelectedRows={() => {}}
161
+ isSubmitting={false}
162
+ onSubmitAllData={() => {}}
163
+ onSubmitSelectedData={() => {}}
164
+ emptyText="No data available"
165
+ />
166
+ );
167
+
168
+ expect(screen.getByText('My description')).toBeInTheDocument();
169
+ });
98
170
  });
@@ -1,4 +1,4 @@
1
1
  import * as React from 'react';
2
2
  import type { AiModalTableProps } from '../types';
3
- export declare const AiModalTable: ({ columns, customActionButtons, data, description, editDataIndexes, filters, isLoading, isSubmitting, onChangeSelectedRows, onEdit, onSubmitAllData, onSubmitSelectedData, rowKey, selectedRows, submitAllLabel, submitSelectedLabel, mapperConfig, tableClassName, ...modalProps }: AiModalTableProps) => React.JSX.Element;
3
+ export declare const AiModalTable: ({ columns, customActionButtons, data, description, editDataIndexes, filters, isLoading, isSubmitting, onChangeSelectedRows, onEdit, onSubmitAllData, onSubmitSelectedData, rowKey, selectedRows, submitAllLabel, submitSelectedLabel, mapperConfig, tableClassName, emptyText, ...modalProps }: AiModalTableProps) => React.JSX.Element;
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai-modal-table/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElD,eAAO,MAAM,YAAY,GAAI,qRAoB1B,iBAAiB,sBAoEnB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai-modal-table/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElD,eAAO,MAAM,YAAY,GAAI,gSAqB1B,iBAAiB,sBAqEnB,CAAC"}
@@ -22,7 +22,7 @@ const React = require("react");
22
22
  const ai_table_1 = require("../ai-table");
23
23
  const constants_1 = require("../ai-table/constants");
24
24
  const AiModalTable = (_a) => {
25
- var { columns = [], customActionButtons, data = [], description, editDataIndexes, filters = [], isLoading, isSubmitting, onChangeSelectedRows, onEdit, onSubmitAllData, onSubmitSelectedData, rowKey = constants_1.DEFAULT_ROW_KEY, selectedRows, submitAllLabel, submitSelectedLabel, mapperConfig, tableClassName } = _a, modalProps = __rest(_a, ["columns", "customActionButtons", "data", "description", "editDataIndexes", "filters", "isLoading", "isSubmitting", "onChangeSelectedRows", "onEdit", "onSubmitAllData", "onSubmitSelectedData", "rowKey", "selectedRows", "submitAllLabel", "submitSelectedLabel", "mapperConfig", "tableClassName"]);
25
+ var { columns = [], customActionButtons, data = [], description, editDataIndexes, filters = [], isLoading, isSubmitting, onChangeSelectedRows, onEdit, onSubmitAllData, onSubmitSelectedData, rowKey = constants_1.DEFAULT_ROW_KEY, selectedRows, submitAllLabel, submitSelectedLabel, mapperConfig, tableClassName, emptyText } = _a, modalProps = __rest(_a, ["columns", "customActionButtons", "data", "description", "editDataIndexes", "filters", "isLoading", "isSubmitting", "onChangeSelectedRows", "onEdit", "onSubmitAllData", "onSubmitSelectedData", "rowKey", "selectedRows", "submitAllLabel", "submitSelectedLabel", "mapperConfig", "tableClassName", "emptyText"]);
26
26
  const { onCancel, className } = modalProps, restModalProps = __rest(modalProps, ["onCancel", "className"]);
27
27
  const { getPrefixCls, theme } = React.useContext(antd_1.ConfigProvider.ConfigContext);
28
28
  const { token, hashId } = (0, ui_theme_1.useToken)();
@@ -49,6 +49,6 @@ const AiModalTable = (_a) => {
49
49
  return useStyle(React.createElement(ui_modal_1.Modal, Object.assign({ className: (0, classnames_1.default)(baseCls, hashId, className), footer: null, onCancel: handleCancel, centered: true, destroyOnClose: true, width: 1200 }, restModalProps),
50
50
  React.createElement(ui_layout_1.Flex, { gap: 10, vertical: true },
51
51
  React.createElement("div", { className: "text-neutral-50 text-sm mb-2" }, description),
52
- React.createElement(ai_table_1.AiTable, { columns: columns, customActionButtons: customActionButtons, data: data, editDataIndexes: editDataIndexes, filters: filters, isLoading: isLoading, isSubmitting: isSubmitting, onChangeSelectedRows: onChangeSelectedRows, onEdit: onEdit, onSubmitAllData: onSubmitAllData, onSubmitSelectedData: onSubmitSelectedData, rowKey: rowKey, selectedRows: selectedRows, submitAllLabel: submitAllLabel, submitSelectedLabel: submitSelectedLabel, mapperConfig: mapperConfig, tableClassName: tableClassName }))));
52
+ React.createElement(ai_table_1.AiTable, { columns: columns, customActionButtons: customActionButtons, data: data, editDataIndexes: editDataIndexes, filters: filters, isLoading: isLoading, isSubmitting: isSubmitting, onChangeSelectedRows: onChangeSelectedRows, onEdit: onEdit, onSubmitAllData: onSubmitAllData, onSubmitSelectedData: onSubmitSelectedData, rowKey: rowKey, selectedRows: selectedRows, submitAllLabel: submitAllLabel, submitSelectedLabel: submitSelectedLabel, mapperConfig: mapperConfig, tableClassName: tableClassName, emptyText: emptyText }))));
53
53
  };
54
54
  exports.AiModalTable = AiModalTable;
@@ -345,4 +345,27 @@ vitest_1.vi.mock('@akinon/ui-layout', () => ({
345
345
  (0, vitest_1.expect)(react_1.screen.getByTestId('table-content')).toBeInTheDocument();
346
346
  });
347
347
  });
348
+ (0, vitest_1.describe)('Empty Text', () => {
349
+ (0, vitest_1.it)('should render table without emptyText prop', () => {
350
+ (0, react_1.render)(React.createElement(index_1.AiTable, Object.assign({}, defaultProps)));
351
+ (0, vitest_1.expect)(react_1.screen.getByTestId('table-content')).toBeInTheDocument();
352
+ });
353
+ (0, vitest_1.it)('should pass emptyText prop to TableContent when provided', () => {
354
+ const customEmptyText = 'No data found';
355
+ (0, react_1.render)(React.createElement(index_1.AiTable, Object.assign({}, defaultProps, { emptyText: customEmptyText })));
356
+ (0, vitest_1.expect)(react_1.screen.getByTestId('table-content')).toBeInTheDocument();
357
+ });
358
+ (0, vitest_1.it)('should handle React nodes as emptyText', () => {
359
+ const customEmptyNode = (React.createElement("div", { "data-testid": "custom-empty-message" },
360
+ React.createElement("p", null, "No results available")));
361
+ (0, react_1.render)(React.createElement(index_1.AiTable, Object.assign({}, defaultProps, { emptyText: customEmptyNode })));
362
+ (0, vitest_1.expect)(react_1.screen.getByTestId('table-content')).toBeInTheDocument();
363
+ });
364
+ (0, vitest_1.it)('should work with empty data and custom emptyText', () => {
365
+ const customEmptyText = 'The table is empty';
366
+ (0, react_1.render)(React.createElement(index_1.AiTable, Object.assign({}, defaultProps, { data: [], emptyText: customEmptyText })));
367
+ (0, vitest_1.expect)(react_1.screen.getByTestId('table-content')).toBeInTheDocument();
368
+ (0, vitest_1.expect)(react_1.screen.queryByTestId('row-1')).not.toBeInTheDocument();
369
+ });
370
+ });
348
371
  });
@@ -569,4 +569,43 @@ describe('AiTable', () => {
569
569
  expect(screen.getByTestId('table-content')).toBeInTheDocument();
570
570
  });
571
571
  });
572
+
573
+ describe('Empty Text', () => {
574
+ it('should render table without emptyText prop', () => {
575
+ render(<AiTable {...defaultProps} />);
576
+
577
+ expect(screen.getByTestId('table-content')).toBeInTheDocument();
578
+ });
579
+
580
+ it('should pass emptyText prop to TableContent when provided', () => {
581
+ const customEmptyText = 'No data found';
582
+
583
+ render(<AiTable {...defaultProps} emptyText={customEmptyText} />);
584
+
585
+ expect(screen.getByTestId('table-content')).toBeInTheDocument();
586
+ });
587
+
588
+ it('should handle React nodes as emptyText', () => {
589
+ const customEmptyNode = (
590
+ <div data-testid="custom-empty-message">
591
+ <p>No results available</p>
592
+ </div>
593
+ );
594
+
595
+ render(<AiTable {...defaultProps} emptyText={customEmptyNode} />);
596
+
597
+ expect(screen.getByTestId('table-content')).toBeInTheDocument();
598
+ });
599
+
600
+ it('should work with empty data and custom emptyText', () => {
601
+ const customEmptyText = 'The table is empty';
602
+
603
+ render(
604
+ <AiTable {...defaultProps} data={[]} emptyText={customEmptyText} />
605
+ );
606
+
607
+ expect(screen.getByTestId('table-content')).toBeInTheDocument();
608
+ expect(screen.queryByTestId('row-1')).not.toBeInTheDocument();
609
+ });
610
+ });
572
611
  });
@@ -18,6 +18,7 @@ const user_event_1 = require("@testing-library/user-event");
18
18
  const antd_1 = require("antd");
19
19
  const react_2 = require("react");
20
20
  const vitest_1 = require("vitest");
21
+ const constants_1 = require("../../constants");
21
22
  const content_1 = require("../content");
22
23
  vitest_1.vi.mock('@akinon/icons', () => ({
23
24
  Icon: (_a) => {
@@ -31,6 +32,12 @@ vitest_1.vi.mock('@akinon/ui-input', () => ({
31
32
  return (react_2.default.createElement("input", Object.assign({ onChange: onChange, value: value, className: className, "data-testid": "edit-input" }, props)));
32
33
  }
33
34
  }));
35
+ vitest_1.vi.mock('@akinon/ui-select', () => ({
36
+ Select: (_a) => {
37
+ var { value, onChange, rootClassName, options } = _a, props = __rest(_a, ["value", "onChange", "rootClassName", "options"]);
38
+ return (react_2.default.createElement("select", Object.assign({ "data-testid": "edit-select", value: value !== null && value !== void 0 ? value : '', onChange: e => onChange === null || onChange === void 0 ? void 0 : onChange(e.target.value), className: rootClassName }, props), options === null || options === void 0 ? void 0 : options.map((opt) => (react_2.default.createElement("option", { key: opt.value, value: String(opt.value) }, opt.label)))));
39
+ }
40
+ }));
34
41
  vitest_1.vi.mock('@akinon/ui-layout', () => ({
35
42
  Flex: (_a) => {
36
43
  var { children } = _a, props = __rest(_a, ["children"]);
@@ -337,12 +344,13 @@ vitest_1.vi.mock('../../i18n', () => ({
337
344
  });
338
345
  (0, vitest_1.it)('should apply collapsed style when not expanded', () => {
339
346
  renderComponent({ expandedRows: [] });
347
+ // Row 2 (pk: 2) has multiple mapper items, so it has the expand button
340
348
  const expandIcons = react_1.screen.getAllByTestId('icon-chevron_down');
341
349
  (0, vitest_1.expect)(expandIcons[0].className).toContain('ai-modal-table__icon--collapsed');
342
350
  });
343
351
  (0, vitest_1.it)('should not apply collapsed style when expanded', () => {
344
- renderComponent({ expandedRows: [1] });
345
- // First icon - for row 1
352
+ renderComponent({ expandedRows: [2] });
353
+ // Icon for row 2 (which has multiple mapper items)
346
354
  const icons = react_1.screen.getAllByTestId('icon-chevron_down');
347
355
  (0, vitest_1.expect)(icons[0].className).not.toContain('ai-modal-table__icon--collapsed');
348
356
  });
@@ -353,9 +361,10 @@ vitest_1.vi.mock('../../i18n', () => ({
353
361
  });
354
362
  (0, vitest_1.expect)(react_1.screen.queryByTestId('icon-chevron_down')).not.toBeInTheDocument();
355
363
  });
356
- (0, vitest_1.it)('should render multiple expand buttons for multiple rows', () => {
364
+ (0, vitest_1.it)('should render expand button for rows with multiple mapper items', () => {
357
365
  renderComponent();
358
- (0, vitest_1.expect)(react_1.screen.getAllByTestId('icon-chevron_down').length).toBe(2);
366
+ // Only row 2 has multiple mapper items (2 items), so only 1 expand button should be rendered
367
+ (0, vitest_1.expect)(react_1.screen.getAllByTestId('icon-chevron_down').length).toBe(1);
359
368
  });
360
369
  });
361
370
  (0, vitest_1.describe)('Mapper Column', () => {
@@ -552,8 +561,10 @@ vitest_1.vi.mock('../../i18n', () => ({
552
561
  });
553
562
  (0, vitest_1.it)('should render expand button in first column', () => {
554
563
  renderComponent();
555
- const firstRow = react_1.screen.getAllByRole('row')[1];
556
- const firstCell = (0, react_1.within)(firstRow).getAllByRole('cell')[0];
564
+ // Row 2 (index 2) has multiple mapper items, so it has the expand button
565
+ const rows = react_1.screen.getAllByRole('row');
566
+ const rowWithExpandButton = rows[2]; // Row 2 (pk: 2) has multiple mapper items
567
+ const firstCell = (0, react_1.within)(rowWithExpandButton).getAllByRole('cell')[0];
557
568
  (0, vitest_1.expect)(firstCell).toContainElement(react_1.screen.getAllByTestId('icon-chevron_down')[0]);
558
569
  });
559
570
  (0, vitest_1.it)('should handle missing optional data gracefully', () => {
@@ -788,18 +799,20 @@ vitest_1.vi.mock('../../i18n', () => ({
788
799
  });
789
800
  const expandButtons = react_1.screen.getAllByTestId('icon-chevron_down');
790
801
  react_1.fireEvent.click(expandButtons[0]);
791
- (0, vitest_1.expect)(onToggleExpand).toHaveBeenCalledWith(1);
802
+ // Row 2 (pk: 2) has multiple mapper items and is the one with expand button
803
+ (0, vitest_1.expect)(onToggleExpand).toHaveBeenCalledWith(2);
792
804
  });
793
805
  (0, vitest_1.it)('should call onToggleExpand when expand button clicked on expanded row', () => {
794
806
  const onToggleExpand = vitest_1.vi.fn();
795
807
  renderComponent({
796
- expandedRows: [1],
808
+ expandedRows: [2],
797
809
  onToggleExpand
798
810
  });
799
811
  const expandButtons = react_1.screen.getAllByTestId('icon-chevron_down');
800
812
  react_1.fireEvent.click(expandButtons[0]);
801
813
  // The expand button is a toggle - it should call onToggleExpand to collapse the row
802
- (0, vitest_1.expect)(onToggleExpand).toHaveBeenCalledWith(1);
814
+ // Row 2 (pk: 2) has multiple mapper items and is the one with expand button
815
+ (0, vitest_1.expect)(onToggleExpand).toHaveBeenCalledWith(2);
803
816
  });
804
817
  (0, vitest_1.it)('should call onAddItem with correct rowId and dataIndex when add button clicked', () => {
805
818
  const onAddItem = vitest_1.vi.fn();
@@ -1345,5 +1358,44 @@ vitest_1.vi.mock('../../i18n', () => ({
1345
1358
  const inputs = react_1.screen.queryAllByTestId('edit-input');
1346
1359
  (0, vitest_1.expect)(inputs.length).toBeGreaterThan(0);
1347
1360
  });
1361
+ (0, vitest_1.it)('should render Select for editable column when editDataIndexes has SELECT config', async () => {
1362
+ const user = user_event_1.default.setup();
1363
+ const onEdit = vitest_1.vi.fn();
1364
+ renderComponent({
1365
+ data: [
1366
+ {
1367
+ pk: 1,
1368
+ name: 'Item 1',
1369
+ status: 'active',
1370
+ mappings: []
1371
+ }
1372
+ ],
1373
+ columns: [
1374
+ { title: 'Name', dataIndex: 'name' },
1375
+ { title: 'Status', dataIndex: 'status' }
1376
+ ],
1377
+ mapperConfig: undefined,
1378
+ onEdit,
1379
+ editDataIndexes: [
1380
+ 'name',
1381
+ {
1382
+ key: 'status',
1383
+ type: constants_1.EDIT_FIELD_TYPES.SELECT,
1384
+ attributes: {
1385
+ options: [
1386
+ { label: 'Active', value: 'active' },
1387
+ { label: 'Inactive', value: 'inactive' }
1388
+ ]
1389
+ }
1390
+ }
1391
+ ]
1392
+ });
1393
+ const editButton = react_1.screen.getByTestId('edit-button-1');
1394
+ await user.click(editButton);
1395
+ const inputs = react_1.screen.queryAllByTestId('edit-input');
1396
+ const selects = react_1.screen.queryAllByTestId('edit-select');
1397
+ (0, vitest_1.expect)(inputs.length).toBeGreaterThan(0);
1398
+ (0, vitest_1.expect)(selects.length).toBeGreaterThan(0);
1399
+ });
1348
1400
  });
1349
1401
  });
@@ -7,6 +7,7 @@ import { ConfigProvider } from 'antd';
7
7
  import React from 'react';
8
8
  import { beforeEach, describe, expect, it, vi } from 'vitest';
9
9
 
10
+ import { EDIT_FIELD_TYPES } from '../../constants';
10
11
  import { TableContent } from '../content';
11
12
 
12
13
  vi.mock('@akinon/icons', () => ({
@@ -35,6 +36,24 @@ vi.mock('@akinon/ui-input', () => ({
35
36
  )
36
37
  }));
37
38
 
39
+ vi.mock('@akinon/ui-select', () => ({
40
+ Select: ({ value, onChange, rootClassName, options, ...props }: any) => (
41
+ <select
42
+ data-testid="edit-select"
43
+ value={value ?? ''}
44
+ onChange={e => onChange?.(e.target.value)}
45
+ className={rootClassName}
46
+ {...props}
47
+ >
48
+ {options?.map((opt: { label: string; value: string | number }) => (
49
+ <option key={opt.value} value={String(opt.value)}>
50
+ {opt.label}
51
+ </option>
52
+ ))}
53
+ </select>
54
+ )
55
+ }));
56
+
38
57
  vi.mock('@akinon/ui-layout', () => ({
39
58
  Flex: ({ children, ...props }: any) => (
40
59
  <div data-testid="flex" {...props}>
@@ -434,6 +453,7 @@ describe('TableContent', () => {
434
453
 
435
454
  it('should apply collapsed style when not expanded', () => {
436
455
  renderComponent({ expandedRows: [] });
456
+ // Row 2 (pk: 2) has multiple mapper items, so it has the expand button
437
457
  const expandIcons = screen.getAllByTestId('icon-chevron_down');
438
458
  expect(expandIcons[0].className).toContain(
439
459
  'ai-modal-table__icon--collapsed'
@@ -441,8 +461,8 @@ describe('TableContent', () => {
441
461
  });
442
462
 
443
463
  it('should not apply collapsed style when expanded', () => {
444
- renderComponent({ expandedRows: [1] });
445
- // First icon - for row 1
464
+ renderComponent({ expandedRows: [2] });
465
+ // Icon for row 2 (which has multiple mapper items)
446
466
  const icons = screen.getAllByTestId('icon-chevron_down');
447
467
  expect(icons[0].className).not.toContain(
448
468
  'ai-modal-table__icon--collapsed'
@@ -457,9 +477,10 @@ describe('TableContent', () => {
457
477
  expect(screen.queryByTestId('icon-chevron_down')).not.toBeInTheDocument();
458
478
  });
459
479
 
460
- it('should render multiple expand buttons for multiple rows', () => {
480
+ it('should render expand button for rows with multiple mapper items', () => {
461
481
  renderComponent();
462
- expect(screen.getAllByTestId('icon-chevron_down').length).toBe(2);
482
+ // Only row 2 has multiple mapper items (2 items), so only 1 expand button should be rendered
483
+ expect(screen.getAllByTestId('icon-chevron_down').length).toBe(1);
463
484
  });
464
485
  });
465
486
 
@@ -691,8 +712,10 @@ describe('TableContent', () => {
691
712
 
692
713
  it('should render expand button in first column', () => {
693
714
  renderComponent();
694
- const firstRow = screen.getAllByRole('row')[1];
695
- const firstCell = within(firstRow).getAllByRole('cell')[0];
715
+ // Row 2 (index 2) has multiple mapper items, so it has the expand button
716
+ const rows = screen.getAllByRole('row');
717
+ const rowWithExpandButton = rows[2]; // Row 2 (pk: 2) has multiple mapper items
718
+ const firstCell = within(rowWithExpandButton).getAllByRole('cell')[0];
696
719
  expect(firstCell).toContainElement(
697
720
  screen.getAllByTestId('icon-chevron_down')[0]
698
721
  );
@@ -986,13 +1009,14 @@ describe('TableContent', () => {
986
1009
  const expandButtons = screen.getAllByTestId('icon-chevron_down');
987
1010
  fireEvent.click(expandButtons[0]);
988
1011
 
989
- expect(onToggleExpand).toHaveBeenCalledWith(1);
1012
+ // Row 2 (pk: 2) has multiple mapper items and is the one with expand button
1013
+ expect(onToggleExpand).toHaveBeenCalledWith(2);
990
1014
  });
991
1015
 
992
1016
  it('should call onToggleExpand when expand button clicked on expanded row', () => {
993
1017
  const onToggleExpand = vi.fn();
994
1018
  renderComponent({
995
- expandedRows: [1],
1019
+ expandedRows: [2],
996
1020
  onToggleExpand
997
1021
  });
998
1022
 
@@ -1000,7 +1024,8 @@ describe('TableContent', () => {
1000
1024
  fireEvent.click(expandButtons[0]);
1001
1025
 
1002
1026
  // The expand button is a toggle - it should call onToggleExpand to collapse the row
1003
- expect(onToggleExpand).toHaveBeenCalledWith(1);
1027
+ // Row 2 (pk: 2) has multiple mapper items and is the one with expand button
1028
+ expect(onToggleExpand).toHaveBeenCalledWith(2);
1004
1029
  });
1005
1030
 
1006
1031
  it('should call onAddItem with correct rowId and dataIndex when add button clicked', () => {
@@ -1633,5 +1658,48 @@ describe('TableContent', () => {
1633
1658
  const inputs = screen.queryAllByTestId('edit-input');
1634
1659
  expect(inputs.length).toBeGreaterThan(0);
1635
1660
  });
1661
+
1662
+ it('should render Select for editable column when editDataIndexes has SELECT config', async () => {
1663
+ const user = userEvent.setup();
1664
+ const onEdit = vi.fn();
1665
+
1666
+ renderComponent({
1667
+ data: [
1668
+ {
1669
+ pk: 1,
1670
+ name: 'Item 1',
1671
+ status: 'active',
1672
+ mappings: []
1673
+ }
1674
+ ],
1675
+ columns: [
1676
+ { title: 'Name', dataIndex: 'name' },
1677
+ { title: 'Status', dataIndex: 'status' }
1678
+ ],
1679
+ mapperConfig: undefined,
1680
+ onEdit,
1681
+ editDataIndexes: [
1682
+ 'name',
1683
+ {
1684
+ key: 'status',
1685
+ type: EDIT_FIELD_TYPES.SELECT,
1686
+ attributes: {
1687
+ options: [
1688
+ { label: 'Active', value: 'active' },
1689
+ { label: 'Inactive', value: 'inactive' }
1690
+ ]
1691
+ }
1692
+ }
1693
+ ]
1694
+ });
1695
+
1696
+ const editButton = screen.getByTestId('edit-button-1');
1697
+ await user.click(editButton);
1698
+
1699
+ const inputs = screen.queryAllByTestId('edit-input');
1700
+ const selects = screen.queryAllByTestId('edit-select');
1701
+ expect(inputs.length).toBeGreaterThan(0);
1702
+ expect(selects.length).toBeGreaterThan(0);
1703
+ });
1636
1704
  });
1637
1705
  });
@@ -5,7 +5,8 @@ interface TableContentProps extends Omit<TableBaseProps, 'onChangeSelectedRows'
5
5
  expandedRows: Array<number | string>;
6
6
  onToggleExpand: (rowId: number | string) => void;
7
7
  rowKey: string;
8
+ emptyText?: React.ReactNode;
8
9
  }
9
- export declare const TableContent: ({ columns, customActionButtons, data, editDataIndexes, expandedRows, onEdit, onToggleExpand, onToggleSelection, rowKey, selectedRows, mapperConfig }: TableContentProps) => React.JSX.Element;
10
+ export declare const TableContent: ({ columns, customActionButtons, data, editDataIndexes, expandedRows, onEdit, onToggleExpand, onToggleSelection, rowKey, selectedRows, mapperConfig, emptyText }: TableContentProps) => React.JSX.Element;
10
11
  export {};
11
12
  //# sourceMappingURL=content.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../../src/ai-table/components/content.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AAQ9E,UAAU,iBACR,SAAQ,IAAI,CAAC,cAAc,EAAE,sBAAsB,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC3E,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACpD,YAAY,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACrC,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,YAAY,GAAI,sJAY1B,iBAAiB,sBAihBnB,CAAC"}
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../../src/ai-table/components/content.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AAY9E,UAAU,iBACR,SAAQ,IAAI,CAAC,cAAc,EAAE,sBAAsB,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC3E,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACpD,YAAY,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACrC,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC7B;AAED,eAAO,MAAM,YAAY,GAAI,iKAa1B,iBAAiB,sBAuhBnB,CAAC"}