Merge pull request 'main' (#349) from main into @hera/dev

Reviewed-on: daoyoucloud/tachycode#349
This commit is contained in:
sealday 2024-03-12 20:00:15 +08:00
commit 1737a0f83b
18 changed files with 209 additions and 101 deletions

View File

@ -164,9 +164,9 @@ export class ACL extends EventEmitter {
const snippetAllowed = aclRole.snippetAllowed(`${resource}:${action}`); const snippetAllowed = aclRole.snippetAllowed(`${resource}:${action}`);
if (snippetAllowed === false) { // if (snippetAllowed === false) {
return null; // return null;
} // }
const fixedParams = this.fixedParamsManager.getParams(resource, action); const fixedParams = this.fixedParamsManager.getParams(resource, action);

View File

@ -221,11 +221,11 @@ export const ForeignKey = observer(
const { getCollection } = useCollectionManager_deprecated(); const { getCollection } = useCollectionManager_deprecated();
const record = useRecord(); const record = useRecord();
const field: any = useField(); const field: any = useField();
const { collectionName, target, type, through, name } = record; const { collectionName, target, type, through, name, template } = record;
const value = record[field.props.name]; const value = record[field.props.name];
const compile = useCompile(); const compile = useCompile();
const form = useForm(); const form = useForm();
const [initialValue, setInitialValue] = useState(value || field.initialValue); const [initialValue, setInitialValue] = useState(value || (template === 'view' ? null : field.initialValue));
useEffect(() => { useEffect(() => {
const effectField = ['belongsTo'].includes(type) const effectField = ['belongsTo'].includes(type)
? collectionName ? collectionName
@ -251,9 +251,10 @@ export const ForeignKey = observer(
} }
} }
}, [type]); }, [type]);
const Compoent = template === 'view' ? Select : AutoComplete;
return ( return (
<div> <div>
<AutoComplete <Compoent
disabled={disabled} disabled={disabled}
value={initialValue} value={initialValue}
options={options} options={options}

View File

@ -16,8 +16,8 @@ export class InheritanceCollectionMixin extends Collection {
protected foreignKeyFields: CollectionFieldOptions[]; protected foreignKeyFields: CollectionFieldOptions[];
getParentCollectionsName() { getParentCollectionsName() {
if (this.parentCollectionsName?.length) { if (this.parentCollectionsName) {
return this.parentCollectionsName; return this.parentCollectionsName.slice();
} }
const parents: string[] = []; const parents: string[] = [];
@ -41,8 +41,8 @@ export class InheritanceCollectionMixin extends Collection {
} }
getParentCollections() { getParentCollections() {
if (this.parentCollections?.length) { if (this.parentCollections) {
return this.parentCollections; return this.parentCollections.slice();
} }
this.parentCollections = this.getParentCollectionsName().map((collectionName) => { this.parentCollections = this.getParentCollectionsName().map((collectionName) => {
return this.collectionManager.getCollection(collectionName); return this.collectionManager.getCollection(collectionName);
@ -52,8 +52,8 @@ export class InheritanceCollectionMixin extends Collection {
getChildrenCollectionsName(isSupportView = false) { getChildrenCollectionsName(isSupportView = false) {
const cacheKey = isSupportView ? 'supportView' : 'notSupportView'; const cacheKey = isSupportView ? 'supportView' : 'notSupportView';
if (this.childrenCollectionsName[cacheKey]?.length) { if (this.childrenCollectionsName[cacheKey]) {
return this.childrenCollectionsName[cacheKey]; return this.childrenCollectionsName[cacheKey].slice();
} }
const children: string[] = []; const children: string[] = [];
@ -86,8 +86,8 @@ export class InheritanceCollectionMixin extends Collection {
getChildrenCollections(isSupportView = false) { getChildrenCollections(isSupportView = false) {
const cacheKey = isSupportView ? 'supportView' : 'notSupportView'; const cacheKey = isSupportView ? 'supportView' : 'notSupportView';
if (this.childrenCollections[cacheKey]?.length) { if (this.childrenCollections[cacheKey]) {
return this.childrenCollections[cacheKey]; return this.childrenCollections[cacheKey].slice();
} }
this.childrenCollections[cacheKey] = this.getChildrenCollectionsName(isSupportView).map((collectionName) => { this.childrenCollections[cacheKey] = this.getChildrenCollectionsName(isSupportView).map((collectionName) => {
return this.collectionManager.getCollection(collectionName); return this.collectionManager.getCollection(collectionName);
@ -96,8 +96,8 @@ export class InheritanceCollectionMixin extends Collection {
} }
getInheritedFields() { getInheritedFields() {
if (this.inheritsFields?.length) { if (this.inheritsFields) {
return this.inheritsFields; return this.inheritsFields.slice();
} }
const parentCollections = this.getParentCollectionsName(); const parentCollections = this.getParentCollectionsName();
@ -155,8 +155,8 @@ export class InheritanceCollectionMixin extends Collection {
} }
getAllCollectionsInheritChain() { getAllCollectionsInheritChain() {
if (this.allCollectionsInheritChain?.length) { if (this.allCollectionsInheritChain) {
return this.allCollectionsInheritChain; return this.allCollectionsInheritChain.slice();
} }
const collectionsInheritChain = [this.name]; const collectionsInheritChain = [this.name];
@ -197,8 +197,8 @@ export class InheritanceCollectionMixin extends Collection {
} }
getInheritCollectionsChain() { getInheritCollectionsChain() {
if (this.inheritCollectionsChain?.length) { if (this.inheritCollectionsChain) {
return this.inheritCollectionsChain; return this.inheritCollectionsChain.slice();
} }
const collectionsInheritChain = [this.name]; const collectionsInheritChain = [this.name];
const getInheritChain = (name: string) => { const getInheritChain = (name: string) => {
@ -225,8 +225,8 @@ export class InheritanceCollectionMixin extends Collection {
} }
getAllFields(predicate?: GetCollectionFieldPredicate) { getAllFields(predicate?: GetCollectionFieldPredicate) {
if (this.allFields?.length) { if (this.allFields) {
return this.allFields; return this.allFields.slice();
} }
const currentFields = this.getCurrentFields(); const currentFields = this.getCurrentFields();
const inheritedFields = this.getInheritedFields(); const inheritedFields = this.getInheritedFields();
@ -240,8 +240,8 @@ export class InheritanceCollectionMixin extends Collection {
} }
getForeignKeyFields() { getForeignKeyFields() {
if (this.foreignKeyFields?.length) { if (this.foreignKeyFields) {
return this.foreignKeyFields; return this.foreignKeyFields.slice();
} }
const currentFields = this.getCurrentFields(); const currentFields = this.getCurrentFields();
const inheritedFields = this.getInheritedFields(); const inheritedFields = this.getInheritedFields();

View File

@ -10,10 +10,11 @@ export const CreateChildInitializer = (props) => {
'x-component': 'Action', 'x-component': 'Action',
'x-visible': '{{treeTable}}', 'x-visible': '{{treeTable}}',
'x-component-props': { 'x-component-props': {
icon: 'PlusOutlined',
openMode: 'drawer', openMode: 'drawer',
type: 'primary', type: 'link',
addChild: true, addChild: true,
style: { padding: '0px', marginTop: '-5px' },
component: 'CreateRecordAction',
}, },
properties: { properties: {
drawer: { drawer: {

View File

@ -1,9 +1,11 @@
import { useFieldSchema } from '@formily/react';
import { useMemo } from 'react';
import { useSchemaToolbar } from '../../../application'; import { useSchemaToolbar } from '../../../application';
import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings'; import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings';
import { useCollection_deprecated } from '../../../collection-manager'; import { useCollection_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
import { ButtonEditor } from '../../../schema-component/antd/action/Action.Designer'; import { ButtonEditor } from '../../../schema-component/antd/action/Action.Designer';
import { SchemaSettingOpenModeSchemaItems } from '../../../schema-items'; import { SchemaSettingOpenModeSchemaItems } from '../../../schema-items';
import { SchemaSettingsLinkageRules } from '../../../schema-settings'; import { SchemaSettingsLinkageRules, SchemaSettingsEnableChildCollections } from '../../../schema-settings';
export const addChildActionSettings = new SchemaSettings({ export const addChildActionSettings = new SchemaSettings({
name: 'actionSettings:addChild', name: 'actionSettings:addChild',
@ -36,6 +38,25 @@ export const addChildActionSettings = new SchemaSettings({
openSize: true, openSize: true,
}, },
}, },
{
name: 'enableChildCollections',
Component: SchemaSettingsEnableChildCollections,
useVisible() {
const { name } = useCollection_deprecated();
const { getChildrenCollections } = useCollectionManager_deprecated();
const isChildCollectionAction = useMemo(
() => getChildrenCollections(name).length > 0,
[getChildrenCollections, name],
);
return isChildCollectionAction;
},
useComponentProps() {
const { name } = useCollection_deprecated();
return {
collectionName: name,
};
},
},
{ {
name: 'delete', name: 'delete',
type: 'remove', type: 'remove',

View File

@ -89,11 +89,11 @@ export function ButtonEditor(props) {
field.title = title; field.title = title;
field.componentProps.icon = icon; field.componentProps.icon = icon;
field.componentProps.danger = type === 'danger'; field.componentProps.danger = type === 'danger';
field.componentProps.type = type; field.componentProps.type = type || field.componentProps.type;
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {}; fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
fieldSchema['x-component-props'].icon = icon; fieldSchema['x-component-props'].icon = icon;
fieldSchema['x-component-props'].danger = type === 'danger'; fieldSchema['x-component-props'].danger = type === 'danger';
fieldSchema['x-component-props'].type = type; fieldSchema['x-component-props'].type = type || field.componentProps.type;
dn.emit('patch', { dn.emit('patch', {
schema: { schema: {
['x-uid']: fieldSchema['x-uid'], ['x-uid']: fieldSchema['x-uid'],
@ -167,7 +167,7 @@ export function AssignedFieldValues() {
<DefaultValueProvider isAllowToSetDefaultValue={() => false}> <DefaultValueProvider isAllowToSetDefaultValue={() => false}>
<SchemaSettingsActionModalItem <SchemaSettingsActionModalItem
title={t('Assign field values')} title={t('Assign field values')}
maskClosable={false} // maskClosable={false}
initialSchema={initialSchema} initialSchema={initialSchema}
initialValues={fieldSchema?.['x-action-settings']?.assignedValues} initialValues={fieldSchema?.['x-action-settings']?.assignedValues}
modalTip={tips[actionType]} modalTip={tips[actionType]}

View File

@ -292,8 +292,13 @@ function FinallyButton({
type={componentType} type={componentType}
icon={<DownOutlined />} icon={<DownOutlined />}
buttonsRender={([leftButton, rightButton]) => [ buttonsRender={([leftButton, rightButton]) => [
leftButton, React.cloneElement(leftButton as React.ReactElement<any, string>, {
React.cloneElement(rightButton as React.ReactElement<any, string>, { loading: false }), style: props?.style,
}),
React.cloneElement(rightButton as React.ReactElement<any, string>, {
loading: false,
style: props?.style,
}),
]} ]}
menu={menu} menu={menu}
onClick={(info) => { onClick={(info) => {
@ -306,7 +311,13 @@ function FinallyButton({
) : ( ) : (
<Dropdown menu={menu}> <Dropdown menu={menu}>
{ {
<Button aria-label={props['aria-label']} icon={icon} type={componentType} danger={props.danger}> <Button
aria-label={props['aria-label']}
icon={icon}
type={componentType}
danger={props.danger}
style={props?.style}
>
{props.children} <DownOutlined /> {props.children} <DownOutlined />
</Button> </Button>
} }
@ -337,9 +348,9 @@ function FinallyButton({
</Button> </Button>
); );
} }
return ( return (
<Button <Button
{...props}
aria-label={props['aria-label']} aria-label={props['aria-label']}
type={componentType} type={componentType}
disabled={field.disabled} disabled={field.disabled}

View File

@ -90,6 +90,41 @@ describe('string field', () => {
console.log(end - begin); console.log(end - begin);
}); });
it('should init sorted value with null scopeValue', async () => {
const Test = db.collection({
name: 'tests',
fields: [
{
type: 'string',
name: 'name',
},
{
type: 'string',
name: 'group',
},
],
});
await db.sync();
await Test.repository.create({
values: [
{
group: null,
name: 'r5',
},
{
group: null,
name: 'r6',
},
],
});
Test.setField('sort', { type: 'sort', scopeKey: 'group' });
await db.sync();
});
it('should init sorted value with scopeKey', async () => { it('should init sorted value with scopeKey', async () => {
const Test = db.collection({ const Test = db.collection({
name: 'tests', name: 'tests',

View File

@ -24,6 +24,22 @@ describe('string operator', () => {
}); });
}); });
it('should escape underscore in inlcude operator', async () => {
const u1 = await db.getRepository('users').create({
values: {
name: 'names of u1',
},
});
const u1Res = await db.getRepository('users').findOne({
filter: {
'name.$includes': '_',
},
});
expect(u1Res).toBeNull();
});
it('should query with include operator', async () => { it('should query with include operator', async () => {
const u1 = await db.getRepository('users').create({ const u1 = await db.getRepository('users').create({
values: { values: {

View File

@ -99,11 +99,19 @@ export class SortField extends Field {
const whereClause = const whereClause =
scopeKey && scopeValue scopeKey && scopeValue
? ` ? (() => {
WHERE ${queryInterface.quoteIdentifier(scopeKey)} IN (${scopeValue const filteredScopeValue = scopeValue.filter((v) => v !== null);
.filter((v) => v !== null) if (filteredScopeValue.length === 0) {
.map((v) => `'${v}'`) return '';
.join(', ')})${scopeValue.includes(null) ? ` OR ${queryInterface.quoteIdentifier(scopeKey)} IS NULL` : ''}` }
const initialClause = `
WHERE ${queryInterface.quoteIdentifier(scopeKey)} IN (${filteredScopeValue.map((v) => `'${v}'`).join(', ')})`;
const nullCheck = scopeValue.includes(null)
? ` OR ${queryInterface.quoteIdentifier(scopeKey)} IS NULL`
: '';
return initialClause + nullCheck;
})()
: ''; : '';
if (this.collection.db.inDialect('postgres')) { if (this.collection.db.inDialect('postgres')) {

View File

@ -1,11 +1,15 @@
import { Op } from 'sequelize'; import { Op } from 'sequelize';
import { isPg } from './utils'; import { isPg } from './utils';
function escapeLike(value: string) {
return value.replace(/[_%]/g, '\\$&');
}
export default { export default {
$includes(value, ctx) { $includes(value, ctx) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const conditions = value.map((item) => ({ const conditions = value.map((item) => ({
[isPg(ctx) ? Op.iLike : Op.like]: `%${item}%`, [isPg(ctx) ? Op.iLike : Op.like]: `%${escapeLike(item)}%`,
})); }));
return { return {
@ -14,14 +18,14 @@ export default {
} }
return { return {
[isPg(ctx) ? Op.iLike : Op.like]: `%${value}%`, [isPg(ctx) ? Op.iLike : Op.like]: `%${escapeLike(value)}%`,
}; };
}, },
$notIncludes(value, ctx) { $notIncludes(value, ctx) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const conditions = value.map((item) => ({ const conditions = value.map((item) => ({
[isPg(ctx) ? Op.notILike : Op.notLike]: `%${item}%`, [isPg(ctx) ? Op.notILike : Op.notLike]: `%${escapeLike(item)}%`,
})); }));
return { return {
@ -30,14 +34,14 @@ export default {
} }
return { return {
[isPg(ctx) ? Op.notILike : Op.notLike]: `%${value}%`, [isPg(ctx) ? Op.notILike : Op.notLike]: `%${escapeLike(value)}%`,
}; };
}, },
$startsWith(value, ctx) { $startsWith(value, ctx) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const conditions = value.map((item) => ({ const conditions = value.map((item) => ({
[isPg(ctx) ? Op.iLike : Op.like]: `${item}%`, [isPg(ctx) ? Op.iLike : Op.like]: `${escapeLike(item)}%`,
})); }));
return { return {
@ -46,14 +50,14 @@ export default {
} }
return { return {
[isPg(ctx) ? Op.iLike : Op.like]: `${value}%`, [isPg(ctx) ? Op.iLike : Op.like]: `${escapeLike(value)}%`,
}; };
}, },
$notStartsWith(value, ctx) { $notStartsWith(value, ctx) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const conditions = value.map((item) => ({ const conditions = value.map((item) => ({
[isPg(ctx) ? Op.notILike : Op.notLike]: `${item}%`, [isPg(ctx) ? Op.notILike : Op.notLike]: `${escapeLike(item)}%`,
})); }));
return { return {
@ -62,14 +66,14 @@ export default {
} }
return { return {
[isPg(ctx) ? Op.notILike : Op.notLike]: `${value}%`, [isPg(ctx) ? Op.notILike : Op.notLike]: `${escapeLike(value)}%`,
}; };
}, },
$endWith(value, ctx) { $endWith(value, ctx) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const conditions = value.map((item) => ({ const conditions = value.map((item) => ({
[isPg(ctx) ? Op.iLike : Op.like]: `%${item}`, [isPg(ctx) ? Op.iLike : Op.like]: `%${escapeLike(item)}`,
})); }));
return { return {
@ -78,14 +82,14 @@ export default {
} }
return { return {
[isPg(ctx) ? Op.iLike : Op.like]: `%${value}`, [isPg(ctx) ? Op.iLike : Op.like]: `%${escapeLike(value)}`,
}; };
}, },
$notEndWith(value, ctx) { $notEndWith(value, ctx) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
const conditions = value.map((item) => ({ const conditions = value.map((item) => ({
[isPg(ctx) ? Op.notILike : Op.notLike]: `%${item}`, [isPg(ctx) ? Op.notILike : Op.notLike]: `%${escapeLike(item)}`,
})); }));
return { return {
@ -94,7 +98,7 @@ export default {
} }
return { return {
[isPg(ctx) ? Op.notILike : Op.notLike]: `%${value}`, [isPg(ctx) ? Op.notILike : Op.notLike]: `%${escapeLike(value)}`,
}; };
}, },
} as Record<string, any>; } as Record<string, any>;

View File

@ -10,7 +10,7 @@ class ACLPlugin extends Plugin {
title: '{{t("Roles & Permissions")}}', title: '{{t("Roles & Permissions")}}',
icon: 'LockOutlined', icon: 'LockOutlined',
Component: RolesManagement, Component: RolesManagement,
aclSnippet: 'pm.roles', aclSnippet: 'pm.acl.roles',
sort: 3, sort: 3,
}); });
} }

View File

@ -12,7 +12,7 @@ describe('snippet', () => {
await app.destroy(); await app.destroy();
}); });
it('should not allow to create collections when global allow create', async () => { it.skip('should not allow to create collections when global allow create', async () => {
await app.db.getRepository('roles').create({ await app.db.getRepository('roles').create({
values: { values: {
name: 'testRole', name: 'testRole',
@ -32,4 +32,26 @@ describe('snippet', () => {
expect(createCollectionResponse.statusCode).toEqual(403); expect(createCollectionResponse.statusCode).toEqual(403);
}); });
it('should allowed when snippet not allowed but resource allowed', async () => {
await app.db.getRepository('roles').create({
values: {
name: 'testRole',
strategy: { actions: ['view'] },
snippets: ['!ui.*', '!pm', '!pm.*'],
},
});
const testUser = await app.db.getRepository('users').create({
values: {
roles: ['testRole'],
},
});
const userAgent: any = app.agent().login(testUser);
const listResp = await userAgent.resource('users').list();
expect(listResp.statusCode).toEqual(200);
});
}); });

View File

@ -1,22 +1,17 @@
import { ISchema, useField, useFieldSchema } from '@formily/react'; import { ISchema, useFieldSchema } from '@formily/react';
import { isValid, uid } from '@formily/shared'; import { isValid } from '@formily/shared';
import { import {
ActionDesigner, ActionDesigner,
DefaultValueProvider,
FlagProvider,
SchemaSettings, SchemaSettings,
SchemaSettingsActionModalItem,
SchemaSettingsItemGroup,
SchemaSettingsItemType, SchemaSettingsItemType,
SchemaSettingsModalItem, SchemaSettingsModalItem,
SchemaSettingsSelectItem, SchemaSettingsSelectItem,
AssignedFieldValues, AssignedFieldValues,
useCompile,
useDesignable, useDesignable,
useSchemaToolbar, useSchemaToolbar,
} from '@nocobase/client'; } from '@nocobase/client';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import React, { useCallback, useEffect, useState } from 'react'; import React from 'react';
function UpdateMode() { function UpdateMode() {
const { dn } = useDesignable(); const { dn } = useDesignable();
@ -135,10 +130,6 @@ const schemaSettingsItems: SchemaSettingsItemType[] = [
{ {
name: 'assignFieldValues', name: 'assignFieldValues',
Component: AssignedFieldValues, Component: AssignedFieldValues,
// useVisible() {
// const fieldSchema = useFieldSchema();
// return isValid(fieldSchema?.['x-action-settings']?.assignedValues);
// },
}, },
{ {
name: 'afterSuccess', name: 'afterSuccess',

View File

@ -62,6 +62,6 @@ export default function addRestoreCommand(app: Application) {
groups, groups,
}); });
await app.restart(); await app.upgrade();
}); });
} }

View File

@ -79,7 +79,6 @@ export class Restorer extends AppMigrator {
await this.checkMeta(); await this.checkMeta();
await this.importCollections(options); await this.importCollections(options);
await this.importDb(options); await this.importDb(options);
await this.upgradeApp();
await this.clearWorkDir(); await this.clearWorkDir();
} }
@ -398,8 +397,4 @@ export class Restorer extends AppMigrator {
} }
} }
} }
async upgradeApp() {
await this.app.runCommand('upgrade');
}
} }

View File

@ -22,6 +22,7 @@ import {
useCurrentAppInfo, useCurrentAppInfo,
useAPIClient, useAPIClient,
useFieldInterfaceOptions, useFieldInterfaceOptions,
useDataSourceManager,
} from '@nocobase/client'; } from '@nocobase/client';
import { ForeignKey } from './components'; import { ForeignKey } from './components';
@ -157,6 +158,7 @@ const useCreateCollectionField = () => {
const api = useAPIClient(); const api = useAPIClient();
const record = useRecord(); const record = useRecord();
const { name: dataSourceKey } = useParams(); const { name: dataSourceKey } = useParams();
const dm = useDataSourceManager();
return { return {
async run() { async run() {
await form.submit(); await form.submit();
@ -176,6 +178,7 @@ const useCreateCollectionField = () => {
data: values, data: values,
}); });
ctx.setVisible(false); ctx.setVisible(false);
dm.getDataSource(dataSourceKey).reload();
await form.reset(); await form.reset();
field.data.loading = false; field.data.loading = false;
refresh(); refresh();

View File

@ -22,7 +22,7 @@ const rolesRemoteCollectionsResourcer = {
const collectionRepository = new FullDataRepository<any>(dataSource.collectionManager.getCollections()); const collectionRepository = new FullDataRepository<any>(dataSource.collectionManager.getCollections());
// all collections // all collections
const [collections, count] = await collectionRepository.findAndCount(); const [collections] = await collectionRepository.findAndCount();
const filterItem = lodash.get(filter, '$and'); const filterItem = lodash.get(filter, '$and');
const filterByTitle = filterItem?.find((item) => item.title); const filterByTitle = filterItem?.find((item) => item.title);
@ -45,44 +45,44 @@ const rolesRemoteCollectionsResourcer = {
.filter((roleResources) => roleResources.get('usingActionsConfig')) .filter((roleResources) => roleResources.get('usingActionsConfig'))
.map((roleResources) => roleResources.get('name')); .map((roleResources) => roleResources.get('name'));
const filtedCollections = collections.filter((collection) => {
return (
(!filterTitle || lodash.get(collection, 'options.title')?.toLowerCase().includes(filterTitle)) &&
(!filterName || collection.options.name.toLowerCase().includes(filterName))
);
});
const items = lodash.sortBy( const items = lodash.sortBy(
collections filtedCollections.map((collection, i) => {
.filter((collection) => { const collectionName = collection.options.name;
return ( const exists = roleResourcesNames.includes(collectionName);
(!filterTitle || lodash.get(collection, 'options.title')?.toLowerCase().includes(filterTitle)) &&
(!filterName || collection.options.name.toLowerCase().includes(filterName))
);
})
.map((collection, i) => {
const collectionName = collection.options.name;
const exists = roleResourcesNames.includes(collectionName);
const usingConfig: UsingConfigType = roleResourceActionResourceNames.includes(collectionName) const usingConfig: UsingConfigType = roleResourceActionResourceNames.includes(collectionName)
? 'resourceAction' ? 'resourceAction'
: 'strategy'; : 'strategy';
return { return {
type: 'collection', type: 'collection',
name: collectionName, name: collectionName,
collectionName, collectionName,
title: collection.options.uiSchema?.title || collection.options.title, title: collection.options.uiSchema?.title || collection.options.title,
roleName: role, roleName: role,
usingConfig, usingConfig,
exists, exists,
fields: [...collection.fields.values()].map((field) => { fields: [...collection.fields.values()].map((field) => {
return field.options; return field.options;
}), }),
}; };
}), }),
'name', 'name',
); );
ctx.body = { ctx.body = {
count, count: filtedCollections.length,
rows: items, rows: items,
page: Number(page), page: Number(page),
pageSize: Number(pageSize), pageSize: Number(pageSize),
totalPage: totalPage(count, pageSize), totalPage: totalPage(filtedCollections.length, pageSize),
}; };
await next(); await next();