@kenyaemr/esm-admin-app 5.4.4-pre.426 → 5.4.4-pre.428

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 (71) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/1442.js +1 -0
  3. package/dist/1442.js.map +1 -0
  4. package/dist/1462.js +1 -1
  5. package/dist/1972.js +1 -1
  6. package/dist/2016.js +1 -1
  7. package/dist/2270.js +1 -1
  8. package/dist/2270.js.map +1 -1
  9. package/dist/2294.js +1 -1
  10. package/dist/2294.js.map +1 -1
  11. package/dist/2467.js +1 -1
  12. package/dist/2467.js.map +1 -1
  13. package/dist/2948.js +1 -1
  14. package/dist/3380.js +1 -1
  15. package/dist/3380.js.map +1 -1
  16. package/dist/3548.js +1 -1
  17. package/dist/3816.js +1 -1
  18. package/dist/4337.js +1 -1
  19. package/dist/4858.js +1 -1
  20. package/dist/487.js +1 -1
  21. package/dist/5910.js +1 -0
  22. package/dist/5910.js.map +1 -0
  23. package/dist/6253.js +1 -0
  24. package/dist/6253.js.map +1 -0
  25. package/dist/6455.js +1 -0
  26. package/dist/6455.js.map +1 -0
  27. package/dist/6456.js +1 -1
  28. package/dist/6925.js +1 -0
  29. package/dist/6925.js.map +1 -0
  30. package/dist/7607.js +1 -1
  31. package/dist/7737.js +1 -1
  32. package/dist/7739.js +1 -1
  33. package/dist/8376.js +1 -1
  34. package/dist/8727.js +1 -1
  35. package/dist/9182.js +1 -1
  36. package/dist/9446.js +1 -1
  37. package/dist/9647.js +1 -1
  38. package/dist/kenyaemr-esm-admin-app.js +3 -3
  39. package/dist/kenyaemr-esm-admin-app.js.buildmanifest.json +157 -208
  40. package/dist/kenyaemr-esm-admin-app.js.map +1 -1
  41. package/dist/main.js +3 -3
  42. package/dist/main.js.map +1 -1
  43. package/dist/routes.json +1 -1
  44. package/package.json +1 -1
  45. package/src/components/global-property/table/global-property-table.component.tsx +125 -117
  46. package/src/components/global-property/table/global-property-table.scss +0 -10
  47. package/src/components/global-property/table/global-property-table.test.tsx +26 -30
  48. package/src/index.ts +0 -4
  49. package/src/routes.json +0 -5
  50. package/translations/am.json +5 -22
  51. package/translations/en.json +8 -25
  52. package/translations/fr.json +5 -22
  53. package/translations/sw.json +5 -22
  54. package/dist/235.js +0 -1
  55. package/dist/235.js.map +0 -1
  56. package/dist/2763.js +0 -1
  57. package/dist/2763.js.map +0 -1
  58. package/dist/3852.js +0 -1
  59. package/dist/3852.js.map +0 -1
  60. package/dist/4157.js +0 -1
  61. package/dist/4157.js.map +0 -1
  62. package/dist/552.js +0 -1
  63. package/dist/552.js.map +0 -1
  64. package/dist/6092.js +0 -1
  65. package/dist/6092.js.map +0 -1
  66. package/dist/9406.js +0 -1
  67. package/dist/9406.js.map +0 -1
  68. package/src/components/global-property/hooks/useLogoUpload.ts +0 -28
  69. package/src/components/global-property/workspace/upload-logo.workspace.scss +0 -61
  70. package/src/components/global-property/workspace/upload-logo.workspace.test.tsx +0 -180
  71. package/src/components/global-property/workspace/upload-logo.workspace.tsx +0 -191
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemrCharts":"^1.6.7"},"extensions":[{"component":"adminLeftPanelLink","name":"admin-left-panel-link","slot":"admin-left-panel-slot"},{"component":"userManagementLeftPannelLink","name":"user-management-left-panel-link","slot":"admin-left-panel-slot"},{"component":"etlAdministrationLeftPannelLink","name":"etl-administration-left-panel-link","slot":"admin-left-panel-slot"},{"component":"locationsLeftPanelLink","name":"locations-left-panel-link","slot":"admin-left-panel-slot"},{"component":"facilitySetupLeftPanelLink","name":"facility-setup-left-panel-link","slot":"admin-left-panel-slot"},{"name":"global-property-link","component":"globalPropertyLink","slot":"admin-left-panel-slot"},{"component":"providerBanner","name":"provider-banner","slot":"provider-banner-info-slot","order":1},{"component":"globalPropertyDashboard","name":"global-property-dashboard"}],"modals":[{"component":"operationConfirmationModal","name":"operation-confirmation-modal"},{"component":"hwrConfirmationModal","name":"hwr-confirmation-modal"},{"component":"hwrEmptyModal","name":"hwr-empty-modal"},{"component":"hwrSyncModal","name":"hwr-syncing-modal"},{"component":"deleteGlobalPropertyModal","name":"delete-global-property-modal"}],"workspaces2":[{"name":"manage-user-workspace","component":"manageUserWorkspace","window":"esm-admin-extra-wide-workspace-window"},{"name":"user-role-scope-workspace","component":"userRoleScopeWorkspace","window":"esm-admin-workspace-window"},{"name":"add-location-workspace","component":"addLocation","window":"esm-admin-workspace-window"},{"name":"search-location-workspace","component":"searchLocationWorkspace","window":"esm-admin-workspace-window"},{"name":"global-property-workspace","component":"globalPropertyWorkspace","window":"esm-admin-workspace-window"},{"name":"upload-logo-workspace","component":"uploadLogoWorkspace","window":"esm-admin-workspace-window"}],"workspaceWindows2":[{"name":"esm-admin-workspace-window","canMaximize":true,"group":"esm-admin-workspace-group","width":"wider"},{"name":"esm-admin-extra-wide-workspace-window","canMaximize":true,"group":"esm-admin-workspace-group","width":"extra-wide"}],"workspaceGroups2":[{"name":"esm-admin-workspace-group","scopePattern":"/admin","closeable":true}],"pages":[{"component":"root","route":"admin"}],"version":"5.4.4-pre.426"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemrCharts":"^1.6.7"},"extensions":[{"component":"adminLeftPanelLink","name":"admin-left-panel-link","slot":"admin-left-panel-slot"},{"component":"userManagementLeftPannelLink","name":"user-management-left-panel-link","slot":"admin-left-panel-slot"},{"component":"etlAdministrationLeftPannelLink","name":"etl-administration-left-panel-link","slot":"admin-left-panel-slot"},{"component":"locationsLeftPanelLink","name":"locations-left-panel-link","slot":"admin-left-panel-slot"},{"component":"facilitySetupLeftPanelLink","name":"facility-setup-left-panel-link","slot":"admin-left-panel-slot"},{"name":"global-property-link","component":"globalPropertyLink","slot":"admin-left-panel-slot"},{"component":"providerBanner","name":"provider-banner","slot":"provider-banner-info-slot","order":1},{"component":"globalPropertyDashboard","name":"global-property-dashboard"}],"modals":[{"component":"operationConfirmationModal","name":"operation-confirmation-modal"},{"component":"hwrConfirmationModal","name":"hwr-confirmation-modal"},{"component":"hwrEmptyModal","name":"hwr-empty-modal"},{"component":"hwrSyncModal","name":"hwr-syncing-modal"},{"component":"deleteGlobalPropertyModal","name":"delete-global-property-modal"}],"workspaces2":[{"name":"manage-user-workspace","component":"manageUserWorkspace","window":"esm-admin-extra-wide-workspace-window"},{"name":"user-role-scope-workspace","component":"userRoleScopeWorkspace","window":"esm-admin-workspace-window"},{"name":"add-location-workspace","component":"addLocation","window":"esm-admin-workspace-window"},{"name":"search-location-workspace","component":"searchLocationWorkspace","window":"esm-admin-workspace-window"},{"name":"global-property-workspace","component":"globalPropertyWorkspace","window":"esm-admin-workspace-window"}],"workspaceWindows2":[{"name":"esm-admin-workspace-window","canMaximize":true,"group":"esm-admin-workspace-group","width":"wider"},{"name":"esm-admin-extra-wide-workspace-window","canMaximize":true,"group":"esm-admin-workspace-group","width":"extra-wide"}],"workspaceGroups2":[{"name":"esm-admin-workspace-group","scopePattern":"/admin","closeable":true}],"pages":[{"component":"root","route":"admin"}],"version":"5.4.4-pre.428"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-admin-app",
3
- "version": "5.4.4-pre.426",
3
+ "version": "5.4.4-pre.428",
4
4
  "description": "Facilitates the management of ETL tables",
