feat: filter with variable (#574)
This commit is contained in:
parent
ec7bc2bc8b
commit
e3b6c0513a
@ -1,12 +1,12 @@
|
|||||||
import { Action } from '@nocobase/resourcer';
|
import { Action } from '@nocobase/resourcer';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
|
import parse from 'json-templates';
|
||||||
import compose from 'koa-compose';
|
import compose from 'koa-compose';
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
import { AclAvailableAction, AvailableActionOptions } from './acl-available-action';
|
import { AclAvailableAction, AvailableActionOptions } from './acl-available-action';
|
||||||
import { ACLAvailableStrategy, AvailableStrategyOptions, predicate } from './acl-available-strategy';
|
import { ACLAvailableStrategy, AvailableStrategyOptions, predicate } from './acl-available-strategy';
|
||||||
import { ACLRole, RoleActionParams } from './acl-role';
|
import { ACLRole, RoleActionParams } from './acl-role';
|
||||||
import { AllowManager } from './allow-manager';
|
import { AllowManager } from './allow-manager';
|
||||||
const parse = require('json-templates');
|
|
||||||
|
|
||||||
interface CanResult {
|
interface CanResult {
|
||||||
role: string;
|
role: string;
|
||||||
|
@ -70,6 +70,14 @@ export const number = [
|
|||||||
export const id = [
|
export const id = [
|
||||||
{ label: '{{t("is")}}', value: '$eq', selected: true },
|
{ label: '{{t("is")}}', value: '$eq', selected: true },
|
||||||
{ label: '{{t("is not")}}', value: '$ne' },
|
{ label: '{{t("is not")}}', value: '$ne' },
|
||||||
|
{
|
||||||
|
label: '{{t("is variable")}}',
|
||||||
|
value: '$isVar',
|
||||||
|
schema: {
|
||||||
|
'x-component': 'VariableCascader',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '{{t("is current logged-in user")}}',
|
label: '{{t("is current logged-in user")}}',
|
||||||
value: '$isCurrentUser',
|
value: '$isCurrentUser',
|
||||||
|
@ -1,10 +1,52 @@
|
|||||||
import { createForm, onFieldValueChange } from '@formily/core';
|
import { createForm, onFieldValueChange } from '@formily/core';
|
||||||
import { FieldContext, FormContext } from '@formily/react';
|
import { connect, FieldContext, FormContext } from '@formily/react';
|
||||||
import { merge } from '@formily/shared';
|
import { merge } from '@formily/shared';
|
||||||
|
import { Cascader } from 'antd';
|
||||||
import React, { useContext, useMemo } from 'react';
|
import React, { useContext, useMemo } from 'react';
|
||||||
import { SchemaComponent } from '../../core';
|
import { SchemaComponent } from '../../core';
|
||||||
import { useComponent } from '../../hooks';
|
import { useCompile, useComponent } from '../../hooks';
|
||||||
import { FilterContext } from './context';
|
import { FilterContext } from './context';
|
||||||
|
import { useFilterOptions } from './useFilterActionProps';
|
||||||
|
|
||||||
|
const VariableCascader = connect((props) => {
|
||||||
|
const fields = useFilterOptions('users');
|
||||||
|
const compile = useCompile();
|
||||||
|
const { value, onChange } = props;
|
||||||
|
return (
|
||||||
|
<Cascader
|
||||||
|
value={value ? value.split('.') : []}
|
||||||
|
fieldNames={{
|
||||||
|
label: 'title',
|
||||||
|
value: 'name',
|
||||||
|
children: 'children',
|
||||||
|
}}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange(value ? value.join('.') : null);
|
||||||
|
}}
|
||||||
|
options={compile([
|
||||||
|
{
|
||||||
|
title: '{{t("Current user")}}',
|
||||||
|
name: 'currentUser',
|
||||||
|
children: fields
|
||||||
|
.filter((field) => {
|
||||||
|
if (!field.target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return field.type === 'belongsTo';
|
||||||
|
})
|
||||||
|
.map((field) => {
|
||||||
|
if (field.children) {
|
||||||
|
field.children = field.children.filter((child) => {
|
||||||
|
return !child.target;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return field;
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export const DynamicComponent = (props) => {
|
export const DynamicComponent = (props) => {
|
||||||
const { dynamicComponent } = useContext(FilterContext);
|
const { dynamicComponent } = useContext(FilterContext);
|
||||||
@ -38,6 +80,9 @@ export const DynamicComponent = (props) => {
|
|||||||
'x-validator': undefined,
|
'x-validator': undefined,
|
||||||
'x-decorator': undefined,
|
'x-decorator': undefined,
|
||||||
}}
|
}}
|
||||||
|
components={{
|
||||||
|
VariableCascader,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</FieldContext.Provider>
|
</FieldContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -24,6 +24,8 @@ export const useFilterOptions = (collectionName: string) => {
|
|||||||
const { nested, children, operators } = fieldInterface.filterable;
|
const { nested, children, operators } = fieldInterface.filterable;
|
||||||
const option = {
|
const option = {
|
||||||
name: field.name,
|
name: field.name,
|
||||||
|
type: field.type,
|
||||||
|
target: field.target,
|
||||||
title: field?.uiSchema?.title || field.name,
|
title: field?.uiSchema?.title || field.name,
|
||||||
schema: field?.uiSchema,
|
schema: field?.uiSchema,
|
||||||
operators:
|
operators:
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nocobase/test": "0.7.1-alpha.7",
|
"@nocobase/test": "0.7.1-alpha.7",
|
||||||
"@types/jsonwebtoken": "^8.5.8"
|
"@types/jsonwebtoken": "^8.5.8",
|
||||||
|
"json-templates": "^4.2.0"
|
||||||
},
|
},
|
||||||
"gitHead": "7e9556e489007577fc0ed89063b3a9ce2f9aae53"
|
"gitHead": "7e9556e489007577fc0ed89063b3a9ce2f9aae53"
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ export function parseToken(options?: { plugin: UsersPlugin }) {
|
|||||||
return async function parseToken(ctx: Context, next: Next) {
|
return async function parseToken(ctx: Context, next: Next) {
|
||||||
const user = await findUserByToken(ctx, options.plugin);
|
const user = await findUserByToken(ctx, options.plugin);
|
||||||
if (user) {
|
if (user) {
|
||||||
|
console.log('appends', user.toJSON());
|
||||||
ctx.state.currentUser = user;
|
ctx.state.currentUser = user;
|
||||||
setCurrentRole(ctx);
|
setCurrentRole(ctx);
|
||||||
}
|
}
|
||||||
@ -45,12 +46,18 @@ async function findUserByToken(ctx: Context, plugin: UsersPlugin) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { userId } = await plugin.jwtService.decode(token);
|
const { userId } = await plugin.jwtService.decode(token);
|
||||||
|
const collection = ctx.db.getCollection('users');
|
||||||
|
const appends = ['roles'];
|
||||||
|
for (const [, field] of collection.fields) {
|
||||||
|
if (field.type === 'belongsTo') {
|
||||||
|
appends.push(field.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
return await ctx.db.getRepository('users').findOne({
|
return await ctx.db.getRepository('users').findOne({
|
||||||
|
appends,
|
||||||
filter: {
|
filter: {
|
||||||
id: userId,
|
id: userId,
|
||||||
},
|
},
|
||||||
appends: ['roles'],
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Collection, Op } from '@nocobase/database';
|
import { Collection, Op } from '@nocobase/database';
|
||||||
import { Plugin } from '@nocobase/server';
|
import { Plugin } from '@nocobase/server';
|
||||||
|
import parse from 'json-templates';
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import { namespace } from './';
|
import { namespace } from './';
|
||||||
import * as actions from './actions/users';
|
import * as actions from './actions/users';
|
||||||
@ -35,6 +36,12 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
|
|||||||
[Op.eq]: ctx?.app?.ctx?.state?.currentUser?.id || -1,
|
[Op.eq]: ctx?.app?.ctx?.state?.currentUser?.id || -1,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
$isVar(val, ctx) {
|
||||||
|
const obj = parse({ val: `{{${val}}}` })(JSON.parse(JSON.stringify(ctx?.app?.ctx?.state)));
|
||||||
|
return {
|
||||||
|
[Op.eq]: obj.val,
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
this.db.registerModels({ UserModel });
|
this.db.registerModels({ UserModel });
|
||||||
this.db.on('users.afterCreateWithAssociations', async (model, options) => {
|
this.db.on('users.afterCreateWithAssociations', async (model, options) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user