@proteinjs/db-ui 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 (60) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -0
  3. package/dist/generated/index.d.ts +15 -0
  4. package/dist/generated/index.d.ts.map +1 -0
  5. package/dist/generated/index.js +53 -0
  6. package/dist/generated/index.js.map +1 -0
  7. package/dist/index.d.ts +5 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +21 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/src/form/RecordForm.d.ts +8 -0
  12. package/dist/src/form/RecordForm.d.ts.map +1 -0
  13. package/dist/src/form/RecordForm.js +232 -0
  14. package/dist/src/form/RecordForm.js.map +1 -0
  15. package/dist/src/form/RecordFormCustomization.d.ts +10 -0
  16. package/dist/src/form/RecordFormCustomization.d.ts.map +1 -0
  17. package/dist/src/form/RecordFormCustomization.js +25 -0
  18. package/dist/src/form/RecordFormCustomization.js.map +1 -0
  19. package/dist/src/form/customizations/MigrationRecordFormCustomization.d.ts +8 -0
  20. package/dist/src/form/customizations/MigrationRecordFormCustomization.d.ts.map +1 -0
  21. package/dist/src/form/customizations/MigrationRecordFormCustomization.js +106 -0
  22. package/dist/src/form/customizations/MigrationRecordFormCustomization.js.map +1 -0
  23. package/dist/src/pages/RecordFormPage.d.ts +5 -0
  24. package/dist/src/pages/RecordFormPage.d.ts.map +1 -0
  25. package/dist/src/pages/RecordFormPage.js +140 -0
  26. package/dist/src/pages/RecordFormPage.js.map +1 -0
  27. package/dist/src/pages/RecordTablePage.d.ts +6 -0
  28. package/dist/src/pages/RecordTablePage.d.ts.map +1 -0
  29. package/dist/src/pages/RecordTablePage.js +77 -0
  30. package/dist/src/pages/RecordTablePage.js.map +1 -0
  31. package/dist/src/pages/TablesPage.d.ts +3 -0
  32. package/dist/src/pages/TablesPage.d.ts.map +1 -0
  33. package/dist/src/pages/TablesPage.js +93 -0
  34. package/dist/src/pages/TablesPage.js.map +1 -0
  35. package/dist/src/pages/UuidGeneratorPage.d.ts +3 -0
  36. package/dist/src/pages/UuidGeneratorPage.d.ts.map +1 -0
  37. package/dist/src/pages/UuidGeneratorPage.js +93 -0
  38. package/dist/src/pages/UuidGeneratorPage.js.map +1 -0
  39. package/dist/src/table/QueryTableLoader.d.ts +10 -0
  40. package/dist/src/table/QueryTableLoader.d.ts.map +1 -0
  41. package/dist/src/table/QueryTableLoader.js +71 -0
  42. package/dist/src/table/QueryTableLoader.js.map +1 -0
  43. package/dist/src/table/RecordTable.d.ts +15 -0
  44. package/dist/src/table/RecordTable.d.ts.map +1 -0
  45. package/dist/src/table/RecordTable.js +138 -0
  46. package/dist/src/table/RecordTable.js.map +1 -0
  47. package/generated/index.ts +49 -0
  48. package/index.ts +4 -0
  49. package/jest.config.js +18 -0
  50. package/package.json +51 -0
  51. package/src/form/RecordForm.tsx +191 -0
  52. package/src/form/RecordFormCustomization.tsx +20 -0
  53. package/src/form/customizations/MigrationRecordFormCustomization.tsx +29 -0
  54. package/src/pages/RecordFormPage.tsx +81 -0
  55. package/src/pages/RecordTablePage.tsx +56 -0
  56. package/src/pages/TablesPage.tsx +48 -0
  57. package/src/pages/UuidGeneratorPage.tsx +37 -0
  58. package/src/table/QueryTableLoader.ts +23 -0
  59. package/src/table/RecordTable.tsx +112 -0
  60. package/tsconfig.json +18 -0
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.RecordTable = void 0;
43
+ var react_1 = __importDefault(require("react"));
44
+ var icons_material_1 = require("@mui/icons-material");
45
+ var string_1 = __importDefault(require("string"));
46
+ var ui_1 = require("@proteinjs/ui");
47
+ var db_1 = require("@proteinjs/db");
48
+ var QueryTableLoader_1 = require("./QueryTableLoader");
49
+ var RecordFormPage_1 = require("../pages/RecordFormPage");
50
+ var RecordTablePage_1 = require("../pages/RecordTablePage");
51
+ function deleteButton(table) {
52
+ var _this = this;
53
+ return {
54
+ name: "Delete selected rows",
55
+ icon: icons_material_1.Delete,
56
+ visibility: {
57
+ showWhenRowsSelected: true,
58
+ showWhenNoRowsSelected: false,
59
+ },
60
+ onClick: function (selectedRows, navigate) { return __awaiter(_this, void 0, void 0, function () {
61
+ var qb;
62
+ return __generator(this, function (_a) {
63
+ switch (_a.label) {
64
+ case 0:
65
+ qb = new db_1.QueryBuilderFactory().getQueryBuilder(table)
66
+ .condition({ field: 'id', operator: 'IN', value: selectedRows.map(function (row) { return row.id; }) });
67
+ return [4 /*yield*/, (0, db_1.getDb)().delete(table, qb)];
68
+ case 1:
69
+ _a.sent();
70
+ navigate((0, RecordTablePage_1.recordTableLink)(table));
71
+ return [2 /*return*/];
72
+ }
73
+ });
74
+ }); },
75
+ };
76
+ }
77
+ function createButton(table) {
78
+ var _this = this;
79
+ return {
80
+ name: "Create ".concat((0, string_1.default)(table.name).humanize().s),
81
+ icon: icons_material_1.Add,
82
+ visibility: {
83
+ showWhenRowsSelected: false,
84
+ showWhenNoRowsSelected: true,
85
+ },
86
+ onClick: function (selectedRows, navigate) { return __awaiter(_this, void 0, void 0, function () {
87
+ return __generator(this, function (_a) {
88
+ navigate((0, RecordFormPage_1.newRecordFormLink)(table.name));
89
+ return [2 /*return*/];
90
+ });
91
+ }); },
92
+ };
93
+ }
94
+ function RecordTable(props) {
95
+ function defaultColumns() {
96
+ var _a, _b;
97
+ var columnProperties = [];
98
+ if (props.table.columns['name'])
99
+ columnProperties.push('name');
100
+ for (var _i = 0, _c = Object.keys(props.table.columns); _i < _c.length; _i++) {
101
+ var columnProperty = _c[_i];
102
+ if (columnProperties.length >= 5)
103
+ break;
104
+ if (columnProperty == 'name' || columnProperty == 'created' || columnProperty == 'updated')
105
+ continue;
106
+ var column = props.table.columns[columnProperty];
107
+ if ((_b = (_a = column.options) === null || _a === void 0 ? void 0 : _a.ui) === null || _b === void 0 ? void 0 : _b.hidden)
108
+ continue;
109
+ if ((column instanceof db_1.StringColumn && column.maxLength === 'MAX') || column instanceof db_1.ReferenceArrayColumn)
110
+ continue;
111
+ columnProperties.push(columnProperty);
112
+ }
113
+ columnProperties.push('created');
114
+ columnProperties.push('updated');
115
+ return columnProperties;
116
+ }
117
+ function defaultTableLoader() {
118
+ return new QueryTableLoader_1.QueryTableLoader(props.table, undefined, [{ field: 'updated', desc: true }]);
119
+ }
120
+ function defaultRowOnClickRedirectUrl(row) {
121
+ return __awaiter(this, void 0, void 0, function () {
122
+ return __generator(this, function (_a) {
123
+ return [2 /*return*/, (0, RecordFormPage_1.recordFormLink)(props.table.name, row.id)];
124
+ });
125
+ });
126
+ }
127
+ function buttons() {
128
+ var buttons = [];
129
+ if (props.buttons)
130
+ buttons.push.apply(buttons, props.buttons);
131
+ buttons.push(deleteButton(props.table));
132
+ buttons.push(createButton(props.table));
133
+ return buttons;
134
+ }
135
+ return (react_1.default.createElement(ui_1.Table, { title: props.title ? props.title : "".concat((0, string_1.default)(props.table.name).humanize().toString(), " Table"), description: props.description, columns: props.columns ? props.columns : defaultColumns(), tableLoader: props.tableLoader ? props.tableLoader : defaultTableLoader(), rowOnClickRedirectUrl: props.rowOnClickRedirectUrl ? props.rowOnClickRedirectUrl : defaultRowOnClickRedirectUrl, defaultRowsPerPage: props.defaultRowsPerPage, buttons: buttons() }));
136
+ }
137
+ exports.RecordTable = RecordTable;
138
+ //# sourceMappingURL=RecordTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecordTable.js","sourceRoot":"","sources":["../../../src/table/RecordTable.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /** Load Dependency Source Graphs */
2
+
3
+ import '@emotion/react';
4
+ import '@emotion/styled';
5
+ import '@mui/icons-material';
6
+ import '@mui/material';
7
+ import '@proteinjs/db';
8
+ import '@proteinjs/reflection';
9
+ import '@proteinjs/ui';
10
+ import '@proteinjs/util';
11
+ import 'moment';
12
+ import 'react';
13
+ import 'string';
14
+ import 'uuid';
15
+
16
+
17
+ /** Generate Source Graph */
18
+
19
+ const sourceGraph = "{\"options\":{\"directed\":true,\"multigraph\":false,\"compound\":false},\"nodes\":[{\"v\":\"@proteinjs/db-ui/QueryTableLoader\",\"value\":{\"packageName\":\"@proteinjs/db-ui\",\"name\":\"QueryTableLoader\",\"filePath\":\"/home/runner/work/db/db/packages/ui/src/table/QueryTableLoader.ts\",\"qualifiedName\":\"@proteinjs/db-ui/QueryTableLoader\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"table\",\"type\":{\"packageName\":\"\",\"name\":\"Table<T>\",\"filePath\":null,\"qualifiedName\":\"/Table<T>\",\"typeParameters\":null,\"directParents\":null},\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\"},{\"name\":\"query\",\"type\":{\"packageName\":\"\",\"name\":\"Query<T>\",\"filePath\":null,\"qualifiedName\":\"/Query<T>\",\"typeParameters\":null,\"directParents\":null},\"isOptional\":true,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\"},{\"name\":\"sort\",\"type\":{\"packageName\":\"\",\"name\":\"SortCriteria<T>[]\",\"filePath\":null,\"qualifiedName\":\"/SortCriteria<T>[]\",\"typeParameters\":null,\"directParents\":null},\"isOptional\":true,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"private\"}],\"methods\":[{\"name\":\"load\",\"returnType\":{\"packageName\":\"\",\"name\":\"Promise<RowWindow<T>>\",\"filePath\":null,\"qualifiedName\":\"/Promise<RowWindow<T>>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":true,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[{\"name\":\"startIndex\",\"type\":{\"packageName\":\"\",\"name\":\"number\",\"filePath\":null,\"qualifiedName\":\"/number\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"endIndex\",\"type\":{\"packageName\":\"\",\"name\":\"number\",\"filePath\":null,\"qualifiedName\":\"/number\",\"typeParameters\":null,\"directParents\":null}}]}],\"typeParameters\":[\"/T extends Record\"],\"directParentInterfaces\":[{\"packageName\":\"@proteinjs/ui\",\"name\":\"TableLoader\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/ui/TableLoader\",\"properties\":[],\"methods\":[],\"typeParameters\":[\"/T\"],\"directParents\":[]}],\"directParentClasses\":[],\"sourceType\":2}},{\"v\":\"@proteinjs/ui/TableLoader\"},{\"v\":\"@proteinjs/db-ui/RecordFormCustomization\",\"value\":{\"packageName\":\"@proteinjs/db-ui\",\"name\":\"RecordFormCustomization\",\"filePath\":\"/home/runner/work/db/db/packages/ui/src/form/RecordFormCustomization.tsx\",\"qualifiedName\":\"@proteinjs/db-ui/RecordFormCustomization\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"table\",\"type\":{\"packageName\":\"\",\"name\":\"Table<any>\",\"filePath\":null,\"qualifiedName\":\"/Table<any>\",\"typeParameters\":null,\"directParents\":null},\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"}],\"methods\":[{\"name\":\"getFormButtons\",\"returnType\":{\"packageName\":\"\",\"name\":\"FormButtons<any>\",\"filePath\":null,\"qualifiedName\":\"/FormButtons<any>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":false,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[{\"name\":\"record\",\"type\":{\"packageName\":\"\",\"name\":\"any\",\"filePath\":null,\"qualifiedName\":\"/any\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"defaultFormButtons\",\"type\":{\"packageName\":\"\",\"name\":\"FormButtons<any>\",\"filePath\":null,\"qualifiedName\":\"/FormButtons<any>\",\"typeParameters\":null,\"directParents\":null}}]}],\"typeParameters\":[],\"directParentInterfaces\":[{\"packageName\":\"@proteinjs/reflection\",\"name\":\"Loadable\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/reflection/Loadable\",\"properties\":[],\"methods\":[],\"typeParameters\":[],\"directParents\":[]}],\"directParentClasses\":[],\"sourceType\":2}},{\"v\":\"@proteinjs/reflection/Loadable\"},{\"v\":\"@proteinjs/db-ui/recordFormPage\",\"value\":{\"packageName\":\"@proteinjs/db-ui\",\"name\":\"recordFormPage\",\"filePath\":\"/home/runner/work/db/db/packages/ui/src/pages/RecordFormPage.tsx\",\"qualifiedName\":\"@proteinjs/db-ui/recordFormPage\",\"type\":{\"packageName\":\"@proteinjs/ui\",\"name\":\"Page\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/ui/Page\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/ui\",\"name\":\"Page\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/ui/Page\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/ui/Page\"},{\"v\":\"@proteinjs/db-ui/recordTablePage\",\"value\":{\"packageName\":\"@proteinjs/db-ui\",\"name\":\"recordTablePage\",\"filePath\":\"/home/runner/work/db/db/packages/ui/src/pages/RecordTablePage.tsx\",\"qualifiedName\":\"@proteinjs/db-ui/recordTablePage\",\"type\":{\"packageName\":\"@proteinjs/ui\",\"name\":\"Page\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/ui/Page\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/ui\",\"name\":\"Page\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/ui/Page\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/db-ui/tablesPage\",\"value\":{\"packageName\":\"@proteinjs/db-ui\",\"name\":\"tablesPage\",\"filePath\":\"/home/runner/work/db/db/packages/ui/src/pages/TablesPage.tsx\",\"qualifiedName\":\"@proteinjs/db-ui/tablesPage\",\"type\":{\"packageName\":\"@proteinjs/ui\",\"name\":\"Page\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/ui/Page\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/ui\",\"name\":\"Page\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/ui/Page\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/db-ui/uuidGeneratorPage\",\"value\":{\"packageName\":\"@proteinjs/db-ui\",\"name\":\"uuidGeneratorPage\",\"filePath\":\"/home/runner/work/db/db/packages/ui/src/pages/UuidGeneratorPage.tsx\",\"qualifiedName\":\"@proteinjs/db-ui/uuidGeneratorPage\",\"type\":{\"packageName\":\"@proteinjs/ui\",\"name\":\"Page\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/ui/Page\",\"typeParameters\":[],\"directParents\":[{\"packageName\":\"@proteinjs/ui\",\"name\":\"Page\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/ui/Page\",\"typeParameters\":[],\"directParents\":null}]},\"isExported\":true,\"isConst\":true,\"sourceType\":0}},{\"v\":\"@proteinjs/db-ui/MigrationRecordFormCustomization\",\"value\":{\"packageName\":\"@proteinjs/db-ui\",\"name\":\"MigrationRecordFormCustomization\",\"filePath\":\"/home/runner/work/db/db/packages/ui/src/form/customizations/MigrationRecordFormCustomization.tsx\",\"qualifiedName\":\"@proteinjs/db-ui/MigrationRecordFormCustomization\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[{\"name\":\"table\",\"type\":null,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\"}],\"methods\":[{\"name\":\"getFormButtons\",\"returnType\":{\"packageName\":\"\",\"name\":\"FormButtons<any>\",\"filePath\":null,\"qualifiedName\":\"/FormButtons<any>\",\"typeParameters\":null,\"directParents\":null},\"isAsync\":false,\"isOptional\":false,\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"parameters\":[{\"name\":\"migration\",\"type\":{\"packageName\":\"@proteinjs/db\",\"name\":\"Migration\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db/Migration\",\"typeParameters\":null,\"directParents\":null}},{\"name\":\"defaultFormButtons\",\"type\":{\"packageName\":\"\",\"name\":\"FormButtons<any>\",\"filePath\":null,\"qualifiedName\":\"/FormButtons<any>\",\"typeParameters\":null,\"directParents\":null}}]}],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[{\"packageName\":\"@proteinjs/db-ui\",\"name\":\"RecordFormCustomization\",\"filePath\":null,\"qualifiedName\":\"@proteinjs/db-ui/RecordFormCustomization\",\"isAbstract\":false,\"isStatic\":false,\"visibility\":\"public\",\"properties\":[],\"methods\":[],\"typeParameters\":[],\"directParentInterfaces\":[],\"directParentClasses\":[]}],\"sourceType\":2}}],\"edges\":[{\"v\":\"@proteinjs/db-ui/QueryTableLoader\",\"w\":\"@proteinjs/ui/TableLoader\",\"value\":\"implements interface\"},{\"v\":\"@proteinjs/db-ui/RecordFormCustomization\",\"w\":\"@proteinjs/reflection/Loadable\",\"value\":\"implements interface\"},{\"v\":\"@proteinjs/db-ui/recordFormPage\",\"w\":\"@proteinjs/ui/Page\",\"value\":\"has type\"},{\"v\":\"@proteinjs/db-ui/recordTablePage\",\"w\":\"@proteinjs/ui/Page\",\"value\":\"has type\"},{\"v\":\"@proteinjs/db-ui/tablesPage\",\"w\":\"@proteinjs/ui/Page\",\"value\":\"has type\"},{\"v\":\"@proteinjs/db-ui/uuidGeneratorPage\",\"w\":\"@proteinjs/ui/Page\",\"value\":\"has type\"},{\"v\":\"@proteinjs/db-ui/MigrationRecordFormCustomization\",\"w\":\"@proteinjs/db-ui/RecordFormCustomization\",\"value\":\"extends class\"}]}";
20
+
21
+
22
+ /** Generate Source Links */
23
+
24
+ import { QueryTableLoader } from '../src/table/QueryTableLoader';
25
+ import { RecordFormCustomization } from '../src/form/RecordFormCustomization';
26
+ import { recordFormPage } from '../src/pages/RecordFormPage';
27
+ import { recordTablePage } from '../src/pages/RecordTablePage';
28
+ import { tablesPage } from '../src/pages/TablesPage';
29
+ import { uuidGeneratorPage } from '../src/pages/UuidGeneratorPage';
30
+ import { MigrationRecordFormCustomization } from '../src/form/customizations/MigrationRecordFormCustomization';
31
+
32
+ const sourceLinks = {
33
+ '@proteinjs/db-ui/QueryTableLoader': QueryTableLoader,
34
+ '@proteinjs/db-ui/RecordFormCustomization': RecordFormCustomization,
35
+ '@proteinjs/db-ui/recordFormPage': recordFormPage,
36
+ '@proteinjs/db-ui/recordTablePage': recordTablePage,
37
+ '@proteinjs/db-ui/tablesPage': tablesPage,
38
+ '@proteinjs/db-ui/uuidGeneratorPage': uuidGeneratorPage,
39
+ '@proteinjs/db-ui/MigrationRecordFormCustomization': MigrationRecordFormCustomization,
40
+ };
41
+
42
+
43
+ /** Load Source Graph and Links */
44
+
45
+ import { SourceRepository } from '@proteinjs/reflection';
46
+ SourceRepository.merge(sourceGraph, sourceLinks);
47
+
48
+
49
+ export * from '../index';
package/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './src/table/RecordTable'
2
+ export * from './src/table/QueryTableLoader'
3
+ export * from './src/form/RecordForm'
4
+ export * from './src/form/RecordFormCustomization'
package/jest.config.js ADDED
@@ -0,0 +1,18 @@
1
+ module.exports = {
2
+ "roots": [
3
+ "<rootDir>/test"
4
+ ],
5
+ "transform": {
6
+ "^.+\\.tsx?$": "ts-jest"
7
+ },
8
+ "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
9
+ "moduleFileExtensions": [
10
+ "ts",
11
+ "tsx",
12
+ "js",
13
+ "jsx",
14
+ "json",
15
+ "node"
16
+ ],
17
+ "testEnvironment": "node"
18
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@proteinjs/db-ui",
3
+ "version": "1.0.3",
4
+ "description": "Db ui components",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/proteinjs/db.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/proteinjs/db/issues"
14
+ },
15
+ "homepage": "https://github.com/proteinjs/db#readme",
16
+ "author": "Brent Bahry",
17
+ "license": "MIT",
18
+ "scripts": {
19
+ "clean": "rm -rf dist/ node_modules/ generated/ package-lock.json",
20
+ "build": "reflection-build && tsc",
21
+ "watch": "reflection-watch"
22
+ },
23
+ "dependencies": {
24
+ "@emotion/react": "11.11.1",
25
+ "@emotion/styled": "11.11.0",
26
+ "@mui/icons-material": "5.14.11",
27
+ "@mui/material": "5.14.11",
28
+ "@proteinjs/db": "1.0.3",
29
+ "@proteinjs/reflection": "1.0.2",
30
+ "@proteinjs/ui": "1.0.1",
31
+ "@proteinjs/util": "1.0.18",
32
+ "moment": "2.29.4",
33
+ "react": "18.2.0",
34
+ "string": "3.3.3",
35
+ "uuid": "8.3.0"
36
+ },
37
+ "devDependencies": {
38
+ "@proteinjs/reflection-build": "1.0.5",
39
+ "@types/jest": "29.5.5",
40
+ "@types/node": "14.0.27",
41
+ "@types/react": "18.2.23",
42
+ "@types/string": "0.0.33",
43
+ "@types/uuid": "8.3.0",
44
+ "jest": "29.7.0",
45
+ "ts-jest": "29.1.1",
46
+ "typescript": "5.2.2"
47
+ },
48
+ "main": "./dist/generated/index.js",
49
+ "types": "./dist/generated/index.d.ts",
50
+ "gitHead": "d85d27f2ad767c150f9651afe32d2317ba82439c"
51
+ }
@@ -0,0 +1,191 @@
1
+ import React from 'react'
2
+ import S from 'string'
3
+ import moment from 'moment'
4
+ import { StringUtil } from '@proteinjs/util'
5
+ import { Form, Fields, textField, FormButtons } from '@proteinjs/ui'
6
+ import { Table, Record, Column, getDbService, DateTimeColumn, ReferenceArrayColumn, BooleanColumn, StringColumn } from '@proteinjs/db'
7
+ import { recordTableLink } from '../pages/RecordTablePage'
8
+ import { recordFormLink } from '../pages/RecordFormPage'
9
+ import { getRecordFormCustomization } from './RecordFormCustomization'
10
+
11
+ export type RecordFormProps<T extends Record> = {
12
+ table: Table<T>,
13
+ record?: T,
14
+ }
15
+
16
+ export function RecordForm<T extends Record>({ table, record }: RecordFormProps<T>) {
17
+ const isNewRecord = typeof record === 'undefined';
18
+ const recordFormCustomization = getRecordFormCustomization(table.name);
19
+ return (
20
+ <Form
21
+ name={S(table.name).humanize().s}
22
+ createFields={createFields()}
23
+ fieldLayout={fieldLayout()}
24
+ buttons={recordFormCustomization?.getFormButtons ? recordFormCustomization.getFormButtons(record, buttons()) : buttons()}
25
+ onLoad={onLoad}
26
+ onLoadProgressMessage={`Loading ${S(table.name).humanize().s}`}
27
+ />
28
+ );
29
+
30
+ function getColumns() {
31
+ const columns: {[columnPropertyName: string]: Column<T, any>} = {};
32
+ const nameColumn = (table.columns as any)['name'] as Column<T, any>;
33
+ if (nameColumn)
34
+ columns['name'] = nameColumn;
35
+
36
+ for (let columnPropertyName in table.columns) {
37
+ const column = (table.columns as any)[columnPropertyName] as Column<T, any>;
38
+ if (columnPropertyName == 'name' || columnPropertyName == 'created' || columnPropertyName == 'updated')
39
+ continue;
40
+
41
+ if (column.options?.ui?.hidden)
42
+ continue;
43
+
44
+ if ((column instanceof StringColumn && column.maxLength === 'MAX') || column instanceof ReferenceArrayColumn)
45
+ continue;
46
+
47
+ columns[columnPropertyName] = column;
48
+ }
49
+
50
+ if (!isNewRecord) {
51
+ columns['created'] = (table.columns as any)['created'] as Column<T, any>;
52
+ columns['updated'] = (table.columns as any)['updated'] as Column<T, any>;
53
+ }
54
+
55
+ return columns;
56
+ }
57
+
58
+ function createFields(): () => Fields {
59
+ return () => {
60
+ const fields: Fields = {};
61
+ for (let columnPropertyName in getColumns()) {
62
+ fields[columnPropertyName] = textField({
63
+ name: columnPropertyName,
64
+ label: StringUtil.humanizeCamel(columnPropertyName),
65
+ });
66
+ }
67
+
68
+ return fields;
69
+ };
70
+ }
71
+
72
+ function fieldLayout(): any {
73
+ const columns = getColumns();
74
+ const layoutColumns = Object.entries(columns).length > 6 ? 2 : 1;
75
+ if (layoutColumns > 1) {
76
+ const layout: (keyof T)[][] = [];
77
+ for (let columnPropertyName in columns) {
78
+ if (layout.length == 0 || layout[layout.length - 1].length >= layoutColumns)
79
+ layout.push([]);
80
+
81
+ layout[layout.length - 1].push(columnPropertyName as keyof T);
82
+ }
83
+
84
+ return layout;
85
+ }
86
+
87
+ return Object.keys(columns) as (keyof T)[];
88
+ }
89
+
90
+ function buttons(): FormButtons<any> {
91
+ let newRecord: T;
92
+ return {
93
+ delete: {
94
+ name: 'Delete',
95
+ accessibility: {
96
+ hidden: isNewRecord,
97
+ },
98
+ style: {
99
+ color: 'primary',
100
+ variant: 'text',
101
+ },
102
+ redirect: async (fields: Fields, buttons: FormButtons<Fields>) => {
103
+ return { path: recordTableLink(table) };
104
+ },
105
+ onClick: async (fields: Fields, buttons: FormButtons<Fields>) => {
106
+ if (!record || !record.id)
107
+ throw new Error(`Unable to delete record, record or id undefined`);
108
+
109
+ await getDbService().delete(table, { id: record.id } as any);
110
+ return `Deleted ${S(table.name).humanize().s}`;
111
+ },
112
+ progressMessage: (fields: Fields) => { return `Deleting ${S(table.name).humanize().s}` },
113
+ },
114
+ save: {
115
+ name: 'Save',
116
+ accessibility: {
117
+ hidden: isNewRecord,
118
+ },
119
+ style: {
120
+ color: 'primary',
121
+ variant: 'contained',
122
+ },
123
+ onClick: async (fields: Fields, buttons: FormButtons<Fields>) => {
124
+ if (!record || !record.id)
125
+ throw new Error(`Unable to save record, record or id undefined`);
126
+
127
+ for (let columnPropertyName in fields) {
128
+ const field = fields[columnPropertyName];
129
+ (record as any)[columnPropertyName] = field.field.value;
130
+ }
131
+
132
+ await getDbService().update(table, record);
133
+ return `Saved ${S(table.name).humanize().s}`;
134
+ },
135
+ progressMessage: (fields: Fields) => { return `Saving ${S(table.name).humanize().s}` },
136
+ },
137
+ create: {
138
+ name: 'Create',
139
+ accessibility: {
140
+ hidden: !isNewRecord,
141
+ },
142
+ style: {
143
+ color: 'primary',
144
+ variant: 'contained',
145
+ },
146
+ redirect: async (fields: Fields, buttons: FormButtons<Fields>) => {
147
+ return { path: recordFormLink(table.name, newRecord.id) };
148
+ },
149
+ onClick: async (fields: Fields, buttons: FormButtons<Fields>) => {
150
+ const record: any = {};
151
+ for (let columnPropertyName in fields) {
152
+ const field = fields[columnPropertyName];
153
+ (record as any)[columnPropertyName] = field.field.value;
154
+ }
155
+
156
+ newRecord = await getDbService().insert(table, record);
157
+ return `Created ${S(table.name).humanize().s}`;
158
+ },
159
+ progressMessage: (fields: Fields) => { return `Creating ${S(table.name).humanize().s}` },
160
+ },
161
+ }
162
+ }
163
+
164
+ async function onLoad(fields: Fields, buttons: FormButtons<Fields>) {
165
+ if (isNewRecord)
166
+ return;
167
+
168
+ for (let columnPropertyName in fields) {
169
+ const column = (table.columns as any)[columnPropertyName] as Column<any, any>;
170
+ const field = fields[columnPropertyName].field;
171
+ let fieldValue = (record as any)[columnPropertyName];
172
+ if (moment.isMoment(fieldValue))
173
+ fieldValue = fieldValue.format('ddd, MMM Do YY, h:mm:ss a');
174
+ else if (column instanceof BooleanColumn)
175
+ fieldValue = fieldValue == true ? 'True' : 'False';
176
+
177
+ field.value = fieldValue;
178
+ if (
179
+ columnPropertyName == 'created' ||
180
+ columnPropertyName == 'updated' ||
181
+ columnPropertyName == 'id' ||
182
+ column instanceof DateTimeColumn
183
+ ) {
184
+ if (!field.accessibility)
185
+ field.accessibility = {};
186
+
187
+ field.accessibility.readonly = true;
188
+ }
189
+ }
190
+ }
191
+ }
@@ -0,0 +1,20 @@
1
+ import { Loadable, SourceRepository } from '@proteinjs/reflection'
2
+ import { FormButtons } from '@proteinjs/ui'
3
+ import { Table } from '@proteinjs/db'
4
+
5
+ export const getRecordFormCustomizations = () => SourceRepository.get().objects<RecordFormCustomization>('@proteinjs/db-ui/RecordFormCustomization');
6
+
7
+ export const getRecordFormCustomization = (tableName: string) => {
8
+ const recordFormCustomizations = getRecordFormCustomizations();
9
+ for (let recordFormCustomization of recordFormCustomizations) {
10
+ if (recordFormCustomization.table.name == tableName)
11
+ return recordFormCustomization;
12
+ }
13
+ }
14
+
15
+ export abstract class RecordFormCustomization implements Loadable {
16
+ abstract table: Table<any>;
17
+ getFormButtons(record: any, defaultFormButtons: FormButtons<any>): FormButtons<any> {
18
+ return defaultFormButtons;
19
+ }
20
+ }
@@ -0,0 +1,29 @@
1
+ import { Fields, FormButtons } from '@proteinjs/ui'
2
+ import { Migration, getMigrationRunnerService, tables } from '@proteinjs/db'
3
+ import { RecordFormCustomization } from '../RecordFormCustomization'
4
+
5
+ export class MigrationRecordFormCustomization extends RecordFormCustomization {
6
+ public table = tables.Migration;
7
+
8
+ getFormButtons(migration: Migration, defaultFormButtons: FormButtons<any>): FormButtons<any> {
9
+ const formButtons = { ...defaultFormButtons };
10
+ delete formButtons['create'];
11
+ delete formButtons['delete'];
12
+ formButtons['run'] = {
13
+ name: 'Run',
14
+ accessibility: {
15
+ hidden: !migration || migration.status === 'running',
16
+ },
17
+ style: {
18
+ color: 'primary',
19
+ variant: 'contained',
20
+ },
21
+ onClick: async (fields: Fields, buttons: FormButtons<Fields>) => {
22
+ await getMigrationRunnerService().runMigration(migration.id);
23
+ return `Started migration`;
24
+ },
25
+ progressMessage: (fields: Fields) => { return `Starting migration` },
26
+ };
27
+ return formButtons;
28
+ }
29
+ }
@@ -0,0 +1,81 @@
1
+ import React from 'react'
2
+ import { FormPage, Page, PageComponentProps } from '@proteinjs/ui'
3
+ import { getDbService, tableByName } from '@proteinjs/db'
4
+ import { RecordForm } from '../form/RecordForm'
5
+
6
+ export const recordFormPage: Page = {
7
+ name: 'Record Form',
8
+ path: 'record/form',
9
+ auth: {
10
+ allUsers: true,
11
+ },
12
+ component: ({...props}) => (
13
+ <FormPage>
14
+ <DynamicRecordForm {...props} />
15
+ </FormPage>
16
+ )
17
+ }
18
+
19
+ export const recordFormLink = (tableName: string, recordId: string) => {
20
+ return `/${recordFormPage.path}?table=${tableName}&record=${recordId}`;
21
+ }
22
+
23
+ export const newRecordFormLink = (tableName: string) => {
24
+ return `/${recordFormPage.path}?table=${tableName}`;
25
+ }
26
+
27
+ const DynamicRecordForm = ({ urlParams }: PageComponentProps) => {
28
+ const [record, setRecord] = React.useState();
29
+
30
+ React.useEffect(() => {
31
+ const fetchData = async () => {
32
+ const { table } = getTable();
33
+ if (!table)
34
+ return;
35
+
36
+ const recordId = urlParams['record'];
37
+ if (!recordId)
38
+ return;
39
+
40
+ const fetchedRecord = await getDbService().get(table, { id: recordId });
41
+ setRecord(fetchedRecord);
42
+ };
43
+
44
+ fetchData();
45
+ }, [urlParams.table, urlParams.record]);
46
+
47
+ function getTable() {
48
+ const tableName = urlParams['table'];
49
+ let table;
50
+ let error;
51
+ if (tableName) {
52
+ try {
53
+ table = tableByName(tableName);
54
+ } catch (error) {
55
+ error = `Table not accessible in UI: ${tableName}`;
56
+ }
57
+ } else {
58
+ error = `Table name not provided via the 'table' url param`;
59
+ }
60
+
61
+ return { table, error };
62
+ }
63
+
64
+ function Form() {
65
+ const { table, error } = getTable();
66
+ if (!table) {
67
+ return <div>{ error }</div>;
68
+ }
69
+
70
+ return (
71
+ <RecordForm
72
+ table={table}
73
+ record={record}
74
+ />
75
+ );
76
+ }
77
+
78
+ return (
79
+ <Form />
80
+ );
81
+ }