chore: migrate audit logs plugin
This commit is contained in:
		
							parent
							
								
									83f01305cb
								
							
						
					
					
						commit
						ac1e9abf77
					
				
							
								
								
									
										2
									
								
								packages/plugins/@hera/plugin-audit-logs/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								packages/plugins/@hera/plugin-audit-logs/.npmignore
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					/node_modules
 | 
				
			||||||
 | 
					/src
 | 
				
			||||||
							
								
								
									
										1
									
								
								packages/plugins/@hera/plugin-audit-logs/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/plugins/@hera/plugin-audit-logs/README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					# @hera/plugin-audit-logs
 | 
				
			||||||
							
								
								
									
										2
									
								
								packages/plugins/@hera/plugin-audit-logs/client.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								packages/plugins/@hera/plugin-audit-logs/client.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					export * from './dist/client';
 | 
				
			||||||
 | 
					export { default } from './dist/client';
 | 
				
			||||||
							
								
								
									
										1
									
								
								packages/plugins/@hera/plugin-audit-logs/client.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/plugins/@hera/plugin-audit-logs/client.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					module.exports = require('./dist/client/index.js');
 | 
				
			||||||
							
								
								
									
										24
									
								
								packages/plugins/@hera/plugin-audit-logs/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								packages/plugins/@hera/plugin-audit-logs/package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "@hera/plugin-audit-logs",
 | 
				
			||||||
 | 
					  "displayName": "Audit logs",
 | 
				
			||||||
 | 
					  "displayName.zh-CN": "审计日志",
 | 
				
			||||||
 | 
					  "description": "Audit logs.",
 | 
				
			||||||
 | 
					  "description.zh-CN": "审计日志。",
 | 
				
			||||||
 | 
					  "version": "1.0.0",
 | 
				
			||||||
 | 
					  "main": "dist/server/index.js",
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@ant-design/icons": "5.x",
 | 
				
			||||||
 | 
					    "@formily/antd-v5": "1.x",
 | 
				
			||||||
 | 
					    "@formily/react": "2.x",
 | 
				
			||||||
 | 
					    "@formily/shared": "2.x",
 | 
				
			||||||
 | 
					    "react": "^18.2.0",
 | 
				
			||||||
 | 
					    "react-i18next": "^11.15.1"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "peerDependencies": {
 | 
				
			||||||
 | 
					    "@nocobase/client": "0.x",
 | 
				
			||||||
 | 
					    "@nocobase/database": "0.x",
 | 
				
			||||||
 | 
					    "@nocobase/server": "0.x",
 | 
				
			||||||
 | 
					    "@nocobase/test": "0.x"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								packages/plugins/@hera/plugin-audit-logs/server.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								packages/plugins/@hera/plugin-audit-logs/server.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					export * from './dist/server';
 | 
				
			||||||
 | 
					export { default } from './dist/server';
 | 
				
			||||||
							
								
								
									
										1
									
								
								packages/plugins/@hera/plugin-audit-logs/server.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/plugins/@hera/plugin-audit-logs/server.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					module.exports = require('./dist/server/index.js');
 | 
				
			||||||
@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					import { TableOutlined } from '@ant-design/icons';
 | 
				
			||||||
 | 
					import { ISchema } from '@formily/react';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  createTableBlockSchema,
 | 
				
			||||||
 | 
					  SchemaInitializerItem,
 | 
				
			||||||
 | 
					  useSchemaInitializer,
 | 
				
			||||||
 | 
					  useSchemaInitializerItem,
 | 
				
			||||||
 | 
					} from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AuditLogsBlockInitializer = () => {
 | 
				
			||||||
 | 
					  const { insert } = useSchemaInitializer();
 | 
				
			||||||
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
 | 
					  const itemConfig = useSchemaInitializerItem();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const schema = createTableBlockSchema({
 | 
				
			||||||
 | 
					    collection: 'auditLogs',
 | 
				
			||||||
 | 
					    rowKey: 'id',
 | 
				
			||||||
 | 
					    tableActionInitializers: 'auditLogsTable:configureActions',
 | 
				
			||||||
 | 
					    tableColumnInitializers: 'auditLogsTable:configureColumns',
 | 
				
			||||||
 | 
					    tableActionColumnInitializers: 'auditLogsTable:configureItemActions',
 | 
				
			||||||
 | 
					    tableBlockProvider: 'AuditLogsBlockProvider',
 | 
				
			||||||
 | 
					    disableTemplate: true,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <SchemaInitializerItem
 | 
				
			||||||
 | 
					      icon={<TableOutlined />}
 | 
				
			||||||
 | 
					      onClick={() => {
 | 
				
			||||||
 | 
					        insert(schema as ISchema);
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					      title={t('Audit Logs')}
 | 
				
			||||||
 | 
					      {...itemConfig}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import { ExtendCollectionsProvider, TableBlockProvider } from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { useAuditChangesCollection, useAuditLogsCollection, useCollectionsCollection } from './collections';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AuditLogsBlockProvider: React.FC = ({ children, ...restProps }) => {
 | 
				
			||||||
 | 
					  const auditChangesCollection = useAuditChangesCollection();
 | 
				
			||||||
 | 
					  const auditLogsCollection = useAuditLogsCollection();
 | 
				
			||||||
 | 
					  const collectionsCollection = useCollectionsCollection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <ExtendCollectionsProvider collections={[auditLogsCollection, auditChangesCollection, collectionsCollection]}>
 | 
				
			||||||
 | 
					      <TableBlockProvider name="audit-logs" {...restProps}>
 | 
				
			||||||
 | 
					        {children}
 | 
				
			||||||
 | 
					      </TableBlockProvider>
 | 
				
			||||||
 | 
					    </ExtendCollectionsProvider>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					import { SchemaComponentOptions } from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { AuditLogsBlockInitializer } from './AuditLogsBlockInitializer';
 | 
				
			||||||
 | 
					import { AuditLogsBlockProvider } from './AuditLogsBlockProvider';
 | 
				
			||||||
 | 
					import { AuditLogsField } from './components/AuditLogsField';
 | 
				
			||||||
 | 
					import { AuditLogsValue } from './components/AuditLogsValue';
 | 
				
			||||||
 | 
					import { AuditLogsViewActionInitializer } from './components/AuditLogsViewActionInitializer';
 | 
				
			||||||
 | 
					import { AuditLogs } from './deplicated/AuditLogs';
 | 
				
			||||||
 | 
					import { AuditLogsTableActionColumnInitializer } from './initializers/AuditLogsTableActionColumnInitializer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AuditLogsProvider = (props: any) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <SchemaComponentOptions
 | 
				
			||||||
 | 
					      components={{
 | 
				
			||||||
 | 
					        AuditLogs,
 | 
				
			||||||
 | 
					        AuditLogsBlockProvider,
 | 
				
			||||||
 | 
					        AuditLogsBlockInitializer,
 | 
				
			||||||
 | 
					        AuditLogsValue,
 | 
				
			||||||
 | 
					        AuditLogsField,
 | 
				
			||||||
 | 
					        AuditLogsViewActionInitializer,
 | 
				
			||||||
 | 
					        AuditLogsTableActionColumnInitializer,
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      {props.children}
 | 
				
			||||||
 | 
					    </SchemaComponentOptions>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,166 @@
 | 
				
			|||||||
 | 
					import { useAuditLogsTranslation } from './locale';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useAuditLogsCollection = () => {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    name: 'auditLogs',
 | 
				
			||||||
 | 
					    title: '{{t("Audit logs")}}',
 | 
				
			||||||
 | 
					    fields: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'createdAt',
 | 
				
			||||||
 | 
					        type: 'date',
 | 
				
			||||||
 | 
					        interface: 'createdAt',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          type: 'datetime',
 | 
				
			||||||
 | 
					          title: '{{t("Created at")}}',
 | 
				
			||||||
 | 
					          'x-component': 'DatePicker',
 | 
				
			||||||
 | 
					          'x-component-props': {
 | 
				
			||||||
 | 
					            showTime: true,
 | 
				
			||||||
 | 
					            ellipsis: true,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          'x-read-pretty': true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'type',
 | 
				
			||||||
 | 
					        type: 'string',
 | 
				
			||||||
 | 
					        interface: 'select',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          type: 'string',
 | 
				
			||||||
 | 
					          title: '{{t("Action type")}}',
 | 
				
			||||||
 | 
					          'x-component': 'Select',
 | 
				
			||||||
 | 
					          'x-component-props': { ellipsis: true },
 | 
				
			||||||
 | 
					          'x-read-pretty': true,
 | 
				
			||||||
 | 
					          enum: [
 | 
				
			||||||
 | 
					            { label: '{{t("Create record")}}', value: 'create', color: 'lime' },
 | 
				
			||||||
 | 
					            { label: '{{t("Update record")}}', value: 'update', color: 'gold' },
 | 
				
			||||||
 | 
					            { label: '{{t("Delete record")}}', value: 'destroy', color: 'magenta' },
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'recordId',
 | 
				
			||||||
 | 
					        type: 'string',
 | 
				
			||||||
 | 
					        interface: 'input',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          title: '{{t("Record ID")}}',
 | 
				
			||||||
 | 
					          type: 'string',
 | 
				
			||||||
 | 
					          'x-component': 'Input',
 | 
				
			||||||
 | 
					          'x-component-props': { ellipsis: true },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        collectionName: 'auditLogs',
 | 
				
			||||||
 | 
					        name: 'collection',
 | 
				
			||||||
 | 
					        type: 'belongsTo',
 | 
				
			||||||
 | 
					        interface: 'm2o',
 | 
				
			||||||
 | 
					        target: 'collections',
 | 
				
			||||||
 | 
					        targetKey: 'name',
 | 
				
			||||||
 | 
					        sourceKey: 'id',
 | 
				
			||||||
 | 
					        foreignKey: 'collectionName',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          type: 'object',
 | 
				
			||||||
 | 
					          title: '{{t("Collection")}}',
 | 
				
			||||||
 | 
					          'x-component': 'AssociationField',
 | 
				
			||||||
 | 
					          'x-component-props': { fieldNames: { value: 'name', label: 'title' }, ellipsis: true },
 | 
				
			||||||
 | 
					          'x-read-pretty': true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'user',
 | 
				
			||||||
 | 
					        collectionName: 'auditLogs',
 | 
				
			||||||
 | 
					        type: 'belongsTo',
 | 
				
			||||||
 | 
					        interface: 'createdBy',
 | 
				
			||||||
 | 
					        targetKey: 'id',
 | 
				
			||||||
 | 
					        foreignKey: 'createdById',
 | 
				
			||||||
 | 
					        target: 'users',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          type: 'object',
 | 
				
			||||||
 | 
					          title: '{{t("User")}}',
 | 
				
			||||||
 | 
					          'x-component': 'AssociationField',
 | 
				
			||||||
 | 
					          'x-component-props': { fieldNames: { value: 'id', label: 'nickname' }, ellipsis: true },
 | 
				
			||||||
 | 
					          'x-read-pretty': true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'changes',
 | 
				
			||||||
 | 
					        collectionName: 'auditLogs',
 | 
				
			||||||
 | 
					        type: 'hasMany',
 | 
				
			||||||
 | 
					        interface: 'subTable',
 | 
				
			||||||
 | 
					        target: 'auditChanges',
 | 
				
			||||||
 | 
					        foreignKey: 'auditLogId',
 | 
				
			||||||
 | 
					        targetKey: 'id',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          type: 'object',
 | 
				
			||||||
 | 
					          title: '{{t("Details of changes", { ns: "audit-logs" })}}',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useAuditChangesCollection = () => {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    name: 'auditChanges',
 | 
				
			||||||
 | 
					    title: '{{t("Audit Changes")}}',
 | 
				
			||||||
 | 
					    fields: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'field',
 | 
				
			||||||
 | 
					        type: 'json',
 | 
				
			||||||
 | 
					        interface: 'input',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          title: '{{t("Field")}}',
 | 
				
			||||||
 | 
					          'x-component': 'AuditLogsField',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        type: 'json',
 | 
				
			||||||
 | 
					        name: 'before',
 | 
				
			||||||
 | 
					        interface: 'input',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          title: '{{t("Before change")}}',
 | 
				
			||||||
 | 
					          'x-component': 'AuditLogsValue',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        type: 'json',
 | 
				
			||||||
 | 
					        name: 'after',
 | 
				
			||||||
 | 
					        interface: 'input',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          title: '{{t("After change")}}',
 | 
				
			||||||
 | 
					          'x-component': 'AuditLogsValue',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCollectionsCollection = () => {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    name: 'collections',
 | 
				
			||||||
 | 
					    title: '{{t("Collections")}}',
 | 
				
			||||||
 | 
					    fields: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'name',
 | 
				
			||||||
 | 
					        type: 'string',
 | 
				
			||||||
 | 
					        interface: 'input',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          title: '{{t("Collection name")}}',
 | 
				
			||||||
 | 
					          type: 'string',
 | 
				
			||||||
 | 
					          'x-component': 'Input',
 | 
				
			||||||
 | 
					          'x-component-props': { ellipsis: true },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'title',
 | 
				
			||||||
 | 
					        type: 'string',
 | 
				
			||||||
 | 
					        interface: 'input',
 | 
				
			||||||
 | 
					        uiSchema: {
 | 
				
			||||||
 | 
					          title: '{{t("Collection display name")}}',
 | 
				
			||||||
 | 
					          type: 'string',
 | 
				
			||||||
 | 
					          'x-component': 'Input',
 | 
				
			||||||
 | 
					          'x-component-props': { ellipsis: true },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import { EllipsisWithTooltip, useCompile } from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { observer, useField } from '@formily/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AuditLogsField = observer(
 | 
				
			||||||
 | 
					  () => {
 | 
				
			||||||
 | 
					    const field = useField<any>();
 | 
				
			||||||
 | 
					    const compile = useCompile();
 | 
				
			||||||
 | 
					    if (!field.value) {
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <EllipsisWithTooltip ellipsis>
 | 
				
			||||||
 | 
					        {field.value?.uiSchema?.title ? compile(field.value?.uiSchema?.title) : field.value.name}
 | 
				
			||||||
 | 
					      </EllipsisWithTooltip>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  { displayName: 'AuditLogsField' },
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { EllipsisWithTooltip, FormProvider, SchemaComponent, useRecord } from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { observer, useField } from '@formily/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AuditLogsValue = observer(
 | 
				
			||||||
 | 
					  () => {
 | 
				
			||||||
 | 
					    const field = useField<any>();
 | 
				
			||||||
 | 
					    const record = useRecord();
 | 
				
			||||||
 | 
					    if (record.field?.uiSchema) {
 | 
				
			||||||
 | 
					      return (
 | 
				
			||||||
 | 
					        <FormProvider>
 | 
				
			||||||
 | 
					          <SchemaComponent
 | 
				
			||||||
 | 
					            schema={{
 | 
				
			||||||
 | 
					              name: record.field.name,
 | 
				
			||||||
 | 
					              ...record.field?.uiSchema,
 | 
				
			||||||
 | 
					              default: field.value,
 | 
				
			||||||
 | 
					              'x-read-pretty': true,
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </FormProvider>
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return <EllipsisWithTooltip ellipsis>{field.value ? JSON.stringify(field.value) : null}</EllipsisWithTooltip>;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  { displayName: 'AuditLogsValue' },
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
@ -0,0 +1,343 @@
 | 
				
			|||||||
 | 
					import { ActionInitializer } from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AuditLogsViewActionInitializer = () => {
 | 
				
			||||||
 | 
					  const schema = {
 | 
				
			||||||
 | 
					    type: 'void',
 | 
				
			||||||
 | 
					    title: '{{ t("View") }}',
 | 
				
			||||||
 | 
					    'x-action': 'view',
 | 
				
			||||||
 | 
					    // 'x-designer': 'Action.Designer',
 | 
				
			||||||
 | 
					    'x-toolbar': 'ActionSchemaToolbar',
 | 
				
			||||||
 | 
					    'x-settings': 'actionSettings:view',
 | 
				
			||||||
 | 
					    'x-component': 'Action',
 | 
				
			||||||
 | 
					    'x-component-props': {
 | 
				
			||||||
 | 
					      openMode: 'drawer',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					      drawer: {
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        title: '{{ t("View record") }}',
 | 
				
			||||||
 | 
					        'x-component': 'Action.Container',
 | 
				
			||||||
 | 
					        'x-component-props': {
 | 
				
			||||||
 | 
					          className: 'nb-action-popup',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          tabs: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            'x-component': 'Tabs',
 | 
				
			||||||
 | 
					            'x-component-props': {},
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              tab1: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                title: '{{t("Details")}}',
 | 
				
			||||||
 | 
					                'x-component': 'Tabs.TabPane',
 | 
				
			||||||
 | 
					                'x-designer': 'Tabs.Designer',
 | 
				
			||||||
 | 
					                'x-component-props': {},
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  grid: {
 | 
				
			||||||
 | 
					                    type: 'void',
 | 
				
			||||||
 | 
					                    'x-component': 'Grid',
 | 
				
			||||||
 | 
					                    properties: {
 | 
				
			||||||
 | 
					                      '7ypqrxaqysp': {
 | 
				
			||||||
 | 
					                        type: 'void',
 | 
				
			||||||
 | 
					                        'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                        properties: {
 | 
				
			||||||
 | 
					                          '1fc2l8dwe7m': {
 | 
				
			||||||
 | 
					                            type: 'void',
 | 
				
			||||||
 | 
					                            'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                            properties: {
 | 
				
			||||||
 | 
					                              '5ley6xifrsb': {
 | 
				
			||||||
 | 
					                                type: 'void',
 | 
				
			||||||
 | 
					                                'x-acl-action': 'auditLogs:get',
 | 
				
			||||||
 | 
					                                'x-decorator': 'FormBlockProvider',
 | 
				
			||||||
 | 
					                                'x-decorator-props': {
 | 
				
			||||||
 | 
					                                  resource: 'auditLogs',
 | 
				
			||||||
 | 
					                                  collection: 'auditLogs',
 | 
				
			||||||
 | 
					                                  readPretty: true,
 | 
				
			||||||
 | 
					                                  action: 'get',
 | 
				
			||||||
 | 
					                                  params: {
 | 
				
			||||||
 | 
					                                    appends: ['collection', 'user', 'changes'],
 | 
				
			||||||
 | 
					                                  },
 | 
				
			||||||
 | 
					                                  useParams: '{{ useParamsFromRecord }}',
 | 
				
			||||||
 | 
					                                  useSourceId: '{{ useSourceIdFromParentRecord }}',
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                'x-component': 'CardItem',
 | 
				
			||||||
 | 
					                                properties: {
 | 
				
			||||||
 | 
					                                  bv710pbf9w6: {
 | 
				
			||||||
 | 
					                                    type: 'void',
 | 
				
			||||||
 | 
					                                    'x-component': 'FormV2',
 | 
				
			||||||
 | 
					                                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                    'x-component-props': {
 | 
				
			||||||
 | 
					                                      useProps: '{{ useFormBlockProps }}',
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                    properties: {
 | 
				
			||||||
 | 
					                                      grid: {
 | 
				
			||||||
 | 
					                                        type: 'void',
 | 
				
			||||||
 | 
					                                        'x-component': 'Grid',
 | 
				
			||||||
 | 
					                                        properties: {
 | 
				
			||||||
 | 
					                                          g4c24abnbd9: {
 | 
				
			||||||
 | 
					                                            type: 'void',
 | 
				
			||||||
 | 
					                                            'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                            properties: {
 | 
				
			||||||
 | 
					                                              fkt9dj5lu1k: {
 | 
				
			||||||
 | 
					                                                type: 'void',
 | 
				
			||||||
 | 
					                                                'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                properties: {
 | 
				
			||||||
 | 
					                                                  createdAt: {
 | 
				
			||||||
 | 
					                                                    type: 'string',
 | 
				
			||||||
 | 
					                                                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                    'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                    'x-collection-field': 'auditLogs.createdAt',
 | 
				
			||||||
 | 
					                                                    'x-component-props': {},
 | 
				
			||||||
 | 
					                                                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                  },
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                            },
 | 
				
			||||||
 | 
					                                          },
 | 
				
			||||||
 | 
					                                          l267bkv423v: {
 | 
				
			||||||
 | 
					                                            type: 'void',
 | 
				
			||||||
 | 
					                                            'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                            properties: {
 | 
				
			||||||
 | 
					                                              tehaepm5xqy: {
 | 
				
			||||||
 | 
					                                                type: 'void',
 | 
				
			||||||
 | 
					                                                'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                properties: {
 | 
				
			||||||
 | 
					                                                  type: {
 | 
				
			||||||
 | 
					                                                    type: 'string',
 | 
				
			||||||
 | 
					                                                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                    'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                    'x-collection-field': 'auditLogs.type',
 | 
				
			||||||
 | 
					                                                    'x-component-props': {},
 | 
				
			||||||
 | 
					                                                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                  },
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                            },
 | 
				
			||||||
 | 
					                                          },
 | 
				
			||||||
 | 
					                                          zhmn2tkzdh2: {
 | 
				
			||||||
 | 
					                                            type: 'void',
 | 
				
			||||||
 | 
					                                            'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                            properties: {
 | 
				
			||||||
 | 
					                                              yuwyej17i64: {
 | 
				
			||||||
 | 
					                                                type: 'void',
 | 
				
			||||||
 | 
					                                                'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                properties: {
 | 
				
			||||||
 | 
					                                                  recordId: {
 | 
				
			||||||
 | 
					                                                    type: 'string',
 | 
				
			||||||
 | 
					                                                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                    'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                    'x-collection-field': 'auditLogs.recordId',
 | 
				
			||||||
 | 
					                                                    'x-component-props': {},
 | 
				
			||||||
 | 
					                                                  },
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                            },
 | 
				
			||||||
 | 
					                                          },
 | 
				
			||||||
 | 
					                                          '6q933ic06mj': {
 | 
				
			||||||
 | 
					                                            type: 'void',
 | 
				
			||||||
 | 
					                                            'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                            properties: {
 | 
				
			||||||
 | 
					                                              nwtbkqd99zl2: {
 | 
				
			||||||
 | 
					                                                type: 'void',
 | 
				
			||||||
 | 
					                                                'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                properties: {
 | 
				
			||||||
 | 
					                                                  'collection.title': {
 | 
				
			||||||
 | 
					                                                    type: 'string',
 | 
				
			||||||
 | 
					                                                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                    'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                    'x-collection-field': 'auditLogs.collection.title',
 | 
				
			||||||
 | 
					                                                    'x-component-props': {},
 | 
				
			||||||
 | 
					                                                  },
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                              nwtbkqd99zl1: {
 | 
				
			||||||
 | 
					                                                type: 'void',
 | 
				
			||||||
 | 
					                                                'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                properties: {
 | 
				
			||||||
 | 
					                                                  'collection.name': {
 | 
				
			||||||
 | 
					                                                    type: 'string',
 | 
				
			||||||
 | 
					                                                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                    'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                    'x-collection-field': 'auditLogs.collection.name',
 | 
				
			||||||
 | 
					                                                    'x-component-props': {},
 | 
				
			||||||
 | 
					                                                  },
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                            },
 | 
				
			||||||
 | 
					                                          },
 | 
				
			||||||
 | 
					                                          xd4kzulndqk: {
 | 
				
			||||||
 | 
					                                            type: 'void',
 | 
				
			||||||
 | 
					                                            'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                            properties: {
 | 
				
			||||||
 | 
					                                              k3sd72n83zd: {
 | 
				
			||||||
 | 
					                                                type: 'void',
 | 
				
			||||||
 | 
					                                                'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                properties: {
 | 
				
			||||||
 | 
					                                                  user: {
 | 
				
			||||||
 | 
					                                                    type: 'string',
 | 
				
			||||||
 | 
					                                                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                    'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                    'x-collection-field': 'auditLogs.user',
 | 
				
			||||||
 | 
					                                                    'x-component-props': {},
 | 
				
			||||||
 | 
					                                                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                    properties: {
 | 
				
			||||||
 | 
					                                                      viewer: {
 | 
				
			||||||
 | 
					                                                        type: 'void',
 | 
				
			||||||
 | 
					                                                        title: '{{ t("View record") }}',
 | 
				
			||||||
 | 
					                                                        'x-component': 'RecordPicker.Viewer',
 | 
				
			||||||
 | 
					                                                        'x-component-props': {
 | 
				
			||||||
 | 
					                                                          className: 'nb-action-popup',
 | 
				
			||||||
 | 
					                                                        },
 | 
				
			||||||
 | 
					                                                        properties: {
 | 
				
			||||||
 | 
					                                                          tabs: {
 | 
				
			||||||
 | 
					                                                            type: 'void',
 | 
				
			||||||
 | 
					                                                            'x-component': 'Tabs',
 | 
				
			||||||
 | 
					                                                            'x-component-props': {},
 | 
				
			||||||
 | 
					                                                            'x-initializer': 'TabPaneInitializers',
 | 
				
			||||||
 | 
					                                                            properties: {
 | 
				
			||||||
 | 
					                                                              tab1: {
 | 
				
			||||||
 | 
					                                                                type: 'void',
 | 
				
			||||||
 | 
					                                                                title: '{{t("Details")}}',
 | 
				
			||||||
 | 
					                                                                'x-component': 'Tabs.TabPane',
 | 
				
			||||||
 | 
					                                                                'x-designer': 'Tabs.Designer',
 | 
				
			||||||
 | 
					                                                                'x-component-props': {},
 | 
				
			||||||
 | 
					                                                                properties: {
 | 
				
			||||||
 | 
					                                                                  grid: {
 | 
				
			||||||
 | 
					                                                                    type: 'void',
 | 
				
			||||||
 | 
					                                                                    'x-component': 'Grid',
 | 
				
			||||||
 | 
					                                                                    'x-initializer': 'popup:common:addBlock',
 | 
				
			||||||
 | 
					                                                                  },
 | 
				
			||||||
 | 
					                                                                },
 | 
				
			||||||
 | 
					                                                              },
 | 
				
			||||||
 | 
					                                                            },
 | 
				
			||||||
 | 
					                                                          },
 | 
				
			||||||
 | 
					                                                        },
 | 
				
			||||||
 | 
					                                                      },
 | 
				
			||||||
 | 
					                                                    },
 | 
				
			||||||
 | 
					                                                  },
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                            },
 | 
				
			||||||
 | 
					                                          },
 | 
				
			||||||
 | 
					                                          '3lghgclbtcg': {
 | 
				
			||||||
 | 
					                                            type: 'void',
 | 
				
			||||||
 | 
					                                            'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                            properties: {
 | 
				
			||||||
 | 
					                                              '8l1v1auwlx0': {
 | 
				
			||||||
 | 
					                                                type: 'void',
 | 
				
			||||||
 | 
					                                                'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                properties: {
 | 
				
			||||||
 | 
					                                                  changes: {
 | 
				
			||||||
 | 
					                                                    type: 'void',
 | 
				
			||||||
 | 
					                                                    'x-component': 'TableField',
 | 
				
			||||||
 | 
					                                                    'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                    'x-collection-field': 'auditLogs.changes',
 | 
				
			||||||
 | 
					                                                    'x-component-props': {},
 | 
				
			||||||
 | 
					                                                    properties: {
 | 
				
			||||||
 | 
					                                                      block: {
 | 
				
			||||||
 | 
					                                                        type: 'void',
 | 
				
			||||||
 | 
					                                                        'x-decorator': 'TableFieldProvider',
 | 
				
			||||||
 | 
					                                                        'x-acl-action': 'auditChanges:list',
 | 
				
			||||||
 | 
					                                                        'x-decorator-props': {
 | 
				
			||||||
 | 
					                                                          collection: 'auditChanges',
 | 
				
			||||||
 | 
					                                                          association: 'auditLogs.changes',
 | 
				
			||||||
 | 
					                                                          resource: 'auditLogs.changes',
 | 
				
			||||||
 | 
					                                                          action: 'list',
 | 
				
			||||||
 | 
					                                                          params: {
 | 
				
			||||||
 | 
					                                                            paginate: false,
 | 
				
			||||||
 | 
					                                                          },
 | 
				
			||||||
 | 
					                                                          showIndex: true,
 | 
				
			||||||
 | 
					                                                          dragSort: false,
 | 
				
			||||||
 | 
					                                                        },
 | 
				
			||||||
 | 
					                                                        properties: {
 | 
				
			||||||
 | 
					                                                          actions: {
 | 
				
			||||||
 | 
					                                                            type: 'void',
 | 
				
			||||||
 | 
					                                                            'x-component': 'TableField.ActionBar',
 | 
				
			||||||
 | 
					                                                            'x-component-props': {},
 | 
				
			||||||
 | 
					                                                          },
 | 
				
			||||||
 | 
					                                                          changes: {
 | 
				
			||||||
 | 
					                                                            type: 'array',
 | 
				
			||||||
 | 
					                                                            'x-component': 'TableV2',
 | 
				
			||||||
 | 
					                                                            'x-component-props': {
 | 
				
			||||||
 | 
					                                                              rowSelection: false,
 | 
				
			||||||
 | 
					                                                              useProps: '{{ useTableFieldProps }}',
 | 
				
			||||||
 | 
					                                                            },
 | 
				
			||||||
 | 
					                                                            properties: {
 | 
				
			||||||
 | 
					                                                              '5uvv96u9ict': {
 | 
				
			||||||
 | 
					                                                                type: 'void',
 | 
				
			||||||
 | 
					                                                                'x-decorator': 'TableV2.Column.Decorator',
 | 
				
			||||||
 | 
					                                                                'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                                                                properties: {
 | 
				
			||||||
 | 
					                                                                  field: {
 | 
				
			||||||
 | 
					                                                                    'x-collection-field': 'auditChanges.field',
 | 
				
			||||||
 | 
					                                                                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                                    'x-component-props': {
 | 
				
			||||||
 | 
					                                                                      ellipsis: true,
 | 
				
			||||||
 | 
					                                                                    },
 | 
				
			||||||
 | 
					                                                                  },
 | 
				
			||||||
 | 
					                                                                },
 | 
				
			||||||
 | 
					                                                              },
 | 
				
			||||||
 | 
					                                                              h7a4tgt11gd: {
 | 
				
			||||||
 | 
					                                                                type: 'void',
 | 
				
			||||||
 | 
					                                                                'x-decorator': 'TableV2.Column.Decorator',
 | 
				
			||||||
 | 
					                                                                'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                                                                properties: {
 | 
				
			||||||
 | 
					                                                                  before: {
 | 
				
			||||||
 | 
					                                                                    'x-collection-field': 'auditChanges.before',
 | 
				
			||||||
 | 
					                                                                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                                    'x-component-props': {
 | 
				
			||||||
 | 
					                                                                      ellipsis: true,
 | 
				
			||||||
 | 
					                                                                    },
 | 
				
			||||||
 | 
					                                                                  },
 | 
				
			||||||
 | 
					                                                                },
 | 
				
			||||||
 | 
					                                                              },
 | 
				
			||||||
 | 
					                                                              m275z8rglzx: {
 | 
				
			||||||
 | 
					                                                                type: 'void',
 | 
				
			||||||
 | 
					                                                                'x-decorator': 'TableV2.Column.Decorator',
 | 
				
			||||||
 | 
					                                                                'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                                                                properties: {
 | 
				
			||||||
 | 
					                                                                  after: {
 | 
				
			||||||
 | 
					                                                                    'x-collection-field': 'auditChanges.after',
 | 
				
			||||||
 | 
					                                                                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                                    'x-component-props': {
 | 
				
			||||||
 | 
					                                                                      ellipsis: true,
 | 
				
			||||||
 | 
					                                                                    },
 | 
				
			||||||
 | 
					                                                                  },
 | 
				
			||||||
 | 
					                                                                },
 | 
				
			||||||
 | 
					                                                              },
 | 
				
			||||||
 | 
					                                                            },
 | 
				
			||||||
 | 
					                                                          },
 | 
				
			||||||
 | 
					                                                        },
 | 
				
			||||||
 | 
					                                                      },
 | 
				
			||||||
 | 
					                                                    },
 | 
				
			||||||
 | 
					                                                  },
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                            },
 | 
				
			||||||
 | 
					                                          },
 | 
				
			||||||
 | 
					                                        },
 | 
				
			||||||
 | 
					                                      },
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                  },
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return <ActionInitializer schema={schema} />;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,513 @@
 | 
				
			|||||||
 | 
					import { ArrayTable } from '@formily/antd-v5';
 | 
				
			||||||
 | 
					import { observer, useField } from '@formily/react';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ExtendCollectionsProvider,
 | 
				
			||||||
 | 
					  FormProvider,
 | 
				
			||||||
 | 
					  SchemaComponent,
 | 
				
			||||||
 | 
					  TableBlockProvider,
 | 
				
			||||||
 | 
					  useCollection_deprecated,
 | 
				
			||||||
 | 
					  useCompile,
 | 
				
			||||||
 | 
					  useRecord,
 | 
				
			||||||
 | 
					} from '@nocobase/client';
 | 
				
			||||||
 | 
					import React, { createContext, useContext } from 'react';
 | 
				
			||||||
 | 
					import { AuditLogsDesigner } from './AuditLogsDesigner';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const collection = {
 | 
				
			||||||
 | 
					  name: 'auditLogs',
 | 
				
			||||||
 | 
					  title: '{{t("Audit logs")}}',
 | 
				
			||||||
 | 
					  fields: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'createdAt',
 | 
				
			||||||
 | 
					      type: 'date',
 | 
				
			||||||
 | 
					      interface: 'createdAt',
 | 
				
			||||||
 | 
					      uiSchema: {
 | 
				
			||||||
 | 
					        type: 'datetime',
 | 
				
			||||||
 | 
					        title: '{{t("Created at")}}',
 | 
				
			||||||
 | 
					        'x-component': 'DatePicker',
 | 
				
			||||||
 | 
					        'x-component-props': {
 | 
				
			||||||
 | 
					          showTime: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        'x-read-pretty': true,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'type',
 | 
				
			||||||
 | 
					      type: 'string',
 | 
				
			||||||
 | 
					      interface: 'select',
 | 
				
			||||||
 | 
					      uiSchema: {
 | 
				
			||||||
 | 
					        type: 'string',
 | 
				
			||||||
 | 
					        title: '{{t("Action type")}}',
 | 
				
			||||||
 | 
					        'x-component': 'Select',
 | 
				
			||||||
 | 
					        'x-read-pretty': true,
 | 
				
			||||||
 | 
					        enum: [
 | 
				
			||||||
 | 
					          { label: '{{t("Create record")}}', value: 'create', color: 'lime' },
 | 
				
			||||||
 | 
					          { label: '{{t("Update record")}}', value: 'update', color: 'gold' },
 | 
				
			||||||
 | 
					          { label: '{{t("Delete record")}}', value: 'destroy', color: 'magenta' },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Username = observer(
 | 
				
			||||||
 | 
					  () => {
 | 
				
			||||||
 | 
					    const field = useField<any>();
 | 
				
			||||||
 | 
					    return <div>{field?.value?.nickname || field.value?.id}</div>;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  { displayName: 'Username' },
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Collection = observer(
 | 
				
			||||||
 | 
					  () => {
 | 
				
			||||||
 | 
					    const field = useField<any>();
 | 
				
			||||||
 | 
					    const { title, name } = field.value || {};
 | 
				
			||||||
 | 
					    const compile = useCompile();
 | 
				
			||||||
 | 
					    return <div>{title ? compile(title) : name}</div>;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  { displayName: 'Collection' },
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Field = observer(
 | 
				
			||||||
 | 
					  () => {
 | 
				
			||||||
 | 
					    const field = useField<any>();
 | 
				
			||||||
 | 
					    const compile = useCompile();
 | 
				
			||||||
 | 
					    if (!field.value) {
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return <div>{field.value?.uiSchema?.title ? compile(field.value?.uiSchema?.title) : field.value.name}</div>;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  { displayName: 'Field' },
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Value = observer(
 | 
				
			||||||
 | 
					  () => {
 | 
				
			||||||
 | 
					    const field = useField<any>();
 | 
				
			||||||
 | 
					    const record = ArrayTable.useRecord();
 | 
				
			||||||
 | 
					    if (record.field?.uiSchema) {
 | 
				
			||||||
 | 
					      return (
 | 
				
			||||||
 | 
					        <FormProvider>
 | 
				
			||||||
 | 
					          <SchemaComponent
 | 
				
			||||||
 | 
					            schema={{
 | 
				
			||||||
 | 
					              name: record.field.name,
 | 
				
			||||||
 | 
					              ...record.field?.uiSchema,
 | 
				
			||||||
 | 
					              default: field.value,
 | 
				
			||||||
 | 
					              'x-read-pretty': true,
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </FormProvider>
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return <div>{field.value ? JSON.stringify(field.value) : null}</div>;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  { displayName: 'Value' },
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const IsAssociationBlock = createContext(null);
 | 
				
			||||||
 | 
					IsAssociationBlock.displayName = 'IsAssociationBlock';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AuditLogs: any = () => {
 | 
				
			||||||
 | 
					  const isAssoc = useContext(IsAssociationBlock);
 | 
				
			||||||
 | 
					  const ext = {};
 | 
				
			||||||
 | 
					  if (!isAssoc) {
 | 
				
			||||||
 | 
					    ext['column31'] = {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					      title: '{{t("Record ID")}}',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        recordId: {
 | 
				
			||||||
 | 
					          'x-component': 'Input',
 | 
				
			||||||
 | 
					          'x-read-pretty': true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <SchemaComponent
 | 
				
			||||||
 | 
					      memoized
 | 
				
			||||||
 | 
					      components={{ ArrayTable, Username, Collection, Field, Value }}
 | 
				
			||||||
 | 
					      schema={{
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        name: 'lfm4trkw8j3',
 | 
				
			||||||
 | 
					        'x-component': 'div',
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          actions: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            'x-component': 'ActionBar',
 | 
				
			||||||
 | 
					            'x-component-props': {
 | 
				
			||||||
 | 
					              style: {
 | 
				
			||||||
 | 
					                marginBottom: 16,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              filter: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                title: '{{ t("Filter") }}',
 | 
				
			||||||
 | 
					                'x-action': 'filter',
 | 
				
			||||||
 | 
					                // 'x-designer': 'Filter.Action.Designer',
 | 
				
			||||||
 | 
					                'x-component': 'Filter.Action',
 | 
				
			||||||
 | 
					                'x-component-props': {
 | 
				
			||||||
 | 
					                  icon: 'FilterOutlined',
 | 
				
			||||||
 | 
					                  useProps: '{{ useFilterActionProps }}',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                'x-align': 'left',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          y84dlntcaup: {
 | 
				
			||||||
 | 
					            type: 'array',
 | 
				
			||||||
 | 
					            'x-component': 'TableV2',
 | 
				
			||||||
 | 
					            'x-component-props': {
 | 
				
			||||||
 | 
					              rowKey: 'id',
 | 
				
			||||||
 | 
					              rowSelection: {
 | 
				
			||||||
 | 
					                type: 'checkbox',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              useProps: '{{ useTableBlockProps }}',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              actions: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                title: '{{ t("Actions") }}',
 | 
				
			||||||
 | 
					                'x-action-column': 'actions',
 | 
				
			||||||
 | 
					                'x-decorator': 'TableV2.Column.ActionBar',
 | 
				
			||||||
 | 
					                'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                'x-designer': 'TableV2.ActionColumnDesigner',
 | 
				
			||||||
 | 
					                'x-initializer': 'table:configureItemActions',
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  actions: {
 | 
				
			||||||
 | 
					                    type: 'void',
 | 
				
			||||||
 | 
					                    'x-decorator': 'DndContext',
 | 
				
			||||||
 | 
					                    'x-component': 'Space',
 | 
				
			||||||
 | 
					                    'x-component-props': {
 | 
				
			||||||
 | 
					                      split: '|',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    properties: {
 | 
				
			||||||
 | 
					                      o80rypwmeeg: {
 | 
				
			||||||
 | 
					                        type: 'void',
 | 
				
			||||||
 | 
					                        title: '{{ t("View") }}',
 | 
				
			||||||
 | 
					                        // 'x-designer': 'Action.Designer',
 | 
				
			||||||
 | 
					                        'x-toolbar': 'ActionSchemaToolbar',
 | 
				
			||||||
 | 
					                        'x-settings': 'actionSettings:view',
 | 
				
			||||||
 | 
					                        'x-component': 'Action.Link',
 | 
				
			||||||
 | 
					                        'x-component-props': {
 | 
				
			||||||
 | 
					                          openMode: 'drawer',
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        properties: {
 | 
				
			||||||
 | 
					                          drawer: {
 | 
				
			||||||
 | 
					                            type: 'void',
 | 
				
			||||||
 | 
					                            title: '{{ t("View record") }}',
 | 
				
			||||||
 | 
					                            'x-component': 'Action.Container',
 | 
				
			||||||
 | 
					                            'x-component-props': {
 | 
				
			||||||
 | 
					                              className: 'nb-action-popup',
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            properties: {
 | 
				
			||||||
 | 
					                              grid: {
 | 
				
			||||||
 | 
					                                type: 'void',
 | 
				
			||||||
 | 
					                                'x-component': 'Grid',
 | 
				
			||||||
 | 
					                                properties: {
 | 
				
			||||||
 | 
					                                  tdlav8o9o17: {
 | 
				
			||||||
 | 
					                                    type: 'void',
 | 
				
			||||||
 | 
					                                    'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                    properties: {
 | 
				
			||||||
 | 
					                                      '7bsnaf47i6g': {
 | 
				
			||||||
 | 
					                                        type: 'void',
 | 
				
			||||||
 | 
					                                        'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                        properties: {
 | 
				
			||||||
 | 
					                                          '6s2qbihe3tu': {
 | 
				
			||||||
 | 
					                                            type: 'void',
 | 
				
			||||||
 | 
					                                            'x-acl-action': 'auditLogs:get',
 | 
				
			||||||
 | 
					                                            'x-decorator': 'FormBlockProvider',
 | 
				
			||||||
 | 
					                                            'x-decorator-props': {
 | 
				
			||||||
 | 
					                                              resource: 'auditLogs',
 | 
				
			||||||
 | 
					                                              collection: 'auditLogs',
 | 
				
			||||||
 | 
					                                              readPretty: true,
 | 
				
			||||||
 | 
					                                              action: 'get',
 | 
				
			||||||
 | 
					                                              params: {
 | 
				
			||||||
 | 
					                                                appends: ['collection', 'user', 'changes'],
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                              useParams: '{{ useParamsFromRecord }}',
 | 
				
			||||||
 | 
					                                              useSourceId: '{{ useSourceIdFromParentRecord }}',
 | 
				
			||||||
 | 
					                                            },
 | 
				
			||||||
 | 
					                                            'x-component': 'CardItem',
 | 
				
			||||||
 | 
					                                            properties: {
 | 
				
			||||||
 | 
					                                              mevpuonrda0: {
 | 
				
			||||||
 | 
					                                                type: 'void',
 | 
				
			||||||
 | 
					                                                'x-component': 'FormV2',
 | 
				
			||||||
 | 
					                                                'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                'x-component-props': {
 | 
				
			||||||
 | 
					                                                  useProps: '{{ useFormBlockProps }}',
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                                properties: {
 | 
				
			||||||
 | 
					                                                  grid: {
 | 
				
			||||||
 | 
					                                                    type: 'void',
 | 
				
			||||||
 | 
					                                                    'x-component': 'Grid',
 | 
				
			||||||
 | 
					                                                    properties: {
 | 
				
			||||||
 | 
					                                                      row1: {
 | 
				
			||||||
 | 
					                                                        type: 'void',
 | 
				
			||||||
 | 
					                                                        'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                                        properties: {
 | 
				
			||||||
 | 
					                                                          col11: {
 | 
				
			||||||
 | 
					                                                            type: 'void',
 | 
				
			||||||
 | 
					                                                            'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                            properties: {
 | 
				
			||||||
 | 
					                                                              collection: {
 | 
				
			||||||
 | 
					                                                                type: 'string',
 | 
				
			||||||
 | 
					                                                                title: '{{t("Collection display name")}}',
 | 
				
			||||||
 | 
					                                                                'x-component': 'Collection',
 | 
				
			||||||
 | 
					                                                                'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                                'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                              },
 | 
				
			||||||
 | 
					                                                            },
 | 
				
			||||||
 | 
					                                                          },
 | 
				
			||||||
 | 
					                                                        },
 | 
				
			||||||
 | 
					                                                      },
 | 
				
			||||||
 | 
					                                                      row2: {
 | 
				
			||||||
 | 
					                                                        type: 'void',
 | 
				
			||||||
 | 
					                                                        'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                                        properties: {
 | 
				
			||||||
 | 
					                                                          col21: {
 | 
				
			||||||
 | 
					                                                            type: 'void',
 | 
				
			||||||
 | 
					                                                            'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                            properties: {
 | 
				
			||||||
 | 
					                                                              type: {
 | 
				
			||||||
 | 
					                                                                type: 'string',
 | 
				
			||||||
 | 
					                                                                'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                                'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                                'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                              },
 | 
				
			||||||
 | 
					                                                            },
 | 
				
			||||||
 | 
					                                                          },
 | 
				
			||||||
 | 
					                                                        },
 | 
				
			||||||
 | 
					                                                      },
 | 
				
			||||||
 | 
					                                                      row3: {
 | 
				
			||||||
 | 
					                                                        type: 'void',
 | 
				
			||||||
 | 
					                                                        'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                                        properties: {
 | 
				
			||||||
 | 
					                                                          col31: {
 | 
				
			||||||
 | 
					                                                            type: 'void',
 | 
				
			||||||
 | 
					                                                            'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                            properties: {
 | 
				
			||||||
 | 
					                                                              createdAt: {
 | 
				
			||||||
 | 
					                                                                type: 'string',
 | 
				
			||||||
 | 
					                                                                'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                                                                'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                                'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                              },
 | 
				
			||||||
 | 
					                                                            },
 | 
				
			||||||
 | 
					                                                          },
 | 
				
			||||||
 | 
					                                                        },
 | 
				
			||||||
 | 
					                                                      },
 | 
				
			||||||
 | 
					                                                      row4: {
 | 
				
			||||||
 | 
					                                                        type: 'void',
 | 
				
			||||||
 | 
					                                                        'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                                        properties: {
 | 
				
			||||||
 | 
					                                                          col41: {
 | 
				
			||||||
 | 
					                                                            type: 'void',
 | 
				
			||||||
 | 
					                                                            'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                            properties: {
 | 
				
			||||||
 | 
					                                                              user: {
 | 
				
			||||||
 | 
					                                                                type: 'string',
 | 
				
			||||||
 | 
					                                                                title: '{{t("User")}}',
 | 
				
			||||||
 | 
					                                                                'x-component': 'Username',
 | 
				
			||||||
 | 
					                                                                'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                                'x-read-pretty': true,
 | 
				
			||||||
 | 
					                                                              },
 | 
				
			||||||
 | 
					                                                            },
 | 
				
			||||||
 | 
					                                                          },
 | 
				
			||||||
 | 
					                                                        },
 | 
				
			||||||
 | 
					                                                      },
 | 
				
			||||||
 | 
					                                                      row5: {
 | 
				
			||||||
 | 
					                                                        type: 'void',
 | 
				
			||||||
 | 
					                                                        'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					                                                        properties: {
 | 
				
			||||||
 | 
					                                                          col51: {
 | 
				
			||||||
 | 
					                                                            type: 'void',
 | 
				
			||||||
 | 
					                                                            'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					                                                            properties: {
 | 
				
			||||||
 | 
					                                                              changes: {
 | 
				
			||||||
 | 
					                                                                type: 'array',
 | 
				
			||||||
 | 
					                                                                title: '{{t("Field value changes")}}',
 | 
				
			||||||
 | 
					                                                                'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                                'x-component': 'ArrayTable',
 | 
				
			||||||
 | 
					                                                                'x-component-props': {
 | 
				
			||||||
 | 
					                                                                  pagination: { pageSize: 10 },
 | 
				
			||||||
 | 
					                                                                  scroll: { x: '100%' },
 | 
				
			||||||
 | 
					                                                                },
 | 
				
			||||||
 | 
					                                                                items: {
 | 
				
			||||||
 | 
					                                                                  type: 'object',
 | 
				
			||||||
 | 
					                                                                  properties: {
 | 
				
			||||||
 | 
					                                                                    column3: {
 | 
				
			||||||
 | 
					                                                                      type: 'void',
 | 
				
			||||||
 | 
					                                                                      'x-component': 'ArrayTable.Column',
 | 
				
			||||||
 | 
					                                                                      'x-component-props': {
 | 
				
			||||||
 | 
					                                                                        width: 200,
 | 
				
			||||||
 | 
					                                                                        title: '{{t("Field")}}',
 | 
				
			||||||
 | 
					                                                                      },
 | 
				
			||||||
 | 
					                                                                      properties: {
 | 
				
			||||||
 | 
					                                                                        field: {
 | 
				
			||||||
 | 
					                                                                          type: 'string',
 | 
				
			||||||
 | 
					                                                                          //'x-decorator': 'Editable',
 | 
				
			||||||
 | 
					                                                                          'x-component': 'Field',
 | 
				
			||||||
 | 
					                                                                        },
 | 
				
			||||||
 | 
					                                                                      },
 | 
				
			||||||
 | 
					                                                                    },
 | 
				
			||||||
 | 
					                                                                    column4: {
 | 
				
			||||||
 | 
					                                                                      type: 'void',
 | 
				
			||||||
 | 
					                                                                      'x-component': 'ArrayTable.Column',
 | 
				
			||||||
 | 
					                                                                      'x-component-props': {
 | 
				
			||||||
 | 
					                                                                        width: 200,
 | 
				
			||||||
 | 
					                                                                        title: '{{t("Before change")}}',
 | 
				
			||||||
 | 
					                                                                      },
 | 
				
			||||||
 | 
					                                                                      properties: {
 | 
				
			||||||
 | 
					                                                                        before: {
 | 
				
			||||||
 | 
					                                                                          type: 'string',
 | 
				
			||||||
 | 
					                                                                          'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                                          'x-component': 'Value',
 | 
				
			||||||
 | 
					                                                                        },
 | 
				
			||||||
 | 
					                                                                      },
 | 
				
			||||||
 | 
					                                                                    },
 | 
				
			||||||
 | 
					                                                                    column5: {
 | 
				
			||||||
 | 
					                                                                      type: 'void',
 | 
				
			||||||
 | 
					                                                                      'x-component': 'ArrayTable.Column',
 | 
				
			||||||
 | 
					                                                                      'x-component-props': {
 | 
				
			||||||
 | 
					                                                                        width: 200,
 | 
				
			||||||
 | 
					                                                                        title: '{{t("After change")}}',
 | 
				
			||||||
 | 
					                                                                      },
 | 
				
			||||||
 | 
					                                                                      properties: {
 | 
				
			||||||
 | 
					                                                                        after: {
 | 
				
			||||||
 | 
					                                                                          type: 'string',
 | 
				
			||||||
 | 
					                                                                          'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                                                          'x-component': 'Value',
 | 
				
			||||||
 | 
					                                                                        },
 | 
				
			||||||
 | 
					                                                                      },
 | 
				
			||||||
 | 
					                                                                    },
 | 
				
			||||||
 | 
					                                                                  },
 | 
				
			||||||
 | 
					                                                                },
 | 
				
			||||||
 | 
					                                                              },
 | 
				
			||||||
 | 
					                                                            },
 | 
				
			||||||
 | 
					                                                          },
 | 
				
			||||||
 | 
					                                                        },
 | 
				
			||||||
 | 
					                                                      },
 | 
				
			||||||
 | 
					                                                    },
 | 
				
			||||||
 | 
					                                                  },
 | 
				
			||||||
 | 
					                                                },
 | 
				
			||||||
 | 
					                                              },
 | 
				
			||||||
 | 
					                                            },
 | 
				
			||||||
 | 
					                                          },
 | 
				
			||||||
 | 
					                                        },
 | 
				
			||||||
 | 
					                                      },
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                  },
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              column1: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-decorator': 'TableV2.Column.Decorator',
 | 
				
			||||||
 | 
					                'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  createdAt: {
 | 
				
			||||||
 | 
					                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              column2: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-decorator': 'TableV2.Column.Decorator',
 | 
				
			||||||
 | 
					                'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  type: {
 | 
				
			||||||
 | 
					                    'x-component': 'CollectionField',
 | 
				
			||||||
 | 
					                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              column3: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                title: '{{t("Collection display name")}}',
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  collection: {
 | 
				
			||||||
 | 
					                    'x-component': 'Collection',
 | 
				
			||||||
 | 
					                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              ...ext,
 | 
				
			||||||
 | 
					              column4: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					                title: '{{t("User")}}',
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  user: {
 | 
				
			||||||
 | 
					                    'x-component': 'Username',
 | 
				
			||||||
 | 
					                    'x-read-pretty': true,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AuditLogs.Decorator = observer(
 | 
				
			||||||
 | 
					  (props: any) => {
 | 
				
			||||||
 | 
					    const parent = useCollection_deprecated();
 | 
				
			||||||
 | 
					    const record = useRecord();
 | 
				
			||||||
 | 
					    let filter = props?.params?.filter;
 | 
				
			||||||
 | 
					    if (parent.name) {
 | 
				
			||||||
 | 
					      const filterByTk = record?.[parent.filterTargetKey || 'id'];
 | 
				
			||||||
 | 
					      if (filter) {
 | 
				
			||||||
 | 
					        filter = {
 | 
				
			||||||
 | 
					          $and: [
 | 
				
			||||||
 | 
					            filter,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              collectionName: parent.name,
 | 
				
			||||||
 | 
					              recordId: `${filterByTk}`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        filter = {
 | 
				
			||||||
 | 
					          collectionName: parent.name,
 | 
				
			||||||
 | 
					          recordId: `${filterByTk}`,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const defaults = {
 | 
				
			||||||
 | 
					      collection: 'auditLogs',
 | 
				
			||||||
 | 
					      resource: 'auditLogs',
 | 
				
			||||||
 | 
					      action: 'list',
 | 
				
			||||||
 | 
					      params: {
 | 
				
			||||||
 | 
					        pageSize: 20,
 | 
				
			||||||
 | 
					        appends: ['collection', 'user'],
 | 
				
			||||||
 | 
					        ...props.params,
 | 
				
			||||||
 | 
					        filter,
 | 
				
			||||||
 | 
					        sort: '-createdAt',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      rowKey: 'id',
 | 
				
			||||||
 | 
					      showIndex: true,
 | 
				
			||||||
 | 
					      dragSort: false,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <IsAssociationBlock.Provider value={!!parent.name}>
 | 
				
			||||||
 | 
					        <ExtendCollectionsProvider collections={[collection]}>
 | 
				
			||||||
 | 
					          <TableBlockProvider {...defaults}>{props.children}</TableBlockProvider>
 | 
				
			||||||
 | 
					        </ExtendCollectionsProvider>
 | 
				
			||||||
 | 
					      </IsAssociationBlock.Provider>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  { displayName: 'AuditLogs.Decorator' },
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AuditLogs.Designer = AuditLogsDesigner;
 | 
				
			||||||
@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					import { useField, useFieldSchema } from '@formily/react';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  GeneralSchemaDesigner,
 | 
				
			||||||
 | 
					  SchemaSettingsDataScope,
 | 
				
			||||||
 | 
					  SchemaSettingsDivider,
 | 
				
			||||||
 | 
					  SchemaSettingsRemove,
 | 
				
			||||||
 | 
					  SchemaSettingsSelectItem,
 | 
				
			||||||
 | 
					  useCollection_deprecated,
 | 
				
			||||||
 | 
					  useDesignable,
 | 
				
			||||||
 | 
					  useFormBlockContext,
 | 
				
			||||||
 | 
					  useTableBlockContext,
 | 
				
			||||||
 | 
					} from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AuditLogsDesigner = () => {
 | 
				
			||||||
 | 
					  const { name, title } = useCollection_deprecated();
 | 
				
			||||||
 | 
					  const field = useField();
 | 
				
			||||||
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
 | 
					  const { form } = useFormBlockContext();
 | 
				
			||||||
 | 
					  const { service } = useTableBlockContext();
 | 
				
			||||||
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
 | 
					  const { dn } = useDesignable();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <GeneralSchemaDesigner title={title || name}>
 | 
				
			||||||
 | 
					      <SchemaSettingsDataScope
 | 
				
			||||||
 | 
					        collectionName={name}
 | 
				
			||||||
 | 
					        defaultFilter={fieldSchema?.['x-decorator-props']?.params?.filter || {}}
 | 
				
			||||||
 | 
					        form={form}
 | 
				
			||||||
 | 
					        onSubmit={({ filter }) => {
 | 
				
			||||||
 | 
					          const params = field.decoratorProps.params || {};
 | 
				
			||||||
 | 
					          params.filter = filter;
 | 
				
			||||||
 | 
					          field.decoratorProps.params = params;
 | 
				
			||||||
 | 
					          fieldSchema['x-decorator-props']['params'] = params;
 | 
				
			||||||
 | 
					          service.run({ ...service.params?.[0], filter, page: 1 });
 | 
				
			||||||
 | 
					          dn.emit('patch', {
 | 
				
			||||||
 | 
					            schema: {
 | 
				
			||||||
 | 
					              ['x-uid']: fieldSchema['x-uid'],
 | 
				
			||||||
 | 
					              'x-decorator-props': fieldSchema['x-decorator-props'],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <SchemaSettingsSelectItem
 | 
				
			||||||
 | 
					        title={t('Records per page')}
 | 
				
			||||||
 | 
					        value={field.decoratorProps?.params?.pageSize || 20}
 | 
				
			||||||
 | 
					        options={[
 | 
				
			||||||
 | 
					          { label: '10', value: 10 },
 | 
				
			||||||
 | 
					          { label: '20', value: 20 },
 | 
				
			||||||
 | 
					          { label: '50', value: 50 },
 | 
				
			||||||
 | 
					          { label: '100', value: 100 },
 | 
				
			||||||
 | 
					          { label: '200', value: 200 },
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        onChange={(pageSize) => {
 | 
				
			||||||
 | 
					          const params = field.decoratorProps.params || {};
 | 
				
			||||||
 | 
					          params.pageSize = pageSize;
 | 
				
			||||||
 | 
					          field.decoratorProps.params = params;
 | 
				
			||||||
 | 
					          fieldSchema['x-decorator-props']['params'] = params;
 | 
				
			||||||
 | 
					          service.run({ ...service.params?.[0], pageSize, page: 1 });
 | 
				
			||||||
 | 
					          dn.emit('patch', {
 | 
				
			||||||
 | 
					            schema: {
 | 
				
			||||||
 | 
					              ['x-uid']: fieldSchema['x-uid'],
 | 
				
			||||||
 | 
					              'x-decorator-props': fieldSchema['x-decorator-props'],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <SchemaSettingsDivider />
 | 
				
			||||||
 | 
					      <SchemaSettingsRemove
 | 
				
			||||||
 | 
					        removeParentsIfNoChildren
 | 
				
			||||||
 | 
					        breakRemoveOn={{
 | 
				
			||||||
 | 
					          'x-component': 'Grid',
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </GeneralSchemaDesigner>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										39
									
								
								packages/plugins/@hera/plugin-audit-logs/src/client/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								packages/plugins/@hera/plugin-audit-logs/src/client/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import { Plugin, SchemaInitializerItemType } from '@nocobase/client';
 | 
				
			||||||
 | 
					import { AuditLogsProvider } from './AuditLogsProvider';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  auditLogsTableActionColumnInitializers,
 | 
				
			||||||
 | 
					  auditLogsTableActionColumnInitializers_deprecated,
 | 
				
			||||||
 | 
					} from './initializers/AuditLogsTableActionColumnInitializers';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  auditLogsTableActionInitializers,
 | 
				
			||||||
 | 
					  auditLogsTableActionInitializers_deprecated,
 | 
				
			||||||
 | 
					} from './initializers/AuditLogsTableActionInitializers';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  auditLogsTableColumnInitializers,
 | 
				
			||||||
 | 
					  auditLogsTableColumnInitializers_deprecated,
 | 
				
			||||||
 | 
					} from './initializers/AuditLogsTableColumnInitializers';
 | 
				
			||||||
 | 
					export * from './AuditLogsBlockInitializer';
 | 
				
			||||||
 | 
					export * from './AuditLogsProvider';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class AuditLogsPlugin extends Plugin {
 | 
				
			||||||
 | 
					  async load() {
 | 
				
			||||||
 | 
					    this.app.use(AuditLogsProvider);
 | 
				
			||||||
 | 
					    this.app.schemaInitializerManager.add(auditLogsTableActionInitializers_deprecated);
 | 
				
			||||||
 | 
					    this.app.schemaInitializerManager.add(auditLogsTableActionInitializers);
 | 
				
			||||||
 | 
					    this.app.schemaInitializerManager.add(auditLogsTableActionColumnInitializers_deprecated);
 | 
				
			||||||
 | 
					    this.app.schemaInitializerManager.add(auditLogsTableActionColumnInitializers);
 | 
				
			||||||
 | 
					    this.app.schemaInitializerManager.add(auditLogsTableColumnInitializers_deprecated);
 | 
				
			||||||
 | 
					    this.app.schemaInitializerManager.add(auditLogsTableColumnInitializers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const blockInitializers = this.app.schemaInitializerManager.get('page:addBlock');
 | 
				
			||||||
 | 
					    const recordBlockInitializers = this.app.schemaInitializerManager.get('popup:common:addBlock');
 | 
				
			||||||
 | 
					    const auditLogs: Omit<SchemaInitializerItemType, 'name'> = {
 | 
				
			||||||
 | 
					      title: '{{t("Audit logs")}}',
 | 
				
			||||||
 | 
					      Component: 'AuditLogsBlockInitializer',
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    blockInitializers.add('otherBlocks.auditLogs', auditLogs);
 | 
				
			||||||
 | 
					    recordBlockInitializers.add('otherBlocks.auditLogs', auditLogs);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AuditLogsPlugin;
 | 
				
			||||||
@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					import { InitializerWithSwitch, useSchemaInitializerItem } from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AuditLogsTableActionColumnInitializer = () => {
 | 
				
			||||||
 | 
					  const schema = {
 | 
				
			||||||
 | 
					    type: 'void',
 | 
				
			||||||
 | 
					    title: '{{ t("Actions") }}',
 | 
				
			||||||
 | 
					    'x-decorator': 'TableV2.Column.ActionBar',
 | 
				
			||||||
 | 
					    'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					    'x-designer': 'TableV2.ActionColumnDesigner',
 | 
				
			||||||
 | 
					    'x-initializer': 'auditLogsTable:configureItemActions',
 | 
				
			||||||
 | 
					    'x-action-column': 'actions',
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					      actions: {
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        'x-decorator': 'DndContext',
 | 
				
			||||||
 | 
					        'x-component': 'Space',
 | 
				
			||||||
 | 
					        'x-component-props': {
 | 
				
			||||||
 | 
					          split: '|',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        properties: {},
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const itemConfig = useSchemaInitializerItem();
 | 
				
			||||||
 | 
					  return <InitializerWithSwitch {...itemConfig} schema={schema} item={itemConfig} type={'x-action-column'} />;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					import { MenuOutlined } from '@ant-design/icons';
 | 
				
			||||||
 | 
					import { useFieldSchema } from '@formily/react';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  CompatibleSchemaInitializer,
 | 
				
			||||||
 | 
					  createDesignable,
 | 
				
			||||||
 | 
					  Resizable,
 | 
				
			||||||
 | 
					  useAPIClient,
 | 
				
			||||||
 | 
					  useDesignable,
 | 
				
			||||||
 | 
					} from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @deprecated
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const auditLogsTableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({
 | 
				
			||||||
 | 
					  name: 'AuditLogsTableActionColumnInitializers',
 | 
				
			||||||
 | 
					  insertPosition: 'beforeEnd',
 | 
				
			||||||
 | 
					  Component: (props: any) => <MenuOutlined {...props} style={{ cursor: 'pointer' }} />,
 | 
				
			||||||
 | 
					  useInsert() {
 | 
				
			||||||
 | 
					    const fieldSchema = useFieldSchema();
 | 
				
			||||||
 | 
					    const api = useAPIClient();
 | 
				
			||||||
 | 
					    const { refresh } = useDesignable();
 | 
				
			||||||
 | 
					    const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (schema) => {
 | 
				
			||||||
 | 
					      const spaceSchema = fieldSchema.reduceProperties((buf, schema) => {
 | 
				
			||||||
 | 
					        if (schema['x-component'] === 'Space') {
 | 
				
			||||||
 | 
					          return schema;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return buf;
 | 
				
			||||||
 | 
					      }, null);
 | 
				
			||||||
 | 
					      if (!spaceSchema) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const dn = createDesignable({
 | 
				
			||||||
 | 
					        t,
 | 
				
			||||||
 | 
					        api,
 | 
				
			||||||
 | 
					        refresh,
 | 
				
			||||||
 | 
					        current: spaceSchema,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      dn.loadAPIClientEvents();
 | 
				
			||||||
 | 
					      dn.insertBeforeEnd(schema);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  items: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'enableActions',
 | 
				
			||||||
 | 
					      type: 'itemGroup',
 | 
				
			||||||
 | 
					      title: '{{t("Enable actions")}}',
 | 
				
			||||||
 | 
					      children: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          name: 'view',
 | 
				
			||||||
 | 
					          type: 'item',
 | 
				
			||||||
 | 
					          title: '{{t("View")}}',
 | 
				
			||||||
 | 
					          Component: 'AuditLogsViewActionInitializer',
 | 
				
			||||||
 | 
					          schema: {
 | 
				
			||||||
 | 
					            'x-component': 'Action.Link',
 | 
				
			||||||
 | 
					            'x-action': 'view',
 | 
				
			||||||
 | 
					            'x-decorator': 'ACLActionProvider',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'divider',
 | 
				
			||||||
 | 
					      type: 'divider',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'columnWidth',
 | 
				
			||||||
 | 
					      type: 'item',
 | 
				
			||||||
 | 
					      title: '{{t("Column width")}}',
 | 
				
			||||||
 | 
					      Component: Resizable,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const auditLogsTableActionColumnInitializers = new CompatibleSchemaInitializer(
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    name: 'auditLogsTable:configureItemActions',
 | 
				
			||||||
 | 
					    insertPosition: 'beforeEnd',
 | 
				
			||||||
 | 
					    Component: (props: any) => <MenuOutlined {...props} style={{ cursor: 'pointer' }} />,
 | 
				
			||||||
 | 
					    useInsert() {
 | 
				
			||||||
 | 
					      const fieldSchema = useFieldSchema();
 | 
				
			||||||
 | 
					      const api = useAPIClient();
 | 
				
			||||||
 | 
					      const { refresh } = useDesignable();
 | 
				
			||||||
 | 
					      const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return (schema) => {
 | 
				
			||||||
 | 
					        const spaceSchema = fieldSchema.reduceProperties((buf, schema) => {
 | 
				
			||||||
 | 
					          if (schema['x-component'] === 'Space') {
 | 
				
			||||||
 | 
					            return schema;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return buf;
 | 
				
			||||||
 | 
					        }, null);
 | 
				
			||||||
 | 
					        if (!spaceSchema) {
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const dn = createDesignable({
 | 
				
			||||||
 | 
					          t,
 | 
				
			||||||
 | 
					          api,
 | 
				
			||||||
 | 
					          refresh,
 | 
				
			||||||
 | 
					          current: spaceSchema,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        dn.loadAPIClientEvents();
 | 
				
			||||||
 | 
					        dn.insertBeforeEnd(schema);
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    items: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'enableActions',
 | 
				
			||||||
 | 
					        type: 'itemGroup',
 | 
				
			||||||
 | 
					        title: '{{t("Enable actions")}}',
 | 
				
			||||||
 | 
					        children: [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            name: 'view',
 | 
				
			||||||
 | 
					            type: 'item',
 | 
				
			||||||
 | 
					            title: '{{t("View")}}',
 | 
				
			||||||
 | 
					            Component: 'AuditLogsViewActionInitializer',
 | 
				
			||||||
 | 
					            schema: {
 | 
				
			||||||
 | 
					              'x-component': 'Action.Link',
 | 
				
			||||||
 | 
					              'x-action': 'view',
 | 
				
			||||||
 | 
					              'x-decorator': 'ACLActionProvider',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'divider',
 | 
				
			||||||
 | 
					        type: 'divider',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'columnWidth',
 | 
				
			||||||
 | 
					        type: 'item',
 | 
				
			||||||
 | 
					        title: '{{t("Column width")}}',
 | 
				
			||||||
 | 
					        Component: Resizable,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  auditLogsTableActionColumnInitializers_deprecated,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					import { CompatibleSchemaInitializer } from '@nocobase/client';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @deprecated
 | 
				
			||||||
 | 
					 * 操作记录表格操作配置
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const auditLogsTableActionInitializers_deprecated = new CompatibleSchemaInitializer({
 | 
				
			||||||
 | 
					  name: 'AuditLogsTableActionInitializers',
 | 
				
			||||||
 | 
					  title: "{{t('Configure actions')}}",
 | 
				
			||||||
 | 
					  icon: 'SettingOutlined',
 | 
				
			||||||
 | 
					  style: {
 | 
				
			||||||
 | 
					    marginLeft: 8,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  items: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'itemGroup',
 | 
				
			||||||
 | 
					      title: "{{t('Enable actions')}}",
 | 
				
			||||||
 | 
					      name: 'enableActions',
 | 
				
			||||||
 | 
					      children: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          name: 'filter',
 | 
				
			||||||
 | 
					          title: "{{t('Filter')}}",
 | 
				
			||||||
 | 
					          Component: 'FilterActionInitializer',
 | 
				
			||||||
 | 
					          schema: {
 | 
				
			||||||
 | 
					            'x-align': 'left',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          name: 'refresh',
 | 
				
			||||||
 | 
					          title: "{{t('Refresh')}}",
 | 
				
			||||||
 | 
					          Component: 'RefreshActionInitializer',
 | 
				
			||||||
 | 
					          schema: {
 | 
				
			||||||
 | 
					            'x-align': 'right',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const auditLogsTableActionInitializers = new CompatibleSchemaInitializer(
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    name: 'auditLogsTable:configureActions',
 | 
				
			||||||
 | 
					    title: "{{t('Configure actions')}}",
 | 
				
			||||||
 | 
					    icon: 'SettingOutlined',
 | 
				
			||||||
 | 
					    style: {
 | 
				
			||||||
 | 
					      marginLeft: 8,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    items: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        type: 'itemGroup',
 | 
				
			||||||
 | 
					        title: "{{t('Enable actions')}}",
 | 
				
			||||||
 | 
					        name: 'enableActions',
 | 
				
			||||||
 | 
					        children: [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            name: 'filter',
 | 
				
			||||||
 | 
					            title: "{{t('Filter')}}",
 | 
				
			||||||
 | 
					            Component: 'FilterActionInitializer',
 | 
				
			||||||
 | 
					            schema: {
 | 
				
			||||||
 | 
					              'x-align': 'left',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            name: 'refresh',
 | 
				
			||||||
 | 
					            title: "{{t('Refresh')}}",
 | 
				
			||||||
 | 
					            Component: 'RefreshActionInitializer',
 | 
				
			||||||
 | 
					            schema: {
 | 
				
			||||||
 | 
					              'x-align': 'right',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  auditLogsTableActionInitializers_deprecated,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
@ -0,0 +1,139 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  CompatibleSchemaInitializer,
 | 
				
			||||||
 | 
					  SchemaInitializerChildren,
 | 
				
			||||||
 | 
					  useAssociatedTableColumnInitializerFields,
 | 
				
			||||||
 | 
					  useCompile,
 | 
				
			||||||
 | 
					  useInheritsTableColumnInitializerFields,
 | 
				
			||||||
 | 
					  useTableColumnInitializerFields,
 | 
				
			||||||
 | 
					} from '@nocobase/client';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 表格列配置
 | 
				
			||||||
 | 
					const ParentCollectionFields = () => {
 | 
				
			||||||
 | 
					  const inheritFields = useInheritsTableColumnInitializerFields();
 | 
				
			||||||
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
 | 
					  const compile = useCompile();
 | 
				
			||||||
 | 
					  if (!inheritFields?.length) return null;
 | 
				
			||||||
 | 
					  const res = [];
 | 
				
			||||||
 | 
					  inheritFields.forEach((inherit) => {
 | 
				
			||||||
 | 
					    Object.values(inherit)[0].length &&
 | 
				
			||||||
 | 
					      res.push({
 | 
				
			||||||
 | 
					        type: 'itemGroup',
 | 
				
			||||||
 | 
					        divider: true,
 | 
				
			||||||
 | 
					        title: t(`Parent collection fields`) + '(' + compile(`${Object.keys(inherit)[0]}`) + ')',
 | 
				
			||||||
 | 
					        children: Object.values(inherit)[0].filter((v: any) => !v?.field?.isForeignKey),
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return <SchemaInitializerChildren>{res}</SchemaInitializerChildren>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AssociatedFields = () => {
 | 
				
			||||||
 | 
					  const associatedFields = useAssociatedTableColumnInitializerFields();
 | 
				
			||||||
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!associatedFields?.length) return null;
 | 
				
			||||||
 | 
					  const schema: any = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'itemGroup',
 | 
				
			||||||
 | 
					      divider: true,
 | 
				
			||||||
 | 
					      title: t('Display association fields'),
 | 
				
			||||||
 | 
					      children: associatedFields,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  return <SchemaInitializerChildren>{schema}</SchemaInitializerChildren>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @deprecated
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const auditLogsTableColumnInitializers_deprecated = new CompatibleSchemaInitializer({
 | 
				
			||||||
 | 
					  name: 'AuditLogsTableColumnInitializers',
 | 
				
			||||||
 | 
					  insertPosition: 'beforeEnd',
 | 
				
			||||||
 | 
					  icon: 'SettingOutlined',
 | 
				
			||||||
 | 
					  title: '{{t("Configure columns")}}',
 | 
				
			||||||
 | 
					  wrap(s) {
 | 
				
			||||||
 | 
					    if (s['x-action-column']) {
 | 
				
			||||||
 | 
					      return s;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      'x-decorator': 'TableV2.Column.Decorator',
 | 
				
			||||||
 | 
					      'x-designer': 'TableV2.Column.Designer',
 | 
				
			||||||
 | 
					      'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        [s.name]: {
 | 
				
			||||||
 | 
					          ...s,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  items: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'displayFields',
 | 
				
			||||||
 | 
					      type: 'itemGroup',
 | 
				
			||||||
 | 
					      title: '{{t("Display fields")}}',
 | 
				
			||||||
 | 
					      useChildren: useTableColumnInitializerFields,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'parentCollectionFields',
 | 
				
			||||||
 | 
					      Component: ParentCollectionFields,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'associationFields',
 | 
				
			||||||
 | 
					      Component: AssociatedFields,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'actionColumn',
 | 
				
			||||||
 | 
					      title: '{{t("Action column")}}',
 | 
				
			||||||
 | 
					      Component: 'AuditLogsTableActionColumnInitializer',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const auditLogsTableColumnInitializers = new CompatibleSchemaInitializer(
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    name: 'auditLogsTable:configureColumns',
 | 
				
			||||||
 | 
					    insertPosition: 'beforeEnd',
 | 
				
			||||||
 | 
					    icon: 'SettingOutlined',
 | 
				
			||||||
 | 
					    title: '{{t("Configure columns")}}',
 | 
				
			||||||
 | 
					    wrap(s) {
 | 
				
			||||||
 | 
					      if (s['x-action-column']) {
 | 
				
			||||||
 | 
					        return s;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        'x-decorator': 'TableV2.Column.Decorator',
 | 
				
			||||||
 | 
					        'x-designer': 'TableV2.Column.Designer',
 | 
				
			||||||
 | 
					        'x-component': 'TableV2.Column',
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          [s.name]: {
 | 
				
			||||||
 | 
					            ...s,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    items: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'displayFields',
 | 
				
			||||||
 | 
					        type: 'itemGroup',
 | 
				
			||||||
 | 
					        title: '{{t("Display fields")}}',
 | 
				
			||||||
 | 
					        useChildren: useTableColumnInitializerFields,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'parentCollectionFields',
 | 
				
			||||||
 | 
					        Component: ParentCollectionFields,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'associationFields',
 | 
				
			||||||
 | 
					        Component: AssociatedFields,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'actionColumn',
 | 
				
			||||||
 | 
					        title: '{{t("Action column")}}',
 | 
				
			||||||
 | 
					        Component: 'AuditLogsTableActionColumnInitializer',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  auditLogsTableColumnInitializers_deprecated,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					import { i18n, tval as nTval } from '@nocobase/client';
 | 
				
			||||||
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const NAMESPACE = 'audit-logs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function lang(key: string) {
 | 
				
			||||||
 | 
					  return i18n.t(key, { ns: NAMESPACE });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useAuditLogsTranslation() {
 | 
				
			||||||
 | 
					  return useTranslation(NAMESPACE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const tval = (key: string) => nTval(key, { ns: NAMESPACE });
 | 
				
			||||||
							
								
								
									
										303
									
								
								packages/plugins/@hera/plugin-audit-logs/src/client/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								packages/plugins/@hera/plugin-audit-logs/src/client/utils.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,303 @@
 | 
				
			|||||||
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const createSchema = () => {
 | 
				
			||||||
 | 
					  const filterSchema = {
 | 
				
			||||||
 | 
					    'x-component': 'Action',
 | 
				
			||||||
 | 
					    'x-component-props': {
 | 
				
			||||||
 | 
					      popover: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    type: 'void',
 | 
				
			||||||
 | 
					    title: '{{t("Filter")}}',
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					      popover: {
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        'x-decorator': 'Form',
 | 
				
			||||||
 | 
					        'x-decorator-props': {},
 | 
				
			||||||
 | 
					        'x-component': 'Action.Popover',
 | 
				
			||||||
 | 
					        'x-component-props': {
 | 
				
			||||||
 | 
					          trigger: 'click',
 | 
				
			||||||
 | 
					          placement: 'bottomLeft',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          filter: {
 | 
				
			||||||
 | 
					            type: 'object',
 | 
				
			||||||
 | 
					            default: {
 | 
				
			||||||
 | 
					              $and: [{}],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            'x-component': 'Filter',
 | 
				
			||||||
 | 
					            'x-component-props': {
 | 
				
			||||||
 | 
					              useDataSource: '{{cm.useFilterDataSource}}',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          footer: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            'x-component': 'Action.Popover.Footer',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              actions: {
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-component': 'ActionBar',
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  saveDefault: {
 | 
				
			||||||
 | 
					                    type: 'void',
 | 
				
			||||||
 | 
					                    'x-component': 'Filter.SaveDefaultValue',
 | 
				
			||||||
 | 
					                    'x-component-props': {},
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  cancel: {
 | 
				
			||||||
 | 
					                    type: 'void',
 | 
				
			||||||
 | 
					                    title: '{{t("Cancel")}}',
 | 
				
			||||||
 | 
					                    'x-component': 'Action',
 | 
				
			||||||
 | 
					                    'x-component-props': {
 | 
				
			||||||
 | 
					                      useAction: '{{cm.useCancelFilterAction}}',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  submit: {
 | 
				
			||||||
 | 
					                    type: 'void',
 | 
				
			||||||
 | 
					                    title: '{{t("Submit")}}',
 | 
				
			||||||
 | 
					                    'x-component': 'Action',
 | 
				
			||||||
 | 
					                    'x-component-props': {
 | 
				
			||||||
 | 
					                      type: 'primary',
 | 
				
			||||||
 | 
					                      useAction: '{{cm.useFilterAction}}',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const schema = {
 | 
				
			||||||
 | 
					    type: 'void',
 | 
				
			||||||
 | 
					    name: 'actionLog',
 | 
				
			||||||
 | 
					    'x-decorator': 'ResourceActionProvider',
 | 
				
			||||||
 | 
					    'x-decorator-props': {
 | 
				
			||||||
 | 
					      collection: 'action_logs',
 | 
				
			||||||
 | 
					      dragSort: false,
 | 
				
			||||||
 | 
					      request: {
 | 
				
			||||||
 | 
					        resource: 'action_logs',
 | 
				
			||||||
 | 
					        action: 'list',
 | 
				
			||||||
 | 
					        params: {
 | 
				
			||||||
 | 
					          pageSize: 20,
 | 
				
			||||||
 | 
					          filter: {},
 | 
				
			||||||
 | 
					          appends: [],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    'x-designer': 'ActionLog.Designer',
 | 
				
			||||||
 | 
					    'x-component': 'CardItem',
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					      actions: {
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        'x-component': 'ActionBar',
 | 
				
			||||||
 | 
					        'x-component-props': {
 | 
				
			||||||
 | 
					          layout: 'one-column',
 | 
				
			||||||
 | 
					          style: {
 | 
				
			||||||
 | 
					            marginBottom: 16,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          [uid()]: { ...filterSchema },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      table: {
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        'x-component': 'Table.Void',
 | 
				
			||||||
 | 
					        'x-component-props': {
 | 
				
			||||||
 | 
					          rowKey: 'id',
 | 
				
			||||||
 | 
					          useDataSource: '{{cm.useDataSourceFromRAC}}',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          column1: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            title: "{{t('Created at')}}",
 | 
				
			||||||
 | 
					            'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              created_at: {
 | 
				
			||||||
 | 
					                type: 'string',
 | 
				
			||||||
 | 
					                'x-component': 'DatePicker',
 | 
				
			||||||
 | 
					                'x-read-pretty': true,
 | 
				
			||||||
 | 
					                'x-component-props': {
 | 
				
			||||||
 | 
					                  format: 'YYYY-MM-DD HH:mm:ss',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          column2: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            title: "{{t('Created by')}}",
 | 
				
			||||||
 | 
					            'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              'user.nickname': {
 | 
				
			||||||
 | 
					                type: 'string',
 | 
				
			||||||
 | 
					                'x-component': 'Input',
 | 
				
			||||||
 | 
					                'x-read-pretty': true,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          column3: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            title: "{{t('Collection display name')}}",
 | 
				
			||||||
 | 
					            'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              'collection.title': {
 | 
				
			||||||
 | 
					                type: 'string',
 | 
				
			||||||
 | 
					                'x-component': 'Input',
 | 
				
			||||||
 | 
					                'x-read-pretty': true,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          column4: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            title: "{{t('Action type')}}",
 | 
				
			||||||
 | 
					            'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              type: {
 | 
				
			||||||
 | 
					                type: 'string',
 | 
				
			||||||
 | 
					                'x-component': 'Select',
 | 
				
			||||||
 | 
					                'x-read-pretty': true,
 | 
				
			||||||
 | 
					                enum: [
 | 
				
			||||||
 | 
					                  { label: "{{ t('Add new') }}", value: 'create', color: 'green' },
 | 
				
			||||||
 | 
					                  { label: "{{ t('Update') }}", value: 'update', color: 'blue' },
 | 
				
			||||||
 | 
					                  { label: "{{ t('Delete') }}", value: 'destroy', color: 'red' },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          [uid()]: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            title: "{{t('Actions')}}",
 | 
				
			||||||
 | 
					            'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					            'x-component-props': {
 | 
				
			||||||
 | 
					              width: 60,
 | 
				
			||||||
 | 
					              align: 'center',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              [uid()]: {
 | 
				
			||||||
 | 
					                title: '{{ t("View") }}',
 | 
				
			||||||
 | 
					                type: 'void',
 | 
				
			||||||
 | 
					                'x-action': 'view',
 | 
				
			||||||
 | 
					                'x-component': 'Action.Link',
 | 
				
			||||||
 | 
					                'x-component-props': {
 | 
				
			||||||
 | 
					                  openMode: 'drawer',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                  drawer: {
 | 
				
			||||||
 | 
					                    type: 'void',
 | 
				
			||||||
 | 
					                    'x-component': 'Action.Container',
 | 
				
			||||||
 | 
					                    'x-component-props': {
 | 
				
			||||||
 | 
					                      className: 'nb-action-popup',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    title: '{{ t("View record") }}',
 | 
				
			||||||
 | 
					                    properties: {
 | 
				
			||||||
 | 
					                      created_at: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                        title: "{{t('Created at')}}",
 | 
				
			||||||
 | 
					                        'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                        'x-component': 'DatePicker',
 | 
				
			||||||
 | 
					                        'x-read-pretty': true,
 | 
				
			||||||
 | 
					                        'x-component-props': {
 | 
				
			||||||
 | 
					                          format: 'YYYY-MM-DD HH:mm:ss',
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      'user.nickname': {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                        title: "{{t('Created by')}}",
 | 
				
			||||||
 | 
					                        'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                        'x-component': 'Input',
 | 
				
			||||||
 | 
					                        'x-read-pretty': true,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      'collection.title': {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                        title: "{{t('Collection display name')}}",
 | 
				
			||||||
 | 
					                        'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                        'x-component': 'Input',
 | 
				
			||||||
 | 
					                        'x-read-pretty': true,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      type: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                        title: "{{t('Action type')}}",
 | 
				
			||||||
 | 
					                        'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                        'x-component': 'Select',
 | 
				
			||||||
 | 
					                        'x-read-pretty': true,
 | 
				
			||||||
 | 
					                        enum: [
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                            label: "{{t('Insert')}}",
 | 
				
			||||||
 | 
					                            value: 'create',
 | 
				
			||||||
 | 
					                            color: 'green',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                            label: "{{t('Update')}}",
 | 
				
			||||||
 | 
					                            value: 'update',
 | 
				
			||||||
 | 
					                            color: 'blue',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                          {
 | 
				
			||||||
 | 
					                            label: "{{t('Delete')}}",
 | 
				
			||||||
 | 
					                            value: 'destroy',
 | 
				
			||||||
 | 
					                            color: 'red',
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        ],
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      changes: {
 | 
				
			||||||
 | 
					                        type: 'array',
 | 
				
			||||||
 | 
					                        title: "{{t('Data changes')}}",
 | 
				
			||||||
 | 
					                        'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                        'x-component': 'Table.Array',
 | 
				
			||||||
 | 
					                        'x-component-props': {
 | 
				
			||||||
 | 
					                          pagination: false,
 | 
				
			||||||
 | 
					                          showIndex: true,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        items: {
 | 
				
			||||||
 | 
					                          type: 'object',
 | 
				
			||||||
 | 
					                          properties: {
 | 
				
			||||||
 | 
					                            column1: {
 | 
				
			||||||
 | 
					                              type: 'void',
 | 
				
			||||||
 | 
					                              'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					                              'x-component-props': { title: "{{t('Field display name')}}" },
 | 
				
			||||||
 | 
					                              properties: {
 | 
				
			||||||
 | 
					                                field: {
 | 
				
			||||||
 | 
					                                  type: 'string',
 | 
				
			||||||
 | 
					                                  'x-decorator': 'FormilyFormItem',
 | 
				
			||||||
 | 
					                                  'x-component': 'ActionLog.Field',
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            column2: {
 | 
				
			||||||
 | 
					                              type: 'void',
 | 
				
			||||||
 | 
					                              'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					                              'x-component-props': { title: "{{ t('Before change') }}" },
 | 
				
			||||||
 | 
					                              properties: {
 | 
				
			||||||
 | 
					                                before: {
 | 
				
			||||||
 | 
					                                  type: 'string',
 | 
				
			||||||
 | 
					                                  'x-decorator': 'FormilyFormItem',
 | 
				
			||||||
 | 
					                                  'x-component': 'ActionLog.FieldValue',
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            column3: {
 | 
				
			||||||
 | 
					                              type: 'void',
 | 
				
			||||||
 | 
					                              'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					                              'x-component-props': { title: "{{ t('After change') }}" },
 | 
				
			||||||
 | 
					                              properties: {
 | 
				
			||||||
 | 
					                                after: {
 | 
				
			||||||
 | 
					                                  type: 'string',
 | 
				
			||||||
 | 
					                                  'x-decorator': 'FormilyFormItem',
 | 
				
			||||||
 | 
					                                  'x-component': 'ActionLog.FieldValue',
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return schema;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										2
									
								
								packages/plugins/@hera/plugin-audit-logs/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								packages/plugins/@hera/plugin-audit-logs/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					export * from './server';
 | 
				
			||||||
 | 
					export { default } from './server';
 | 
				
			||||||
@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "Details of changes": "Details of changes",
 | 
				
			||||||
 | 
					  "Create record": "Create record"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "Details of changes": "变更详情",
 | 
				
			||||||
 | 
					  "Create record": "创建数据"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					import Database from '@nocobase/database';
 | 
				
			||||||
 | 
					import { createMockServer, MockServer } from '@nocobase/test';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('hook', () => {
 | 
				
			||||||
 | 
					  let api: MockServer;
 | 
				
			||||||
 | 
					  let db: Database;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    api = await createMockServer({
 | 
				
			||||||
 | 
					      plugins: ['audit-logs'],
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    db = api.db;
 | 
				
			||||||
 | 
					    db.collection({
 | 
				
			||||||
 | 
					      name: 'posts',
 | 
				
			||||||
 | 
					      logging: true,
 | 
				
			||||||
 | 
					      fields: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          type: 'string',
 | 
				
			||||||
 | 
					          name: 'title',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          type: 'string',
 | 
				
			||||||
 | 
					          name: 'status',
 | 
				
			||||||
 | 
					          defaultValue: 'draft',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    db.collection({
 | 
				
			||||||
 | 
					      name: 'users',
 | 
				
			||||||
 | 
					      logging: false,
 | 
				
			||||||
 | 
					      fields: [
 | 
				
			||||||
 | 
					        { type: 'string', name: 'nickname' },
 | 
				
			||||||
 | 
					        { type: 'string', name: 'token' },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    await db.sync();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  afterEach(async () => {
 | 
				
			||||||
 | 
					    await api.destroy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('model', async () => {
 | 
				
			||||||
 | 
					    const Post = db.getCollection('posts').model;
 | 
				
			||||||
 | 
					    const post = await Post.create({ title: 't1' });
 | 
				
			||||||
 | 
					    await post.update({ title: 't2' });
 | 
				
			||||||
 | 
					    await post.destroy();
 | 
				
			||||||
 | 
					    const auditLogs = await db.getCollection('auditLogs').repository.find({
 | 
				
			||||||
 | 
					      appends: ['changes'],
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(auditLogs.length).toBe(3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const titleChange = (changes) => {
 | 
				
			||||||
 | 
					      return changes.find((item) => item.field.name === 'title');
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(titleChange(auditLogs[0].changes).before).toBeNull();
 | 
				
			||||||
 | 
					    expect(titleChange(auditLogs[0].changes).after).toBe('t1');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(titleChange(auditLogs[1].changes).before).toBe('t1');
 | 
				
			||||||
 | 
					    expect(titleChange(auditLogs[1].changes).after).toBe('t2');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(titleChange(auditLogs[2].changes).before).toBe('t2');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('repository', async () => {
 | 
				
			||||||
 | 
					    const Post = db.getCollection('posts');
 | 
				
			||||||
 | 
					    const User = db.getCollection('users').model;
 | 
				
			||||||
 | 
					    const user = await User.create({ nickname: 'a', token: 'token1' });
 | 
				
			||||||
 | 
					    const post = await Post.repository.create({
 | 
				
			||||||
 | 
					      values: { title: 't1' },
 | 
				
			||||||
 | 
					      context: {
 | 
				
			||||||
 | 
					        state: {
 | 
				
			||||||
 | 
					          currentUser: user,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const AuditLog = db.getCollection('auditLogs');
 | 
				
			||||||
 | 
					    const log = await AuditLog.repository.findOne({
 | 
				
			||||||
 | 
					      appends: ['changes'],
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(log.toJSON()).toMatchObject({
 | 
				
			||||||
 | 
					      collectionName: 'posts',
 | 
				
			||||||
 | 
					      type: 'create',
 | 
				
			||||||
 | 
					      userId: 1,
 | 
				
			||||||
 | 
					      recordId: `${post.get('id')}`,
 | 
				
			||||||
 | 
					      changes: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          field: {
 | 
				
			||||||
 | 
					            name: 'title',
 | 
				
			||||||
 | 
					            type: 'string',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          before: null,
 | 
				
			||||||
 | 
					          after: 't1',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // it.skip('resource', async () => {
 | 
				
			||||||
 | 
					  //   const agent = api.agent();
 | 
				
			||||||
 | 
					  //   agent.set('Authorization', `Bearer token1`);
 | 
				
			||||||
 | 
					  //   const response = await agent.resource('posts').create({
 | 
				
			||||||
 | 
					  //     values: { title: 't1' },
 | 
				
			||||||
 | 
					  //   });
 | 
				
			||||||
 | 
					  //   await agent.resource('posts').update({
 | 
				
			||||||
 | 
					  //     resourceIndex: response.body.data.id,
 | 
				
			||||||
 | 
					  //     values: { title: 't2' },
 | 
				
			||||||
 | 
					  //   });
 | 
				
			||||||
 | 
					  //   await agent.resource('posts').destroy({
 | 
				
			||||||
 | 
					  //     resourceIndex: response.body.data.id,
 | 
				
			||||||
 | 
					  //   });
 | 
				
			||||||
 | 
					  //   const ActionLog = db.getCollection('action_logs').model;
 | 
				
			||||||
 | 
					  //   const count = await ActionLog.count();
 | 
				
			||||||
 | 
					  //   expect(count).toBe(3);
 | 
				
			||||||
 | 
					  // });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					import { defineCollection } from '@nocobase/database';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineCollection({
 | 
				
			||||||
 | 
					  dumpRules: {
 | 
				
			||||||
 | 
					    group: 'log',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  name: 'auditChanges',
 | 
				
			||||||
 | 
					  title: '变动值',
 | 
				
			||||||
 | 
					  createdBy: false,
 | 
				
			||||||
 | 
					  updatedBy: false,
 | 
				
			||||||
 | 
					  createdAt: false,
 | 
				
			||||||
 | 
					  updatedAt: false,
 | 
				
			||||||
 | 
					  shared: true,
 | 
				
			||||||
 | 
					  fields: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'json',
 | 
				
			||||||
 | 
					      name: 'field',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'json',
 | 
				
			||||||
 | 
					      name: 'before',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'json',
 | 
				
			||||||
 | 
					      name: 'after',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'belongsTo',
 | 
				
			||||||
 | 
					      name: 'log',
 | 
				
			||||||
 | 
					      target: 'auditLogs',
 | 
				
			||||||
 | 
					      foreignKey: 'auditLogId',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					import { defineCollection } from '@nocobase/database';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineCollection({
 | 
				
			||||||
 | 
					  dumpRules: {
 | 
				
			||||||
 | 
					    group: 'log',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  name: 'auditLogs',
 | 
				
			||||||
 | 
					  createdBy: false,
 | 
				
			||||||
 | 
					  updatedBy: false,
 | 
				
			||||||
 | 
					  updatedAt: false,
 | 
				
			||||||
 | 
					  shared: true,
 | 
				
			||||||
 | 
					  fields: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'date',
 | 
				
			||||||
 | 
					      name: 'createdAt',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'string',
 | 
				
			||||||
 | 
					      name: 'type',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'string',
 | 
				
			||||||
 | 
					      name: 'recordId',
 | 
				
			||||||
 | 
					      index: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'string',
 | 
				
			||||||
 | 
					      name: 'collectionName',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'belongsTo',
 | 
				
			||||||
 | 
					      name: 'collection',
 | 
				
			||||||
 | 
					      target: 'collections',
 | 
				
			||||||
 | 
					      targetKey: 'name',
 | 
				
			||||||
 | 
					      sourceKey: 'id',
 | 
				
			||||||
 | 
					      foreignKey: 'collectionName',
 | 
				
			||||||
 | 
					      constraints: false,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'hasMany',
 | 
				
			||||||
 | 
					      name: 'changes',
 | 
				
			||||||
 | 
					      target: 'auditChanges',
 | 
				
			||||||
 | 
					      foreignKey: 'auditLogId',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'belongsTo',
 | 
				
			||||||
 | 
					      name: 'user',
 | 
				
			||||||
 | 
					      target: 'users',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					export const LOG_TYPE_CREATE = 'create';
 | 
				
			||||||
 | 
					export const LOG_TYPE_UPDATE = 'update';
 | 
				
			||||||
 | 
					export const LOG_TYPE_DESTROY = 'destroy';
 | 
				
			||||||
@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					import { LOG_TYPE_CREATE } from '../constants';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function afterCreate(model, options) {
 | 
				
			||||||
 | 
					  if (options.logging === false) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const { collection } = model.constructor;
 | 
				
			||||||
 | 
					  if (!collection || !collection.options.logging) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const transaction = options.transaction;
 | 
				
			||||||
 | 
					  const AuditLog = model.constructor.database.getCollection('auditLogs');
 | 
				
			||||||
 | 
					  const currentUserId = options?.context?.state?.currentUser?.id;
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const changes = [];
 | 
				
			||||||
 | 
					    const changed = model.changed();
 | 
				
			||||||
 | 
					    if (changed) {
 | 
				
			||||||
 | 
					      changed.forEach((key: string) => {
 | 
				
			||||||
 | 
					        const field = collection.findField((field) => {
 | 
				
			||||||
 | 
					          return field.name === key || field.options.field === key;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        if (field && !field.options.hidden) {
 | 
				
			||||||
 | 
					          changes.push({
 | 
				
			||||||
 | 
					            field: field.options,
 | 
				
			||||||
 | 
					            after: model.get(key),
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    await AuditLog.repository.create({
 | 
				
			||||||
 | 
					      values: {
 | 
				
			||||||
 | 
					        type: LOG_TYPE_CREATE,
 | 
				
			||||||
 | 
					        collectionName: model.constructor.name,
 | 
				
			||||||
 | 
					        recordId: model.get(model.constructor.primaryKeyAttribute),
 | 
				
			||||||
 | 
					        createdAt: model.get('createdAt'),
 | 
				
			||||||
 | 
					        userId: currentUserId,
 | 
				
			||||||
 | 
					        changes,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      transaction,
 | 
				
			||||||
 | 
					      hooks: false,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    // console.error(error);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					import { LOG_TYPE_DESTROY } from '../constants';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function afterDestroy(model, options) {
 | 
				
			||||||
 | 
					  const { collection } = model.constructor;
 | 
				
			||||||
 | 
					  if (!collection || !collection.options.logging) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const transaction = options.transaction;
 | 
				
			||||||
 | 
					  const AuditLog = model.constructor.database.getCollection('auditLogs');
 | 
				
			||||||
 | 
					  const currentUserId = options?.context?.state?.currentUser?.id;
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const changes = [];
 | 
				
			||||||
 | 
					    Object.keys(model.get()).forEach((key: string) => {
 | 
				
			||||||
 | 
					      const field = collection.findField((field) => {
 | 
				
			||||||
 | 
					        return field.name === key || field.options.field === key;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      if (field) {
 | 
				
			||||||
 | 
					        changes.push({
 | 
				
			||||||
 | 
					          field: field.options,
 | 
				
			||||||
 | 
					          before: model.get(key),
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    await AuditLog.repository.create({
 | 
				
			||||||
 | 
					      values: {
 | 
				
			||||||
 | 
					        type: LOG_TYPE_DESTROY,
 | 
				
			||||||
 | 
					        collectionName: model.constructor.name,
 | 
				
			||||||
 | 
					        recordId: model.get(model.constructor.primaryKeyAttribute),
 | 
				
			||||||
 | 
					        userId: currentUserId,
 | 
				
			||||||
 | 
					        changes,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      transaction,
 | 
				
			||||||
 | 
					      hooks: false,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    // if (!options.transaction) {
 | 
				
			||||||
 | 
					    //   await transaction.commit();
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    // if (!options.transaction) {
 | 
				
			||||||
 | 
					    //   await transaction.rollback();
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					import { LOG_TYPE_UPDATE } from '../constants';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function afterUpdate(model, options) {
 | 
				
			||||||
 | 
					  const { collection } = model.constructor;
 | 
				
			||||||
 | 
					  if (!collection || !collection.options.logging) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const changed = model.changed();
 | 
				
			||||||
 | 
					  if (!changed) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const transaction = options.transaction;
 | 
				
			||||||
 | 
					  const AuditLog = model.constructor.database.getCollection('auditLogs');
 | 
				
			||||||
 | 
					  const currentUserId = options?.context?.state?.currentUser?.id;
 | 
				
			||||||
 | 
					  const changes = [];
 | 
				
			||||||
 | 
					  changed.forEach((key: string) => {
 | 
				
			||||||
 | 
					    const field = collection.findField((field) => {
 | 
				
			||||||
 | 
					      return field.name === key || field.options.field === key;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (field && !field.options.hidden) {
 | 
				
			||||||
 | 
					      changes.push({
 | 
				
			||||||
 | 
					        field: field.options,
 | 
				
			||||||
 | 
					        after: model.get(key),
 | 
				
			||||||
 | 
					        before: model.previous(key),
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  if (!changes.length) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    await AuditLog.repository.create({
 | 
				
			||||||
 | 
					      values: {
 | 
				
			||||||
 | 
					        type: LOG_TYPE_UPDATE,
 | 
				
			||||||
 | 
					        collectionName: model.constructor.name,
 | 
				
			||||||
 | 
					        recordId: model.get(model.constructor.primaryKeyAttribute),
 | 
				
			||||||
 | 
					        createdAt: model.get('updatedAt'),
 | 
				
			||||||
 | 
					        userId: currentUserId,
 | 
				
			||||||
 | 
					        changes,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      transaction,
 | 
				
			||||||
 | 
					      hooks: false,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    // if (!options.transaction) {
 | 
				
			||||||
 | 
					    //   await transaction.commit();
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    // if (!options.transaction) {
 | 
				
			||||||
 | 
					    //   await transaction.rollback();
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					export * from './after-create';
 | 
				
			||||||
 | 
					export * from './after-update';
 | 
				
			||||||
 | 
					export * from './after-destroy';
 | 
				
			||||||
							
								
								
									
										23
									
								
								packages/plugins/@hera/plugin-audit-logs/src/server/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								packages/plugins/@hera/plugin-audit-logs/src/server/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { Plugin } from '@nocobase/server';
 | 
				
			||||||
 | 
					import path from 'path';
 | 
				
			||||||
 | 
					import { afterCreate, afterDestroy, afterUpdate } from './hooks';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class PluginActionLogs extends Plugin {
 | 
				
			||||||
 | 
					  async beforeLoad() {
 | 
				
			||||||
 | 
					    this.db.on('afterCreate', afterCreate);
 | 
				
			||||||
 | 
					    this.db.on('afterUpdate', afterUpdate);
 | 
				
			||||||
 | 
					    this.db.on('afterDestroy', afterDestroy);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async load() {
 | 
				
			||||||
 | 
					    await this.importCollections(path.resolve(__dirname, 'collections'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.db.addMigrations({
 | 
				
			||||||
 | 
					      namespace: 'audit-logs',
 | 
				
			||||||
 | 
					      directory: path.resolve(__dirname, './migrations'),
 | 
				
			||||||
 | 
					      context: {
 | 
				
			||||||
 | 
					        plugin: this,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user