5
5
  "keywords": [
6
6
  "openmrs"
@@ -2,25 +2,28 @@ import React, { useCallback, useMemo, useState } from 'react';
2
2
  import {
3
3
  Button,
4
4
  DataTable,
5
- OverflowMenu,
6
- OverflowMenuItem,
5
+ DataTableSkeleton,
7
6
  Pagination,
7
+ Search,
8
8
  Table,
9
9
  TableBody,
10
10
  TableCell,
11
- TableContainer,
12
11
  TableHead,
13
12
  TableHeader,
14
13
  TableRow,
15
- TableToolbar,
16
- TableToolbarContent,
17
- TableToolbarSearch,
18
- Tag,
19
14
  type DataTableHeader,
20
15
  } from '@carbon/react';
21
- import { Add, Upload } from '@carbon/react/icons';
16
+ import { Add, Edit, TrashCan } from '@carbon/react/icons';
22
17
  import { useTranslation } from 'react-i18next';
23
- import { ErrorCard, launchWorkspace2, showModal, useDebounce, usePaginationInfo } from '@openmrs/esm-framework';
18
+ import {
19
+ ErrorCard,
20
+ isDesktop,
21
+ launchWorkspace2,
22
+ showModal,
23
+ useDebounce,
24
+ useLayoutType,
25
+ usePaginationInfo,
26
+ } from '@openmrs/esm-framework';
24
27
 
25
28
  import { useGlobalProperties } from '../hooks/useGlobalProperty';
26
29
  import styles from './global-property-table.scss';
@@ -36,12 +39,15 @@ type GlobalPropertyRow = {
36
39
 
37
40
  const GlobalPropertyTable: React.FC = () => {
38
41
  const { t } = useTranslation();
42
+ const layoutType = useLayoutType();
43
+ const desktop = isDesktop(layoutType);
39
44
 
40
45
  const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE);
41
46
  const [searchTerm, setSearchTerm] = useState('');
42
47
  const debouncedSearchTerm = useDebounce(searchTerm, 300);
43
48
 
44
49
  const {
50
+ isLoading,
45
51
  data: globalProperties = [],
46
52
  error,
47
53
  goTo,
@@ -60,7 +66,7 @@ const GlobalPropertyTable: React.FC = () => {
60
66
  [t],
61
67
  );
62
68
 
63
- const tableRows: Array<GlobalPropertyRow> = useMemo(
69
+ const rows: Array<GlobalPropertyRow> = useMemo(
64
70
  () =>
65
71
  globalProperties.map((gp, idx) => ({
66
72
  id: gp?.uuid ?? `gp-${idx}`,
@@ -71,9 +77,8 @@ const GlobalPropertyTable: React.FC = () => {
71
77
  );
72
78
 
73
79
  const handleSearchChange = useCallback(
74
- (event: React.ChangeEvent<HTMLInputElement> | '', value?: string) => {
75
- const searchValue = typeof event === 'string' ? value ?? '' : event.target.value;
76
- setSearchTerm(searchValue);
80
+ (event: React.ChangeEvent<HTMLInputElement>) => {
81
+ setSearchTerm(event.target.value);
77
82
  if (currentPage !== 1) {
78
83
  goTo(1);
79
84
  }
@@ -101,12 +106,6 @@ const GlobalPropertyTable: React.FC = () => {
101
106
  [globalProperties, mutate],
102
107
  );
103
108
 
104
- const openUploadImageWorkspace = useCallback(() => {
105
- launchWorkspace2('upload-logo-workspace', {
106
- mutateGlobalProperty: mutate,
107
- });
108
- }, [mutate]);
109
-
110
109
  const handleEdit = useCallback(
111
110
  (row: GlobalPropertyRow) => {
112
111
  const systemSetting = globalProperties.find((gp) => gp.uuid === row.id);
@@ -127,6 +126,95 @@ const GlobalPropertyTable: React.FC = () => {
127
126
  [mutate],
128
127
  );
129
128
 
129
+ const renderContent = () => {
130
+ if (isLoading) {
131
+ return (
132
+ <DataTableSkeleton
133
+ aria-label={t('globalProperties', 'Global properties')}
134
+ headers={headers}
135
+ showHeader
136
+ showToolbar
137
+ />
138
+ );
139
+ }
140
+
141
+ if (rows.length === 0) {
142
+ return (
143
+ <p className={styles.emptyState}>
144
+ {debouncedSearchTerm
145
+ ? t('noMatchingGlobalProperties', 'No global properties match your search')
146
+ : t('noGlobalProperties', 'No global properties to display')}
147
+ </p>
148
+ );
149
+ }
150
+
151
+ return (
152
+ <>
153
+ <DataTable useZebraStyles size={desktop ? 'sm' : 'md'} rows={rows} headers={headers}>
154
+ {({ rows: renderRows, headers: renderHeaders, getTableProps, getHeaderProps, getRowProps, getCellProps }) => (
155
+ <Table {...getTableProps()}>
156
+ <TableHead>
157
+ <TableRow>
158
+ {renderHeaders.map((header) => (
159
+ <TableHeader {...getHeaderProps({ header })}>{header.header}</TableHeader>
160
+ ))}
161
+ <TableHeader>
162
+ <span className={styles.visuallyHidden}>{t('actions', 'Actions')}</span>
163
+ </TableHeader>
164
+ </TableRow>
165
+ </TableHead>
166
+ <TableBody>
167
+ {renderRows.map((row) => {
168
+ const sourceRow = rows.find((r) => r.id === row.id)!;
169
+ return (
170
+ <TableRow {...getRowProps({ row })}>
171
+ {row.cells.map((cell) => (
172
+ <TableCell {...getCellProps({ cell })}>{cell.value}</TableCell>
173
+ ))}
174
+ <TableCell className={styles.actionsCell}>
175
+ <Button
176
+ kind="ghost"
177
+ size="sm"
178
+ renderIcon={Edit}
179
+ iconDescription={t('edit', 'Edit')}
180
+ hasIconOnly
181
+ onClick={() => handleEdit(sourceRow)}
182
+ />
183
+ <Button
184
+ kind="danger--ghost"
185
+ size="sm"
186
+ renderIcon={TrashCan}
187
+ iconDescription={t('delete', 'Delete')}
188
+ hasIconOnly
189
+ onClick={() => handleDelete(sourceRow)}
190
+ />
191
+ </TableCell>
192
+ </TableRow>
193
+ );
194
+ })}
195
+ </TableBody>
196
+ </Table>
197
+ )}
198
+ </DataTable>
199
+
200
+ <Pagination
201
+ itemsPerPageText={t('itemsPerPage', 'Items per page:')}
202
+ forwardText={t('nextPage', 'Next page')}
203
+ backwardText={t('previousPage', 'Previous page')}
204
+ itemRangeText={(min, max, total) =>
205
+ t('minMaxItems', '{{min}}-{{max}} of {{total}} items', { min, max, total })
206
+ }
207
+ pageRangeText={(_current, total) => t('pageRangeText', 'of {{count}} pages', { count: total })}
208
+ page={currentPage}
209
+ pageSize={pageSize}
210
+ pageSizes={pageSizes?.length > 0 ? pageSizes : PAGE_SIZE_OPTIONS}
211
+ totalItems={totalCount ?? 0}
212
+ onChange={handlePaginationChange}
213
+ />
214
+ </>
215
+ );
216
+ };
217
+
130
218
  if (error) {
131
219
  return (
132
220
  <div className={styles.dataTableContainer}>
@@ -136,104 +224,24 @@ const GlobalPropertyTable: React.FC = () => {
136
224
  }
137
225
 
138
226
  return (
139
- <div className={styles.container}>
140
- <DataTable size="sm" rows={tableRows} headers={headers} isSortable useZebraStyles>
141
- {({
142
- rows,
143
- headers,
144
- getHeaderProps,
145
- getRowProps,
146
- getBatchActionProps,
147
- getToolbarProps,
148
- getTableProps,
149
- getTableContainerProps,
150
- }) => {
151
- const batchActionProps = getBatchActionProps();
152
-
153
- return (
154
- <TableContainer
155
- title={t('globalProperty', 'Global Property')}
156
- description={t(
157
- 'globalPropertyDescription',
158
- 'A list of all global properties for the system. Filter by search term to find specific properties.',
159
- )}
160
- {...getTableContainerProps()}>
161
- <TableToolbar {...getToolbarProps()}>
162
- <TableToolbarContent aria-hidden={batchActionProps.shouldShowBatchActions}>
163
- <TableToolbarSearch
164
- persistent
165
- onChange={handleSearchChange}
166
- placeholder={t('searchForGlobalProperties', 'Search for global properties')}
167
- />
168
- <Button renderIcon={Add} onClick={() => openWorkspace()} size="sm" kind="primary">
169
- {t('addGlobalProperty', 'Add global property')}
170
- </Button>
171
- <Button renderIcon={Upload} onClick={openUploadImageWorkspace} size="sm" kind="tertiary">
172
- {t('uploadImage', 'Upload image')}
173
- </Button>
174
- </TableToolbarContent>
175
- </TableToolbar>
176
-
177
- <Table {...getTableProps()} aria-label="Global properties">
178
- <TableHead>
179
- <TableRow>
180
- {headers.map((header) => (
181
- <TableHeader {...getHeaderProps({ header })}>{header.header}</TableHeader>
182
- ))}
183
- <TableHeader aria-label={t('rowActions', 'Row actions')} />
184
- </TableRow>
185
- </TableHead>
186
-
187
- <TableBody>
188
- {rows.map((row, index) => {
189
- return (
190
- <React.Fragment key={row.id}>
191
- <TableRow {...getRowProps({ row })}>
192
- {row.cells.map((cell) => {
193
- if (cell.info.header === 'status') {
194
- return (
195
- <TableCell key={cell.id}>
196
- <Tag size="sm">{cell.value}</Tag>
197
- </TableCell>
198
- );
199
- }
200
- return <TableCell key={cell.id}>{cell.value}</TableCell>;
201
- })}
202
- <TableCell className="cds--table-column-menu">
203
- <OverflowMenu flipped aria-label="overflow-menu">
204
- <OverflowMenuItem
205
- onClick={() => handleEdit(tableRows[index])}
206
- itemText={t('edit', 'Edit')}
207
- />
208
- <OverflowMenuItem
209
- isDelete
210
- onClick={() => handleDelete(tableRows[index])}
211
- itemText={t('delete', 'Delete')}
212
- />
213
- </OverflowMenu>
214
- </TableCell>
215
- </TableRow>
216
- </React.Fragment>
217
- );
218
- })}
219
- </TableBody>
220
- </Table>
221
- </TableContainer>
222
- );
223
- }}
224
- </DataTable>
225
- <Pagination
226
- itemsPerPageText={t('itemsPerPage', 'Items per page:')}
227
- forwardText={t('nextPage', 'Next page')}
228
- backwardText={t('previousPage', 'Previous page')}
229
- itemRangeText={(min, max, total) => t('minMaxItems', '{{min}}-{{max}} of {{total}} items', { min, max, total })}
230
- pageRangeText={(_current, total) => t('pageRangeText', 'of {{count}} pages', { count: total })}
231
- page={currentPage}
232
- pageSize={pageSize}
233
- pageSizes={pageSizes?.length > 0 ? pageSizes : PAGE_SIZE_OPTIONS}
234
- totalItems={totalCount ?? 0}
235
- onChange={handlePaginationChange}
236
- />
227
+ <div className={styles.dataTableContainer}>
228
+ <div className={styles.tableHeaderSection}>
229
+ <Search
230
+ id="global-property-search"
231
+ labelText=""
232
+ placeholder={t('searchGlobalPropertiesByName', 'Search global property by name')}
233
+ closeButtonLabelText={t('clearSearchButton', 'Clear search button')}
234
+ size={desktop ? 'md' : 'lg'}
235
+ value={searchTerm}
236
+ onChange={handleSearchChange}
237
+ type="search"
238
+ />
239
+ <Button size={desktop ? 'md' : 'lg'} kind="ghost" renderIcon={Add} onClick={() => openWorkspace()}>
240
+ {t('addGlobalProperty', 'Add new global property')}
241
+ </Button>
242
+ </div>
243
+
244
+ {renderContent()}
237
245
  </div>
238
246
  );
239
247
  };
@@ -1,5 +1,4 @@
1
1
  @use '@carbon/layout';
2
- @use '@carbon/colors';
3
2
 
4
3
  .dataTableContainer {
5
4
  height: 100%;
@@ -33,12 +32,3 @@
33
32
  text-align: center;
34
33
  color: var(--cds-text-secondary);
35
34
  }
36
-
37
- .container {
38
- margin: layout.$layout-01;
39
- border: 1px solid colors.$gray-20;
40
-
41
- :global(.cds--table-toolbar) {
42
- position: relative !important;
43
- }
44
- }
@@ -52,9 +52,6 @@ vi.mock('@carbon/react', async (importOriginal) => {
52
52
  getHeaderProps: ({ header }: any) => ({ key: header.key }),
53
53
  getRowProps: ({ row }: any) => ({ key: row.id }),
54
54
  getCellProps: ({ cell }: any) => ({ key: cell.id }),
55
- getToolbarProps: () => ({}),
56
- getTableContainerProps: () => ({}),
57
- getBatchActionProps: () => ({ shouldShowBatchActions: false }),
58
55
  });
59
56
  }
60
57
  return children;
@@ -68,8 +65,6 @@ vi.mock('@carbon/react', async (importOriginal) => {
68
65
  {hasIconOnly ? null : children}
69
66
  </button>
70
67
  ),
71
- OverflowMenu: ({ children }: any) => <div>{children}</div>,
72
- OverflowMenuItem: ({ itemText, onClick }: any) => <button onClick={onClick}>{itemText}</button>,
73
68
  };
74
69
  });
75
70
 
@@ -102,6 +97,18 @@ describe('GlobalPropertyTable', () => {
102
97
  vi.clearAllMocks();
103
98
  });
104
99
 
100
+ it('shows a loading skeleton while data is loading', () => {
101
+ setupMock({ isLoading: true, data: [] });
102
+ render(<GlobalPropertyTable />);
103
+ expect(screen.getByRole('table')).toBeInTheDocument();
104
+ });
105
+
106
+ it('shows empty state message when no properties exist', () => {
107
+ setupMock({ data: [] });
108
+ render(<GlobalPropertyTable />);
109
+ expect(screen.getByText('No global properties to display')).toBeInTheDocument();
110
+ });
111
+
105
112
  it('renders the table with property and value columns', () => {
106
113
  setupMock();
107
114
  render(<GlobalPropertyTable />);
@@ -118,17 +125,10 @@ describe('GlobalPropertyTable', () => {
118
125
  expect(screen.getByText('value2')).toBeInTheDocument();
119
126
  });
120
127
 
121
- it('renders the table without data rows when no properties exist', () => {
122
- setupMock({ data: [], totalCount: 0 });
123
- render(<GlobalPropertyTable />);
124
- expect(screen.getByRole('table')).toBeInTheDocument();
125
- expect(screen.queryByText('setting.one')).not.toBeInTheDocument();
126
- });
127
-
128
- it('opens the add workspace when "Add global property" button is clicked', () => {
128
+ it('opens the add workspace when "Add new global property" button is clicked', () => {
129
129
  setupMock();
130
130
  render(<GlobalPropertyTable />);
131
- fireEvent.click(screen.getByText('Add global property'));
131
+ fireEvent.click(screen.getByText('Add new global property'));
132
132
  expect(mockLaunchWorkspace2).toHaveBeenCalledWith(
133
133
  'global-property-workspace',
134
134
  expect.objectContaining({
@@ -138,18 +138,6 @@ describe('GlobalPropertyTable', () => {
138
138
  );
139
139
  });
140
140
 
141
- it('opens the upload image workspace when "Upload image" button is clicked', () => {
142
- setupMock();
143
- render(<GlobalPropertyTable />);
144
- fireEvent.click(screen.getByText('Upload image'));
145
- expect(mockLaunchWorkspace2).toHaveBeenCalledWith(
146
- 'upload-logo-workspace',
147
- expect.objectContaining({
148
- mutateGlobalProperty: mockMutate,
149
- }),
150
- );
151
- });
152
-
153
141
  it('opens the edit workspace with the correct property when edit is clicked', () => {
154
142
  setupMock();
155
143
  render(<GlobalPropertyTable />);
@@ -180,17 +168,19 @@ describe('GlobalPropertyTable', () => {
180
168
  it('filters results and resets to page 1 when user types in the search box', async () => {
181
169
  setupMock({ currentPage: 2 });
182
170
  render(<GlobalPropertyTable />);
183
- const searchInput = screen.getByPlaceholderText('Search for global properties');
171
+ const searchInput = screen.getByPlaceholderText('Search global property by name');
184
172
  fireEvent.change(searchInput, { target: { value: 'setting' } });
185
173
  await waitFor(() => {
186
174
  expect(mockGoTo).toHaveBeenCalledWith(1);
187
175
  });
188
176
  });
189
177
 
190
- it('renders a search input for filtering properties', () => {
191
- setupMock();
178
+ it('shows "no matching" message when search yields no results', () => {
179
+ setupMock({ data: [] });
192
180
  render(<GlobalPropertyTable />);
193
- expect(screen.getByPlaceholderText('Search for global properties')).toBeInTheDocument();
181
+ const searchInput = screen.getByPlaceholderText('Search global property by name');
182
+ fireEvent.change(searchInput, { target: { value: 'nonexistent' } });
183
+ expect(screen.getByText('No global properties match your search')).toBeInTheDocument();
194
184
  });
195
185
 
196
186
  it('renders an error card when the hook returns an error', () => {
@@ -199,4 +189,10 @@ describe('GlobalPropertyTable', () => {
199
189
  expect(screen.getByTestId('error-card')).toBeInTheDocument();
200
190
  expect(screen.getByText('Global property')).toBeInTheDocument();
201
191
  });
192
+
193
+ it('renders a search input for filtering properties', () => {
194
+ setupMock();
195
+ render(<GlobalPropertyTable />);
196
+ expect(screen.getByPlaceholderText('Search global property by name')).toBeInTheDocument();
197
+ });
202
198
  });
package/src/index.ts CHANGED
@@ -80,10 +80,6 @@ export const globalPropertyWorkspace = getAsyncLifecycle(
80
80
  () => import('./components/global-property/workspace/global-property.workspace'),
81
81
  options,
82
82
  );
83
- export const uploadLogoWorkspace = getAsyncLifecycle(
84
- () => import('./components/global-property/workspace/upload-logo.workspace'),
85
- options,
86
- );
87
83
  export const deleteGlobalPropertyModal = getAsyncLifecycle(
88
84
  () => import('./components/global-property/modal/delete-global-property-modal.component'),
89
85
  options,
package/src/routes.json CHANGED
@@ -92,11 +92,6 @@
92
92
  "name": "global-property-workspace",
93
93
  "component": "globalPropertyWorkspace",
94
94
  "window": "esm-admin-workspace-window"
95
- },
96
- {
97
- "name": "upload-logo-workspace",
98
- "component": "uploadLogoWorkspace",
99
- "window": "esm-admin-workspace-window"
100
95
  }
101
96
  ],
102
97
  "workspaceWindows2": [
@@ -5,7 +5,6 @@
5
5
  "activeFrom": "ከዚህ ቀን ጀምሮ ገባሪ",
6
6
  "activeTo": "እስከዚህ ቀን ገባሪ",
7
7
  "addAnotherRoleScope": "Add user role scope",
8
- "addFile": "Add file",
9
8
  "addGlobalProperty": "Add new global property",
10
9
  "addLocation": "ቦታ ያክሉ",
11
10
  "addRoleScope": "Add a new user role scope",
@@ -19,6 +18,7 @@
19
18
  "chooseIdentifierType": "Choose identifier type",
20
19
  "chooseRegulator": "Choose regulator",
21
20
  "chooseRegulatorType": "Choose regulator option",
21
+ "clearSearchButton": "Clear search button",
22
22
  "completionStatus": "የማጠናቀቂያ ሁኔታ",
23
23
  "confirmation": "ማረጋገጫ",
24
24
  "contact": "Contact",
@@ -91,8 +91,8 @@
91
91
  "generalInformation": "አጠቃላይ መረጃ",
92
92
  "givenName": "Given Name",
93
93
  "givenNameRequired": "Given name is required",
94
+ "globalProperties": "Global properties",
94
95
  "globalProperty": "Global property",
95
- "globalPropertyDescription": "A list of all global properties for the system. Filter by search term to find specific properties.",
96
96
  "globalPropertyError": "Global property",
97
97
  "gpCreated": "Global property {{property}} was created successfully.",
98
98
  "gpDatatypeConfigPlaceholder": "Optional datatype configuration",
@@ -125,11 +125,7 @@
125
125
  "identifierNumber": "Identifier number*",
126
126
  "identifierProvider": "መለያ:",
127
127
  "identity": "Identity",
128
- "image": "Image",
129
- "imagePreview": "Image preview",
130
- "imageTooLarge": "File exceeds the 2 MB maximum size.",
131
128
  "inactive": "Inactive",
132
- "invalidImage": "Invalid image",
133
129
  "itemsPerPage": "Items per page:",
134
130
  "kephLevel": "የ Keph ደረጃ",
135
131
  "lastSynced": "Last synced",
@@ -161,12 +157,6 @@
161
157
  "locationUpdated": "Location {{locationName}} was updated successfully.",
162
158
  "loginInfo": "Login Info",
163
159
  "loginInformation": "Login Info",
164
- "logoTarget": "Logo destination",
165
- "logoUploadDesc": "Upload a logo used in printed documents. JPEG, PNG, GIF, BMP or WebP, up to 2 MB.",
166
- "logoUploaded": "Image uploaded successfully to {{savedPath}}",
167
- "logoUploaderHint": "Max file size is 2 MB. Supported: JPEG, PNG, GIF, BMP, WebP.",
168
- "logoUploadError": "Error uploading image",
169
- "logoUploadTitle": "Printed documents logo",
170
160
  "male": "Male",
171
161
  "manageUserRoleScope": "የተጠቃሚ ሚና ስፋትን አስተዳድር",
172
162
  "manageUsers": "Manage Users",
@@ -183,7 +173,9 @@
183
173
  "noContractedServices": "No contracted services on record for this facility.",
184
174
  "noData": "የሚታይ መረጃ የለም",
185
175
  "noDescriptionAvailable": "ምንም መግለጫ አይገኝም",
176
+ "noGlobalProperties": "No global properties to display",
186
177
  "noHwrApi": "የጤና እንክብካቤ ሰራተኛ መመዝገቢያ API መረጃዎች አልተዋቀሩም፣ እባክዎ የስርዓት አስተዳዳሪን ያግኙ። አካውንት መፍጠር መቀጠል ይፈልጋሉ",
178
+ "noMatchingGlobalProperties": "No global properties match your search",
187
179
  "noMatchingUsers": "ተዛማጅ ተጠቃሚዎች አልተገኙም",
188
180
  "noRecordsFound": "ምንም የETL ክንውን ምዝግብ ማስታወሻዎች አልተገኙም",
189
181
  "noRespond": "አይ",
@@ -212,8 +204,6 @@
212
204
  "practiceTypePlaceholder": "e.g. Clinical Practice",
213
205
  "practitioner": "Practitioner",
214
206
  "preferredHandlerClassname": "Preferred handler classname",
215
- "prescriptionLogo": "Prescription logo",
216
- "preview": "Preview",
217
207
  "previousPage": "የቀድሞ ገጽ",
218
208
  "procedure": "ሥነ-ሥርዓት",
219
209
  "professionalCadre": "Professional Cadre",
@@ -236,7 +226,6 @@
236
226
  "pullDetailsfromHWR": "Pulling data from Health worker registry...",
237
227
  "qualification": "Qualification",
238
228
  "qualificationPlaceholder": "e.g. MBChB(UON)2009",
239
- "receiptLogo": "Receipt logo",
240
229
  "recreated": "በድጋሚ ተፈጥሯል",
241
230
  "recreateDatatools": "የውሂብ መሳሪያዎችን በድጋሚ ፍጠር",
242
231
  "recreateFacilityWideTables": "የተቋም-ሰፊ ሰንጠረዦችን በድጋሚ ፍጠር",
@@ -256,19 +245,17 @@
256
245
  "role": "ሚና",
257
246
  "roles": "Roles Info",
258
247
  "rolesInfo": "Roles Info",
259
- "rowActions": "Row actions",
260
248
  "saveAndClose": "Save & close",
261
249
  "search": "ቦታ ፈልግ",
262
250
  "searchFailed": "Search failed",
263
- "searchForGlobalProperties": "Search for global properties",
264
251
  "searchForLocation": "Search for location",
265
252
  "searchForUsers": "ተጠቃሚ ፈልግ",
253
+ "searchGlobalPropertiesByName": "Search global property by name",
266
254
  "searchLocation": "Search Location",
267
255
  "searchNoResults": "ምንም ተዛማጅ ውጤቶች አልተገኙም",
268
256
  "searchNoResultsHelper": "የተለየ ቃል ለመፈለግ ይሞክሩ",
269
257
  "searchParentLocation": "Search for location...",
270
258
  "selectDatatypeClassname": "Select datatype classname",
271
- "selectImageFirst": "Please select an image to upload.",
272
259
  "selectTagPlaceholder": "Select a tag",
273
260
  "selectTags": "Select tag(s)",
274
261
  "sex": "Sex",
@@ -301,11 +288,7 @@
301
288
  "unknownError": "የጤና ሰራተኛ መመዝገቢያን በሚፈልጉበት ጊዜ ያልታወቀ ስህተት ተከስቷል፣ እባክዎ የስርዓት አስተዳዳሪን ያግኙ። አካውንት መፍጠር መቀጠል ይፈልጋሉ",
302
289
  "unlicensed": "ፈቃድ የሌለው",
303
290
  "Unlicensed": "ፈቃድ የሌለው",
304
- "unsupportedImageType": "Unsupported file type. Accepted: JPEG, PNG, GIF, BMP or WebP.",
305
291
  "updateMessage": "Provider updated successfully",
306
- "upload": "Upload",
307
- "uploadImage": "Upload image",
308
- "uploading": "Uploading...",
309
292
  "userCreationFailedSubtitle": "An error occurred while creating user {{errorMessage}}",
310
293
  "userGivenName": "Enter Given Name",
311
294
  "userManagement": "የተጠቃሚ አስተዳደር",