Properties.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import { Theme } from '@mui/material';
  2. import { useContext, useState, useEffect } from 'react';
  3. import AttuGrid from '@/components/grid/Grid';
  4. import { ColDefinitionsType, ToolBarConfig } from '@/components/grid/Types';
  5. import { useTranslation } from 'react-i18next';
  6. import { usePaginationHook } from '@/hooks';
  7. import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
  8. import EditPropertyDialog from '@/pages/dialogs/EditPropertyDialog';
  9. import ResetPropertyDialog from '@/pages/dialogs/ResetPropertyDialog';
  10. import { rootContext } from '@/context';
  11. import { getLabelDisplayedRows } from '@/pages/search/Utils';
  12. import { CollectionFullObject, KeyValuePair } from '@server/types';
  13. import { formatNumber } from '@/utils';
  14. import { makeStyles } from '@mui/styles';
  15. import { DatabaseService } from '@/http';
  16. import { databaseDefaults, collectionDefaults, Property } from '@/consts';
  17. const useStyles = makeStyles((theme: Theme) => ({
  18. wrapper: {
  19. height: `100%`,
  20. },
  21. icon: {
  22. fontSize: '14px',
  23. marginLeft: theme.spacing(0.5),
  24. },
  25. highlight: {
  26. color: theme.palette.primary.main,
  27. backgroundColor: 'transparent',
  28. },
  29. }));
  30. const mergeProperties = (
  31. defaults: Property[],
  32. custom: KeyValuePair[] | undefined
  33. ) => {
  34. return custom
  35. ? defaults.map(i => {
  36. let prop = custom.find(p => p.key === i.key);
  37. return prop ? { ...i, ...prop } : i;
  38. })
  39. : defaults;
  40. };
  41. interface PropertiesProps {
  42. type: 'collection' | 'database';
  43. target?: CollectionFullObject | string;
  44. }
  45. const Properties = (props: PropertiesProps) => {
  46. const { target, type } = props;
  47. const classes = useStyles();
  48. const { t } = useTranslation('properties');
  49. const { t: successTrans } = useTranslation('success');
  50. const { t: btnTrans } = useTranslation('btn');
  51. const { t: commonTrans } = useTranslation();
  52. const gridTrans = commonTrans('grid');
  53. const [properties, setProperties] = useState<Property[]>([]);
  54. const [selected, setSelected] = useState<Property[]>([]);
  55. const { setDialog, openSnackBar } = useContext(rootContext);
  56. // setup properties
  57. const setupProperties = async () => {
  58. let properties: Property[] = [];
  59. switch (type) {
  60. case 'collection':
  61. const collection = target as CollectionFullObject;
  62. if (!collection || !collection.schema) {
  63. return;
  64. }
  65. properties = mergeProperties(collectionDefaults, collection.properties);
  66. break;
  67. case 'database':
  68. const db = await DatabaseService.describeDatabase(target as string);
  69. properties = mergeProperties(databaseDefaults, db.properties);
  70. break;
  71. }
  72. setProperties(properties);
  73. };
  74. useEffect(() => {
  75. setupProperties();
  76. }, [type, target]);
  77. const {
  78. pageSize,
  79. handlePageSize,
  80. currentPage,
  81. handleCurrentPage,
  82. total,
  83. data,
  84. order,
  85. orderBy,
  86. handleGridSort,
  87. } = usePaginationHook(properties);
  88. const toolbarConfigs: ToolBarConfig[] = [
  89. {
  90. icon: 'edit',
  91. type: 'button',
  92. btnVariant: 'text',
  93. btnColor: 'secondary',
  94. onClick: () => {
  95. setDialog({
  96. open: true,
  97. type: 'custom',
  98. params: {
  99. component: (
  100. <EditPropertyDialog
  101. target={target!}
  102. type={type}
  103. property={selected[0]}
  104. cb={() => {
  105. openSnackBar(
  106. successTrans('update', { name: selected[0].key })
  107. );
  108. setupProperties();
  109. }}
  110. />
  111. ),
  112. },
  113. });
  114. },
  115. label: btnTrans('edit'),
  116. disabled: () => selected.length === 0,
  117. },
  118. {
  119. icon: 'reset',
  120. type: 'button',
  121. btnVariant: 'text',
  122. btnColor: 'secondary',
  123. onClick: () => {
  124. setDialog({
  125. open: true,
  126. type: 'custom',
  127. params: {
  128. component: (
  129. <ResetPropertyDialog
  130. target={target!}
  131. type={type}
  132. property={selected[0]}
  133. cb={() => {
  134. openSnackBar(
  135. successTrans('reset', { name: selected[0].key })
  136. );
  137. setupProperties();
  138. }}
  139. />
  140. ),
  141. },
  142. });
  143. },
  144. label: btnTrans('reset'),
  145. disabled: () => selected.length === 0,
  146. },
  147. ];
  148. const colDefinitions: ColDefinitionsType[] = [
  149. {
  150. id: 'key',
  151. notSort: true,
  152. align: 'left',
  153. disablePadding: false,
  154. label: t('property'),
  155. needCopy: true,
  156. getStyle: () => {
  157. return {
  158. minWidth: 150,
  159. };
  160. },
  161. },
  162. {
  163. id: 'value',
  164. align: 'left',
  165. disablePadding: false,
  166. label: t('value'),
  167. formatter: (obj: Property) => {
  168. if (obj.value === '') {
  169. return '-';
  170. } else {
  171. return obj.type === 'number' ? formatNumber(obj.value) : obj.value;
  172. }
  173. },
  174. getStyle: () => {
  175. return {
  176. minWidth: 450,
  177. };
  178. },
  179. },
  180. ];
  181. const handleSelectChange = (value: Property[]) => {
  182. // only select one row, filter out the rest
  183. if (value.length > 1) {
  184. value = [value[value.length - 1]];
  185. }
  186. setSelected(value);
  187. };
  188. const handlePageChange = (e: any, page: number) => {
  189. handleCurrentPage(page);
  190. setSelected([]);
  191. };
  192. // collection is not found or collection full object is not ready
  193. if (!properties || properties.length === 0) {
  194. return <StatusIcon type={LoadingType.CREATING} />;
  195. }
  196. return (
  197. <section className={classes.wrapper}>
  198. <AttuGrid
  199. toolbarConfigs={toolbarConfigs}
  200. colDefinitions={colDefinitions}
  201. rows={data}
  202. rowCount={total}
  203. primaryKey="key"
  204. selected={selected}
  205. setSelected={handleSelectChange}
  206. page={currentPage}
  207. onPageChange={handlePageChange}
  208. rowsPerPage={pageSize}
  209. setRowsPerPage={handlePageSize}
  210. isLoading={false}
  211. order={order}
  212. orderBy={orderBy}
  213. handleSort={handleGridSort}
  214. labelDisplayedRows={getLabelDisplayedRows(
  215. gridTrans[data.length > 1 ? 'properties' : 'property']
  216. )}
  217. />
  218. </section>
  219. );
  220. };
  221. export default Properties;