Merge pull request 'main' (#349) from main into @hera/dev
Reviewed-on: daoyoucloud/tachycode#349
This commit is contained in:
commit
1737a0f83b
@ -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);
|
||||||
|
|
||||||
|
@ -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}
|
||||||
|
@ -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();
|
||||||
|
@ -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: {
|
||||||
|
@ -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',
|
||||||
|
@ -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]}
|
||||||
|
@ -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}
|
||||||
|
@ -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',
|
||||||
|
@ -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: {
|
||||||
|
@ -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')) {
|
||||||
|
@ -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>;
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -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',
|
||||||
|
@ -62,6 +62,6 @@ export default function addRestoreCommand(app: Application) {
|
|||||||
groups,
|
groups,
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.restart();
|
await app.upgrade();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user