refactor(plugin-file-manager): make attachments manageable

This commit is contained in:
mytharcher 2025-06-24 22:10:26 +08:00
parent e527e4d6ba
commit f07bd5a679
8 changed files with 143 additions and 4 deletions

View File

@ -120,11 +120,15 @@ export const DeleteCollectionAction = (props) => {
<RecordProvider record={record}>
<ActionContextProvider value={{ visible, setVisible }}>
{isBulk ? (
<Button icon={<DeleteOutlined />} onClick={() => setVisible(true)}>
<Button icon={<DeleteOutlined />} onClick={() => setVisible(true)} disabled={record.deletable === false}>
{children || t('Delete')}
</Button>
) : (
<a onClick={() => setVisible(true)} {...otherProps}>
<a
onClick={record.deletable === false ? null : () => setVisible(true)}
{...otherProps}
style={record.deletable === false ? { color: 'rgba(0, 0, 0, 0.25)', cursor: 'not-allowed' } : {}}
>
{children || t('Delete')}
</a>
)}

View File

@ -25,7 +25,7 @@ export class AttachmentFieldInterface extends CollectionFieldInterface {
uiSchema: {
type: 'array',
// title,
'x-component': 'Upload.Attachment',
'x-component': 'AssociationField',
'x-use-component-props': 'useAttachmentFieldProps',
},
};

View File

@ -132,6 +132,7 @@ export class FileCollectionTemplate extends CollectionTemplate {
target: 'storages',
foreignKey: 'storageId',
deletable: false,
interface: 'm2o',
uiSchema: {
type: 'string',
title: `{{t("Storage", { ns: "${NAMESPACE}" })}}`,

View File

@ -7,7 +7,10 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { NAMESPACE } from '../constants';
export default {
title: `{{t("Attachments", { ns: "${NAMESPACE}" })}}`,
dumpRules: {
group: 'user',
},
@ -19,26 +22,75 @@ export default {
updatedBy: true,
template: 'file',
filterTargetKey: 'id',
deletable: false,
fields: [
{
type: 'bigInt',
name: 'id',
deletable: false,
interface: 'number',
autoIncrement: true,
uiSchema: {
type: 'number',
title: `{{t("ID")}}`,
'x-component': 'InputNumber',
'x-read-pretty': true,
},
},
{
comment: '用户文件名(不含扩展名)',
type: 'string',
name: 'title',
deletable: false,
interface: 'input',
uiSchema: {
type: 'string',
title: `{{t("Title")}}`,
'x-component': 'Input',
},
},
{
comment: '系统文件名(含扩展名)',
type: 'string',
name: 'filename',
deletable: false,
interface: 'input',
uiSchema: {
type: 'string',
title: `{{t("File name", { ns: "${NAMESPACE}" })}}`,
'x-component': 'Input',
'x-read-pretty': true,
},
},
{
comment: '扩展名(含“.”)',
type: 'string',
name: 'extname',
deletable: false,
interface: 'input',
uiSchema: {
type: 'string',
title: `{{t("Extension name", { ns: "${NAMESPACE}" })}}`,
'x-component': 'Input',
'x-read-pretty': true,
},
},
{
comment: '文件体积(字节)',
type: 'integer',
name: 'size',
deletable: false,
interface: 'integer',
uiSchema: {
type: 'number',
title: `{{t("Size", { ns: "${NAMESPACE}" })}}`,
'x-component': 'InputNumber',
'x-read-pretty': true,
'x-component-props': {
stringMode: true,
step: '0',
},
},
},
// TODO: 使用暂不明确,以后再考虑
// {
@ -49,28 +101,81 @@ export default {
{
type: 'string',
name: 'mimetype',
deletable: false,
interface: 'input',
uiSchema: {
type: 'string',
title: `{{t("MIME type", { ns: "${NAMESPACE}" })}}`,
'x-component': 'Input',
'x-read-pretty': true,
},
},
{
comment: '存储引擎',
type: 'belongsTo',
name: 'storage',
deletable: false,
interface: 'm2o',
uiSchema: {
type: 'string',
title: `{{t("Storage engine", { ns: "${NAMESPACE}" })}}`,
'x-component': 'Input',
'x-read-pretty': true,
},
},
{
comment: '相对路径(含“/”前缀)',
type: 'text',
name: 'path',
deletable: false,
interface: 'input',
uiSchema: {
type: 'string',
title: `{{t("Path", { ns: "${NAMESPACE}" })}}`,
'x-component': 'Input',
'x-read-pretty': true,
},
},
{
comment: '其他文件信息(如图片的宽高)',
type: 'jsonb',
name: 'meta',
defaultValue: {},
deletable: false,
interface: 'json',
uiSchema: {
type: 'object',
title: `{{t("Meta", { ns: "${NAMESPACE}" })}}`,
'x-component': 'Input.JSON',
'x-read-pretty': true,
},
},
{
comment: '网络访问地址',
type: 'text',
name: 'url',
// formula: '{{ storage.baseUrl }}{{ path }}/{{ filename }}'
deletable: false,
interface: 'url',
uiSchema: {
type: 'string',
title: `{{t("URL", { ns: "${NAMESPACE}" })}}`,
'x-component': 'Input.URL',
'x-read-pretty': true,
},
},
// 用于预览
{
interface: 'url',
type: 'text',
name: 'preview',
field: 'url', // 直接引用 url 字段
deletable: false,
uiSchema: {
type: 'string',
title: `{{t("Preview", { ns: "${NAMESPACE}" })}}`,
'x-component': 'Preview',
'x-read-pretty': true,
},
},
],
};

View File

@ -7,4 +7,6 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
export const NAMESPACE = 'file-manager';
export const INVALID_FILENAME_CHARS = '<>?*~\\/';

View File

@ -12,6 +12,7 @@
"File storage": "文件存储",
"File manager": "文件管理器",
"Attachment": "附件",
"Attachments": "附件",
"Allow uploading multiple files": "允许上传多个文件",
"Storage": "存储空间",
"Storages": "存储空间",

View File

@ -0,0 +1,21 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Migration } from '@nocobase/server';
import { CollectionRepository } from '@nocobase/plugin-data-source-main';
export default class extends Migration {
on = 'afterLoad'; // 'beforeLoad' or 'afterLoad'
appVersion = '<1.8.0';
async up() {
const CollectionRepo = this.db.getRepository('collections') as CollectionRepository;
await CollectionRepo.db2cm('attachments');
}
}

View File

@ -163,6 +163,11 @@ export class PluginFileManagerServer extends Plugin {
}
async install() {
const collectionRepo = this.db.getRepository<any>('collections');
if (collectionRepo) {
await collectionRepo.db2cm('attachments');
}
const defaultStorageType = this.storageTypes.get(DEFAULT_STORAGE_TYPE);
if (defaultStorageType) {