@nocobase/plugin-api-keys 0.10.1-alpha.1

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 (73) hide show
  1. package/README.md +9 -0
  2. package/README.zh-CN.md +9 -0
  3. package/client.d.ts +4 -0
  4. package/client.js +30 -0
  5. package/docs/en-US/changelog.md +1 -0
  6. package/docs/en-US/index.md +9 -0
  7. package/docs/en-US/tabs.json +14 -0
  8. package/docs/en-US/usage.md +19 -0
  9. package/docs/zh-CN/changelog.md +1 -0
  10. package/docs/zh-CN/index.md +10 -0
  11. package/docs/zh-CN/tabs.json +14 -0
  12. package/docs/zh-CN/usage.md +19 -0
  13. package/lib/client/Configuration/ExpiresSelect.d.ts +3 -0
  14. package/lib/client/Configuration/ExpiresSelect.js +131 -0
  15. package/lib/client/Configuration/index.d.ts +2 -0
  16. package/lib/client/Configuration/index.js +47 -0
  17. package/lib/client/Configuration/roles.d.ts +3 -0
  18. package/lib/client/Configuration/roles.js +20 -0
  19. package/lib/client/Configuration/schema.d.ts +2 -0
  20. package/lib/client/Configuration/schema.js +319 -0
  21. package/lib/client/index.d.ts +3 -0
  22. package/lib/client/index.js +46 -0
  23. package/lib/client/locale/en-US.d.ts +2 -0
  24. package/lib/client/locale/en-US.js +9 -0
  25. package/lib/client/locale/index.d.ts +2 -0
  26. package/lib/client/locale/index.js +32 -0
  27. package/lib/client/locale/zh-CN.d.ts +19 -0
  28. package/lib/client/locale/zh-CN.js +26 -0
  29. package/lib/collections/api-keys.d.ts +3 -0
  30. package/lib/collections/api-keys.js +87 -0
  31. package/lib/collections/index.d.ts +1 -0
  32. package/lib/collections/index.js +13 -0
  33. package/lib/constants.d.ts +1 -0
  34. package/lib/constants.js +8 -0
  35. package/lib/index.d.ts +1 -0
  36. package/lib/index.js +13 -0
  37. package/lib/locale.d.ts +1 -0
  38. package/lib/locale.js +10 -0
  39. package/lib/server/actions/api-keys.d.ts +3 -0
  40. package/lib/server/actions/api-keys.js +71 -0
  41. package/lib/server/index.d.ts +1 -0
  42. package/lib/server/index.js +13 -0
  43. package/lib/server/locale/en-US.d.ts +2 -0
  44. package/lib/server/locale/en-US.js +8 -0
  45. package/lib/server/locale/index.d.ts +2 -0
  46. package/lib/server/locale/index.js +20 -0
  47. package/lib/server/locale/zh-CN.d.ts +4 -0
  48. package/lib/server/locale/zh-CN.js +10 -0
  49. package/lib/server/plugin.d.ts +10 -0
  50. package/lib/server/plugin.js +77 -0
  51. package/package.json +24 -0
  52. package/server.d.ts +4 -0
  53. package/server.js +30 -0
  54. package/src/client/Configuration/ExpiresSelect.tsx +80 -0
  55. package/src/client/Configuration/index.tsx +18 -0
  56. package/src/client/Configuration/roles.ts +9 -0
  57. package/src/client/Configuration/schema.tsx +264 -0
  58. package/src/client/index.tsx +29 -0
  59. package/src/client/locale/en-US.ts +3 -0
  60. package/src/client/locale/index.ts +13 -0
  61. package/src/client/locale/zh-CN.ts +21 -0
  62. package/src/collections/api-keys.ts +95 -0
  63. package/src/collections/index.ts +1 -0
  64. package/src/constants.ts +1 -0
  65. package/src/index.ts +1 -0
  66. package/src/locale.ts +5 -0
  67. package/src/server/__tests__/actions.test.ts +181 -0
  68. package/src/server/actions/api-keys.ts +49 -0
  69. package/src/server/index.ts +1 -0
  70. package/src/server/locale/en-US.ts +1 -0
  71. package/src/server/locale/index.ts +2 -0
  72. package/src/server/locale/zh-CN.ts +3 -0
  73. package/src/server/plugin.ts +53 -0
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.create = create;
7
+ exports.destroy = destroy;
8
+ function _actions() {
9
+ const data = _interopRequireDefault(require("@nocobase/actions"));
10
+ _actions = function _actions() {
11
+ return data;
12
+ };
13
+ return data;
14
+ }
15
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
17
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
18
+ function create(_x, _x2) {
19
+ return _create.apply(this, arguments);
20
+ }
21
+ function _create() {
22
+ _create = _asyncToGenerator(function* (ctx, next) {
23
+ const values = ctx.action.params.values;
24
+ if (!values.role) {
25
+ return;
26
+ }
27
+ const repository = ctx.db.getRepository('users.roles', ctx.auth.user.id);
28
+ const role = yield repository.findOne({
29
+ filter: {
30
+ name: values.role.name
31
+ }
32
+ });
33
+ if (!role) {
34
+ throw ctx.throw(400, ctx.t('Role not found'));
35
+ }
36
+ const token = ctx.app.authManager.jwt.sign({
37
+ userId: ctx.auth.user.id,
38
+ roleName: role.name
39
+ }, {
40
+ expiresIn: values.expiresIn
41
+ });
42
+ ctx.action.mergeParams({
43
+ values: {
44
+ token
45
+ }
46
+ });
47
+ return _actions().default.create(ctx, /*#__PURE__*/_asyncToGenerator(function* () {
48
+ ctx.body = {
49
+ token
50
+ };
51
+ yield next();
52
+ }));
53
+ });
54
+ return _create.apply(this, arguments);
55
+ }
56
+ function destroy(_x3, _x4) {
57
+ return _destroy.apply(this, arguments);
58
+ }
59
+ function _destroy() {
60
+ _destroy = _asyncToGenerator(function* (ctx, next) {
61
+ const repo = ctx.db.getRepository(ctx.action.resourceName);
62
+ const filterByTk = ctx.action.params.filterByTk;
63
+ const data = yield repo.findById(filterByTk);
64
+ const token = data === null || data === void 0 ? void 0 : data.get('token');
65
+ if (token) {
66
+ yield ctx.app.authManager.jwt.block(token);
67
+ }
68
+ return _actions().default.destroy(ctx, next);
69
+ });
70
+ return _destroy.apply(this, arguments);
71
+ }
@@ -0,0 +1 @@
1
+ export { default } from './plugin';
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "default", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _plugin.default;
10
+ }
11
+ });
12
+ var _plugin = _interopRequireDefault(require("./plugin"));
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -0,0 +1,2 @@
1
+ declare const _default: {};
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _default = {};
8
+ exports.default = _default;
@@ -0,0 +1,2 @@
1
+ export { default as enUS } from './en-US';
2
+ export { default as zhCN } from './zh-CN';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "enUS", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _enUS.default;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "zhCN", {
13
+ enumerable: true,
14
+ get: function get() {
15
+ return _zhCN.default;
16
+ }
17
+ });
18
+ var _enUS = _interopRequireDefault(require("./en-US"));
19
+ var _zhCN = _interopRequireDefault(require("./zh-CN"));
20
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -0,0 +1,4 @@
1
+ declare const _default: {
2
+ 'Role not found': string;
3
+ };
4
+ export default _default;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _default = {
8
+ 'Role not found': '角色不存在'
9
+ };
10
+ exports.default = _default;
@@ -0,0 +1,10 @@
1
+ import { Plugin } from '@nocobase/server';
2
+ export interface ApiKeysPluginConfig {
3
+ name?: string;
4
+ }
5
+ export default class ApiKeysPlugin extends Plugin<ApiKeysPluginConfig> {
6
+ resourceName: string;
7
+ constructor(app: any, options: any);
8
+ beforeLoad(): Promise<void>;
9
+ load(): Promise<void>;
10
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ function _server() {
8
+ const data = require("@nocobase/server");
9
+ _server = function _server() {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _path() {
15
+ const data = require("path");
16
+ _path = function _path() {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ var _constants = require("../constants");
22
+ var _apiKeys = require("./actions/api-keys");
23
+ var _locale = require("./locale");
24
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
25
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
26
+ class ApiKeysPlugin extends _server().Plugin {
27
+ constructor(app, options) {
28
+ super(app, options);
29
+ this.resourceName = 'apiKeys';
30
+ }
31
+ beforeLoad() {
32
+ var _this = this;
33
+ return _asyncToGenerator(function* () {
34
+ _this.app.i18n.addResources('zh-CN', _constants.NAMESPACE, _locale.zhCN);
35
+ _this.app.i18n.addResources('en-US', _constants.NAMESPACE, _locale.enUS);
36
+ yield _this.app.resourcer.define({
37
+ name: _this.resourceName,
38
+ actions: {
39
+ create: _apiKeys.create,
40
+ destroy: _apiKeys.destroy
41
+ },
42
+ only: ['list', 'create', 'destroy']
43
+ });
44
+ _this.app.acl.registerSnippet({
45
+ name: ['pm', _this.name, 'configuration'].join('.'),
46
+ actions: ['apiKeys:list', 'apiKeys:create', 'apiKeys:destroy']
47
+ });
48
+ })();
49
+ }
50
+ load() {
51
+ var _this2 = this;
52
+ return _asyncToGenerator(function* () {
53
+ yield _this2.db.import({
54
+ directory: (0, _path().resolve)(__dirname, '../collections')
55
+ });
56
+ _this2.app.resourcer.use( /*#__PURE__*/function () {
57
+ var _ref = _asyncToGenerator(function* (ctx, next) {
58
+ const _ctx$action$params = ctx.action.params,
59
+ resourceName = _ctx$action$params.resourceName,
60
+ actionName = _ctx$action$params.actionName;
61
+ if (resourceName == _this2.resourceName && ['list', 'destroy'].includes(actionName)) {
62
+ ctx.action.mergeParams({
63
+ filter: {
64
+ createdById: ctx.auth.user.id
65
+ }
66
+ });
67
+ }
68
+ yield next();
69
+ });
70
+ return function (_x, _x2) {
71
+ return _ref.apply(this, arguments);
72
+ };
73
+ }());
74
+ })();
75
+ }
76
+ }
77
+ exports.default = ApiKeysPlugin;
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@nocobase/plugin-api-keys",
3
+ "displayName": "API keys",
4
+ "displayName.zh-CN": "API keys",
5
+ "description": "Allow users to use API key to access NocoBase's api",
6
+ "description.zh-CN": "允许用户使用 API key 访问 NocoBase 的 api",
7
+ "version": "0.10.1-alpha.1",
8
+ "license": "AGPL-3.0",
9
+ "main": "./lib/index.js",
10
+ "types": "./lib/index.d.ts",
11
+ "dependencies": {
12
+ "@nocobase/actions": "0.10.1-alpha.1",
13
+ "@nocobase/database": "0.10.1-alpha.1",
14
+ "@nocobase/resourcer": "0.10.1-alpha.1",
15
+ "@nocobase/server": "0.10.1-alpha.1",
16
+ "@nocobase/utils": "0.10.1-alpha.1",
17
+ "jsonwebtoken": "^8.5.1"
18
+ },
19
+ "devDependencies": {
20
+ "@nocobase/test": "0.10.1-alpha.1",
21
+ "@types/jsonwebtoken": "^8.5.8"
22
+ },
23
+ "gitHead": "8f415f5e0ee2e72d681f9ab16af5911b52c374a9"
24
+ }
package/server.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ // @ts-nocheck
2
+ export * from './lib/server';
3
+ export { default } from './lib/server';
4
+
package/server.js ADDED
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
4
+
5
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
6
+
7
+ var _index = _interopRequireWildcard(require("./lib/server"));
8
+
9
+ Object.defineProperty(exports, "__esModule", {
10
+ value: true
11
+ });
12
+ var _exportNames = {};
13
+ Object.defineProperty(exports, "default", {
14
+ enumerable: true,
15
+ get: function get() {
16
+ return _index.default;
17
+ }
18
+ });
19
+
20
+ Object.keys(_index).forEach(function (key) {
21
+ if (key === "default" || key === "__esModule") return;
22
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
23
+ if (key in exports && exports[key] === _index[key]) return;
24
+ Object.defineProperty(exports, key, {
25
+ enumerable: true,
26
+ get: function get() {
27
+ return _index[key];
28
+ }
29
+ });
30
+ });
@@ -0,0 +1,80 @@
1
+ import { css } from '@emotion/css';
2
+ import { connect, mapProps, mapReadPretty } from '@formily/react';
3
+ import { useRecord } from '@nocobase/client';
4
+ import { useBoolean } from 'ahooks';
5
+ import { DatePicker, Select, Space, Typography } from 'antd';
6
+ import moment from 'moment';
7
+ import React, { useMemo } from 'react';
8
+ import { useTranslation } from '../locale';
9
+
10
+ const TOMORROW = moment().add(1, 'days');
11
+
12
+ const spaceCSS = css`
13
+ width: 100%;
14
+ & > .ant-space-item {
15
+ flex: 1;
16
+ }
17
+ `;
18
+
19
+ const InternalExpiresSelect = (props) => {
20
+ const { onChange } = props;
21
+ const [isCustom, { toggle: toggleShowDatePicker, setFalse }] = useBoolean();
22
+
23
+ const onSelectChange = (v) => {
24
+ if (v === 'custom') {
25
+ onChange('1d');
26
+ return toggleShowDatePicker();
27
+ } else {
28
+ setFalse();
29
+ onChange(v);
30
+ }
31
+ };
32
+
33
+ const onDatePickerChange = (v: moment.Moment) => {
34
+ v = v.milliseconds(0).second(0);
35
+ const NOW = moment().milliseconds(0).seconds(0);
36
+ const value = `${v.diff(NOW, 'd')}d`;
37
+ onChange(value);
38
+ };
39
+
40
+ return (
41
+ <Space className={spaceCSS}>
42
+ <Select {...props} value={isCustom ? 'custom' : props.value} onChange={onSelectChange}></Select>
43
+ {isCustom ? (
44
+ <DatePicker
45
+ disabledDate={(time) => {
46
+ return time.isSameOrBefore();
47
+ }}
48
+ defaultValue={TOMORROW}
49
+ onChange={onDatePickerChange}
50
+ showToday={false}
51
+ allowClear={false}
52
+ />
53
+ ) : null}
54
+ </Space>
55
+ );
56
+ };
57
+
58
+ const ReadPretty = () => {
59
+ const { expiresIn, createdAt } = useRecord();
60
+ const { t } = useTranslation();
61
+ const expiresDate = useMemo(() => {
62
+ if (expiresIn === 'never') return t('Never expires');
63
+
64
+ return moment(createdAt)
65
+ .add(expiresIn?.replace('d', '') || 0, 'days')
66
+ .format('YYYY-MM-DD HH:mm:ss');
67
+ }, [createdAt, expiresIn]);
68
+
69
+ return <Typography.Text>{expiresDate}</Typography.Text>;
70
+ };
71
+
72
+ const ExpiresSelect = connect(
73
+ InternalExpiresSelect,
74
+ mapProps({
75
+ dataSource: 'options',
76
+ }),
77
+ mapReadPretty(ReadPretty),
78
+ );
79
+
80
+ export { ExpiresSelect };
@@ -0,0 +1,18 @@
1
+ import { RecursionField } from '@formily/react';
2
+ import { CollectionManagerProvider, SchemaComponentOptions, useCurrentRoles } from '@nocobase/client';
3
+ import React from 'react';
4
+ import { apiKeysCollection } from '../../collections';
5
+ import { ExpiresSelect } from './ExpiresSelect';
6
+ import { configurationSchema } from './schema';
7
+
8
+ export const Configuration = () => {
9
+ const currentRoles = useCurrentRoles();
10
+
11
+ return (
12
+ <CollectionManagerProvider collections={[apiKeysCollection]}>
13
+ <SchemaComponentOptions scope={{ currentRoles }} components={{ ExpiresSelect }}>
14
+ <RecursionField schema={configurationSchema} />
15
+ </SchemaComponentOptions>
16
+ </CollectionManagerProvider>
17
+ );
18
+ };
@@ -0,0 +1,9 @@
1
+ import { useCurrentRoles } from '@nocobase/client';
2
+
3
+ export const useCurrentRolesProps = () => {
4
+ const options = useCurrentRoles();
5
+
6
+ return {
7
+ options,
8
+ };
9
+ };
@@ -0,0 +1,264 @@
1
+ import { ISchema, useForm } from '@formily/react';
2
+ import { uid } from '@formily/shared';
3
+ import { useActionContext, useBlockRequestContext, useRecord } from '@nocobase/client';
4
+ import { Alert, Modal, Space, Typography } from 'antd';
5
+ import React from 'react';
6
+ import { generateNTemplate } from '../../locale';
7
+ import { useTranslation } from '../locale';
8
+ const { useModal } = Modal;
9
+
10
+ const useCreateAction = () => {
11
+ const form = useForm();
12
+ const { setVisible } = useActionContext();
13
+ const { resource, service } = useBlockRequestContext();
14
+ const { t } = useTranslation();
15
+ const [modalIns, element] = useModal();
16
+ return {
17
+ async run() {
18
+ await form.submit();
19
+ const response = await resource.create({
20
+ values: form.values,
21
+ });
22
+
23
+ modalIns.success({
24
+ title: t('API key created successfully'),
25
+ onOk: () => {
26
+ form.reset();
27
+ setVisible(false);
28
+ },
29
+ content: (
30
+ <Space direction="vertical">
31
+ <Alert
32
+ message={t('Make sure to copy your personal access key now as you will not be able to see this again.')}
33
+ type="warning"
34
+ ></Alert>
35
+ <Typography.Text copyable>{response.data?.data?.token}</Typography.Text>
36
+ </Space>
37
+ ),
38
+ });
39
+ service?.refresh();
40
+ },
41
+ element,
42
+ };
43
+ };
44
+
45
+ const useDestroyAction = () => {
46
+ const record = useRecord();
47
+ const { resource, service } = useBlockRequestContext();
48
+ return {
49
+ async run() {
50
+ await resource.destroy({
51
+ filterByTk: record.id,
52
+ });
53
+ service.refresh();
54
+ },
55
+ };
56
+ };
57
+
58
+ export const configurationSchema: ISchema = {
59
+ type: 'object',
60
+ properties: {
61
+ configuration: {
62
+ type: 'void',
63
+ 'x-decorator': 'TableBlockProvider',
64
+ 'x-decorator-props': {
65
+ collection: 'apiKeys',
66
+ resource: 'apiKeys',
67
+ action: 'list',
68
+ params: {
69
+ pageSize: 20,
70
+ appends: ['role'],
71
+ sort: ['-createdAt'],
72
+ },
73
+ rowKey: 'name',
74
+ showIndex: true,
75
+ },
76
+ 'x-component': 'CardItem',
77
+ properties: {
78
+ actions: {
79
+ type: 'void',
80
+ 'x-component': 'ActionBar',
81
+ 'x-component-props': {
82
+ style: {
83
+ marginBottom: 'var(--nb-spacing)',
84
+ },
85
+ },
86
+ properties: {
87
+ create: {
88
+ type: 'void',
89
+ 'x-action': 'create',
90
+ title: generateNTemplate('Add API key'),
91
+ 'x-component': 'Action',
92
+ 'x-component-props': {
93
+ openMode: 'drawer',
94
+ type: 'primary',
95
+ },
96
+ properties: {
97
+ drawer: {
98
+ type: 'void',
99
+ title: generateNTemplate('Add API key'),
100
+ 'x-decorator': 'Form',
101
+ 'x-component': 'Action.Modal',
102
+ 'x-component-props': {
103
+ maskClosable: false,
104
+ style: {
105
+ maxWidth: '520px',
106
+ width: '100%',
107
+ },
108
+ },
109
+ properties: {
110
+ name: {
111
+ type: 'string',
112
+ title: generateNTemplate('Key name'),
113
+ required: true,
114
+ 'x-component': 'CollectionField',
115
+ 'x-decorator': 'FormItem',
116
+ },
117
+ role: {
118
+ type: 'string',
119
+ title: generateNTemplate('Role'),
120
+ required: true,
121
+ 'x-collection-field': 'apiKeys.role',
122
+ 'x-component': 'CollectionField',
123
+ 'x-decorator': 'FormItem',
124
+ },
125
+ expiresIn: {
126
+ type: 'string',
127
+ title: generateNTemplate('Expiration'),
128
+ required: true,
129
+ 'x-component': 'CollectionField',
130
+ 'x-decorator': 'FormItem',
131
+ default: '30d',
132
+ },
133
+ footer: {
134
+ type: 'void',
135
+ 'x-component': 'Action.Modal.Footer',
136
+ properties: {
137
+ cancel: {
138
+ title: '{{t("Cancel")}}',
139
+ 'x-component': 'Action',
140
+ 'x-component-props': {
141
+ useAction: '{{ cm.useCancelAction }}',
142
+ },
143
+ },
144
+ submit: {
145
+ title: '{{t("Submit")}}',
146
+ 'x-component': 'Action',
147
+ 'x-component-props': {
148
+ type: 'primary',
149
+ useAction: useCreateAction,
150
+ },
151
+ },
152
+ },
153
+ },
154
+ },
155
+ },
156
+ },
157
+ 'x-align': 'right',
158
+ },
159
+ },
160
+ },
161
+ [uid()]: {
162
+ type: 'array',
163
+ 'x-component': 'TableV2',
164
+ 'x-component-props': {
165
+ rowKey: 'id',
166
+ useProps: '{{ useTableBlockProps }}',
167
+ },
168
+ properties: {
169
+ column1: {
170
+ type: 'void',
171
+ 'x-decorator': 'TableV2.Column.Decorator',
172
+ 'x-component': 'TableV2.Column',
173
+ title: generateNTemplate('Key name'),
174
+ properties: {
175
+ name: {
176
+ type: 'string',
177
+ 'x-component': 'CollectionField',
178
+ 'x-read-pretty': true,
179
+ },
180
+ },
181
+ },
182
+ column2: {
183
+ type: 'void',
184
+ 'x-decorator': 'TableV2.Column.Decorator',
185
+ 'x-component': 'TableV2.Column',
186
+ title: generateNTemplate('Role'),
187
+ properties: {
188
+ role: {
189
+ type: 'object',
190
+ 'x-collection-field': 'apiKeys.role',
191
+ 'x-component': 'CollectionField',
192
+ 'x-component-props': {
193
+ enableLink: false,
194
+ },
195
+ 'x-read-pretty': true,
196
+ },
197
+ },
198
+ },
199
+ column3: {
200
+ type: 'void',
201
+ 'x-decorator': 'TableV2.Column.Decorator',
202
+ 'x-component': 'TableV2.Column',
203
+ title: generateNTemplate('Expiration'),
204
+ properties: {
205
+ expiresIn: {
206
+ type: 'string',
207
+ 'x-component': 'CollectionField',
208
+ 'x-read-pretty': true,
209
+ },
210
+ },
211
+ },
212
+ column4: {
213
+ type: 'void',
214
+ 'x-decorator': 'TableV2.Column.Decorator',
215
+ 'x-component': 'TableV2.Column',
216
+ title: generateNTemplate('Created at'),
217
+ properties: {
218
+ createdAt: {
219
+ type: 'date',
220
+ // 'x-component': 'CollectionField',
221
+ 'x-component': 'DatePicker',
222
+ 'x-component-props': {
223
+ format: 'YYYY-MM-DD HH:mm:ss',
224
+ },
225
+ 'x-read-pretty': true,
226
+ },
227
+ },
228
+ },
229
+ actionColumn: {
230
+ type: 'void',
231
+ title: '{{ t("Actions") }}',
232
+ 'x-action-column': 'actions',
233
+ 'x-decorator': 'TableV2.Column.ActionBar',
234
+ 'x-component': 'TableV2.Column',
235
+ properties: {
236
+ columnActions: {
237
+ type: 'void',
238
+ 'x-component': 'Space',
239
+ 'x-component-props': {
240
+ split: '|',
241
+ },
242
+ properties: {
243
+ delete: {
244
+ type: 'void',
245
+ title: '{{ t("Delete") }}',
246
+ 'x-component': 'Action.Link',
247
+ 'x-component-props': {
248
+ confirm: {
249
+ title: generateNTemplate('Delete API key'),
250
+ content: "{{t('Are you sure you want to delete it?')}}",
251
+ },
252
+ useAction: useDestroyAction,
253
+ },
254
+ },
255
+ },
256
+ },
257
+ },
258
+ },
259
+ },
260
+ },
261
+ },
262
+ },
263
+ },
264
+ };