@qoretechnologies/reqraft 0.10.58 → 0.10.59-pr.130.ga79c828
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
- package/dist/components/form/engine/CompactRow.js +2 -0
- package/dist/components/form/engine/CompactRow.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +11 -5
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/OptionFieldMessages.d.ts +10 -2
- package/dist/components/form/engine/OptionFieldMessages.d.ts.map +1 -1
- package/dist/components/form/engine/OptionFieldMessages.js +21 -4
- package/dist/components/form/engine/OptionFieldMessages.js.map +1 -1
- package/dist/components/form/engine/compactRowContext.d.ts +2 -0
- package/dist/components/form/engine/compactRowContext.d.ts.map +1 -1
- package/dist/components/form/engine/compactRowContext.js.map +1 -1
- package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/index.js +14 -4
- package/dist/components/form/expressions/builder/index.js.map +1 -1
- package/dist/components/smartEditor/useLspAutocomplete.d.ts.map +1 -1
- package/dist/components/smartEditor/useLspAutocomplete.js +60 -38
- package/dist/components/smartEditor/useLspAutocomplete.js.map +1 -1
- package/dist/helpers/allowedValues.d.ts +11 -1
- package/dist/helpers/allowedValues.d.ts.map +1 -1
- package/dist/helpers/allowedValues.js +25 -2
- package/dist/helpers/allowedValues.js.map +1 -1
- package/dist/helpers/expressions.d.ts +10 -1
- package/dist/helpers/expressions.d.ts.map +1 -1
- package/dist/helpers/expressions.js +20 -6
- package/dist/helpers/expressions.js.map +1 -1
- package/package.json +1 -1
- package/src/components/form/engine/CompactRow.tsx +2 -0
- package/src/components/form/engine/FormEngine.stories.tsx +68 -0
- package/src/components/form/engine/FormEngine.tsx +8 -0
- package/src/components/form/engine/OptionFieldMessages.tsx +29 -2
- package/src/components/form/engine/compactRowContext.ts +2 -0
- package/src/components/form/expressions/builder/index.tsx +18 -4
- package/src/components/smartEditor/useLspAutocomplete.ts +71 -44
- package/src/helpers/allowedValues.ts +35 -2
- package/src/helpers/expressions.ts +18 -5
|
@@ -3,9 +3,18 @@ import { IQorusTypeObject } from '../hooks/useQorusTypes';
|
|
|
3
3
|
export declare const getArgumentType: (expressions: IExpressionSchema[], arg?: IExpression, schema?: IExpressionSchemaArg) => string;
|
|
4
4
|
export declare const argumentMatchesType: (expressions: IExpressionSchema[], arg: IExpression | undefined, schema: IExpressionSchemaArg) => boolean;
|
|
5
5
|
export declare const areQorusTypesCompatible: (mainType: string | string[], checkType: string | string[], fallbackTypes?: IQorusTypeObject[]) => boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Whether a type is text, a date or a time: what a condition cannot be. A condition is evaluated by its
|
|
8
|
+
* truthiness, so a number (0 or not), a list or hash (empty or not), binary data and an untyped result
|
|
9
|
+
* all decide it; text, dates and times do not say plainly what is meant, and are compared explicitly
|
|
10
|
+
* instead (`@status == "open"`, `@note != ""`). The Qorus server applies the same rule.
|
|
11
|
+
*/
|
|
12
|
+
export declare const isTextOrDateType: (type: string) => boolean;
|
|
13
|
+
/** Whether a place takes a condition: its result must be true or false (`bool`, or a list of only that). */
|
|
14
|
+
export declare const isConditionType: (returnType: string | string[] | undefined) => boolean;
|
|
6
15
|
/**
|
|
7
16
|
* Whether an operation is offered where its result must be of `returnType`: a condition (`bool`) is
|
|
8
|
-
* built from the operations
|
|
17
|
+
* built from the operations whose result decides it, which is any result but text, a date or a time.
|
|
9
18
|
*
|
|
10
19
|
* Only a condition narrows the list. Any other type keeps every operation: a value of one type is often
|
|
11
20
|
* made from an operation that gives another (text from rich text, a number from an int), and the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expressions.d.ts","sourceRoot":"","sources":["../../src/helpers/expressions.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAoC,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE5F,eAAO,MAAM,eAAe,gBACb,iBAAiB,EAAE,QAC1B,WAAW,WACR,oBAAoB,WAS9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,gBACjB,iBAAiB,EAAE,OAC3B,WAAW,GAAG,SAAS,UACpB,oBAAoB,YAgB7B,CAAC;AAgBF,eAAO,MAAM,uBAAuB,aACxB,MAAM,GAAG,MAAM,EAAE,aAChB,MAAM,GAAG,MAAM,EAAE,kBACZ,gBAAgB,EAAE,KACjC,OAmCF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,eACvB,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,cAC7B;IAAE,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAE,KACvE,
|
|
1
|
+
{"version":3,"file":"expressions.d.ts","sourceRoot":"","sources":["../../src/helpers/expressions.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAoC,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE5F,eAAO,MAAM,eAAe,gBACb,iBAAiB,EAAE,QAC1B,WAAW,WACR,oBAAoB,WAS9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,gBACjB,iBAAiB,EAAE,OAC3B,WAAW,GAAG,SAAS,UACpB,oBAAoB,YAgB7B,CAAC;AAgBF,eAAO,MAAM,uBAAuB,aACxB,MAAM,GAAG,MAAM,EAAE,aAChB,MAAM,GAAG,MAAM,EAAE,kBACZ,gBAAgB,EAAE,KACjC,OAmCF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,SAAU,MAAM,KAAG,OACoC,CAAC;AAErF,4GAA4G;AAC5G,eAAO,MAAM,eAAe,eAAgB,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAAG,OAG3E,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,eACvB,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,cAC7B;IAAE,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAE,KACvE,OASF,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.expressionFitsReturnType = exports.areQorusTypesCompatible = exports.argumentMatchesType = exports.getArgumentType = void 0;
|
|
3
|
+
exports.expressionFitsReturnType = exports.isConditionType = exports.isTextOrDateType = exports.areQorusTypesCompatible = exports.argumentMatchesType = exports.getArgumentType = void 0;
|
|
4
4
|
// Copyright 2026 Qore Technologies, s.r.o.
|
|
5
5
|
// Expression / type-compatibility helpers — ported verbatim from qorus-ide
|
|
6
6
|
// (`src/helpers/expressions.ts` + `areQorusTypesCompatible` from
|
|
@@ -89,9 +89,25 @@ var areQorusTypesCompatible = function (mainType, checkType, fallbackTypes) {
|
|
|
89
89
|
return false;
|
|
90
90
|
};
|
|
91
91
|
exports.areQorusTypesCompatible = areQorusTypesCompatible;
|
|
92
|
+
/**
|
|
93
|
+
* Whether a type is text, a date or a time: what a condition cannot be. A condition is evaluated by its
|
|
94
|
+
* truthiness, so a number (0 or not), a list or hash (empty or not), binary data and an untyped result
|
|
95
|
+
* all decide it; text, dates and times do not say plainly what is meant, and are compared explicitly
|
|
96
|
+
* instead (`@status == "open"`, `@note != ""`). The Qorus server applies the same rule.
|
|
97
|
+
*/
|
|
98
|
+
var isTextOrDateType = function (type) {
|
|
99
|
+
return /^(string|richtext|date|time)$/.test(type.replace(/^\*/, '').replace(/^soft/, ''));
|
|
100
|
+
};
|
|
101
|
+
exports.isTextOrDateType = isTextOrDateType;
|
|
102
|
+
/** Whether a place takes a condition: its result must be true or false (`bool`, or a list of only that). */
|
|
103
|
+
var isConditionType = function (returnType) {
|
|
104
|
+
var types = (0, lodash_1.isArray)(returnType) ? returnType : returnType ? [returnType] : [];
|
|
105
|
+
return types.length > 0 && types.every(function (type) { return /^\*?(bool|boolean)$/.test(type); });
|
|
106
|
+
};
|
|
107
|
+
exports.isConditionType = isConditionType;
|
|
92
108
|
/**
|
|
93
109
|
* Whether an operation is offered where its result must be of `returnType`: a condition (`bool`) is
|
|
94
|
-
* built from the operations
|
|
110
|
+
* built from the operations whose result decides it, which is any result but text, a date or a time.
|
|
95
111
|
*
|
|
96
112
|
* Only a condition narrows the list. Any other type keeps every operation: a value of one type is often
|
|
97
113
|
* made from an operation that gives another (text from rich text, a number from an int), and the
|
|
@@ -99,16 +115,14 @@ exports.areQorusTypesCompatible = areQorusTypesCompatible;
|
|
|
99
115
|
* only once it is built (`any`, or the type of its first argument) is offered everywhere.
|
|
100
116
|
*/
|
|
101
117
|
var expressionFitsReturnType = function (returnType, expression) {
|
|
102
|
-
|
|
103
|
-
var condition = types.length > 0 && types.every(function (type) { return /^\*?(bool|boolean)$/.test(type); });
|
|
104
|
-
if (!condition) {
|
|
118
|
+
if (!(0, exports.isConditionType)(returnType)) {
|
|
105
119
|
return true;
|
|
106
120
|
}
|
|
107
121
|
var result = expression.ui_return_type;
|
|
108
122
|
if (expression.return_type_first_arg || !result || result === 'any' || result === 'auto') {
|
|
109
123
|
return true;
|
|
110
124
|
}
|
|
111
|
-
return
|
|
125
|
+
return !(0, exports.isTextOrDateType)(result);
|
|
112
126
|
};
|
|
113
127
|
exports.expressionFitsReturnType = expressionFitsReturnType;
|
|
114
128
|
//# sourceMappingURL=expressions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expressions.js","sourceRoot":"","sources":["../../src/helpers/expressions.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"expressions.js","sourceRoot":"","sources":["../../src/helpers/expressions.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qoretechnologies/reqraft",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.59-pr.130.ga79c828",
|
|
4
4
|
"description": "ReQraft is a collection of React components and hooks that are used across Qore Technologies' products made using the ReQore component library from Qore.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -278,6 +278,7 @@ export const CompactRow = memo(
|
|
|
278
278
|
(v) => v.removeSelectedOption
|
|
279
279
|
);
|
|
280
280
|
const getTypeForOption = useContextSelector(CompactRowContext, (v) => v.getTypeForOption);
|
|
281
|
+
const isRendererOnly = useContextSelector(CompactRowContext, (v) => v.isRendererOnly);
|
|
281
282
|
const confirmAction = useContextSelector(CompactRowContext, (v) => v.confirmAction);
|
|
282
283
|
const optionActions = useContextSelector(CompactRowContext, (v) => v.optionActions);
|
|
283
284
|
const collapseOptionActions = useContextSelector(
|
|
@@ -1227,6 +1228,7 @@ export const CompactRow = memo(
|
|
|
1227
1228
|
name: optionName,
|
|
1228
1229
|
allOptions: availableOptions,
|
|
1229
1230
|
getType: getTypeForOption,
|
|
1231
|
+
isRendererOnly,
|
|
1230
1232
|
})
|
|
1231
1233
|
// The empty required field's value slot already reads "Required — not
|
|
1232
1234
|
// set", so the plain required message would duplicate it.
|
|
@@ -9213,3 +9213,71 @@ export const CompactReadOnlyDataProvider: Story = {
|
|
|
9213
9213
|
expect(row('name').querySelector('.options-readfirst-structured')).toBeNull();
|
|
9214
9214
|
},
|
|
9215
9215
|
};
|
|
9216
|
+
|
|
9217
|
+
/** The AI endpoint's Tools field as the Qorus IDE hands it to the form: a
|
|
9218
|
+
* `tool-catalog` editor storing tool SELECTORS, with the tool catalogue's
|
|
9219
|
+
* SOURCES (fetched by its `get_message`) hung on `allowed_values`. */
|
|
9220
|
+
const AiEndpointToolsSchema = {
|
|
9221
|
+
tools: {
|
|
9222
|
+
type: 'list',
|
|
9223
|
+
display_name: 'Tools',
|
|
9224
|
+
short_desc: 'Which tools the AI can call during chat',
|
|
9225
|
+
ui_type: 'tool-catalog',
|
|
9226
|
+
element_type: 'string',
|
|
9227
|
+
default_value: { type: 'tool-catalog', value: ['*'] },
|
|
9228
|
+
preselected: true,
|
|
9229
|
+
required: true,
|
|
9230
|
+
get_message: { action: 'creator-get-objects', object_type: 'tool-catalog' },
|
|
9231
|
+
return_message: {
|
|
9232
|
+
action: 'creator-return-objects',
|
|
9233
|
+
object_type: 'tool-catalog',
|
|
9234
|
+
return_value: 'objects',
|
|
9235
|
+
},
|
|
9236
|
+
allowed_values: [
|
|
9237
|
+
{ display_name: 'Qorus system tools', value: { type: 'string', value: 'system' } },
|
|
9238
|
+
{ display_name: 'salesforce-prod', value: { type: 'string', value: 'salesforce-prod' } },
|
|
9239
|
+
],
|
|
9240
|
+
},
|
|
9241
|
+
channel: {
|
|
9242
|
+
type: 'string',
|
|
9243
|
+
display_name: 'Channel',
|
|
9244
|
+
required: true,
|
|
9245
|
+
allowed_values: [
|
|
9246
|
+
{ display_name: 'Ops', value: { type: 'string', value: 'ops' } },
|
|
9247
|
+
{ display_name: 'Dev', value: { type: 'string', value: 'dev' } },
|
|
9248
|
+
],
|
|
9249
|
+
},
|
|
9250
|
+
};
|
|
9251
|
+
|
|
9252
|
+
export const ToolSelectorsAreNotJudgedAsChoices: Story = {
|
|
9253
|
+
parameters: {
|
|
9254
|
+
docs: {
|
|
9255
|
+
description: {
|
|
9256
|
+
story:
|
|
9257
|
+
"An AI endpoint's Tools field holds the server's default, `*` (all tools), and needs no attention: its tool-catalog editor stores selectors, and the catalogue sources listed beside it are not choices the value must be one of. The Channel field below has fixed choices and a value that is none of them, so it alone needs attention.",
|
|
9258
|
+
},
|
|
9259
|
+
},
|
|
9260
|
+
},
|
|
9261
|
+
args: {
|
|
9262
|
+
compact: true,
|
|
9263
|
+
minColumnWidth: '360px',
|
|
9264
|
+
options: AiEndpointToolsSchema as IOptionsSchema,
|
|
9265
|
+
value: {
|
|
9266
|
+
tools: { type: 'tool-catalog', value: ['*'] },
|
|
9267
|
+
channel: { type: 'string', value: 'gone' },
|
|
9268
|
+
},
|
|
9269
|
+
},
|
|
9270
|
+
play: async ({ args }) => {
|
|
9271
|
+
await _testsWaitForText('Tools');
|
|
9272
|
+
// The closed-choice field still flags its value...
|
|
9273
|
+
await _testsWaitForText('"gone" is not one of the choices');
|
|
9274
|
+
// ...and the selector is never reported as a value that is not a choice.
|
|
9275
|
+
await _testsWaitForTextToNotExist('"*" is not one of the choices');
|
|
9276
|
+
await waitFor(() => {
|
|
9277
|
+
const calls = (args.onValidityChange as ReturnType<typeof fn>).mock.calls;
|
|
9278
|
+
expect(calls.length).toBeGreaterThan(0);
|
|
9279
|
+
const [, data] = calls[calls.length - 1] as [boolean, IFormValidityData];
|
|
9280
|
+
expect(data.invalidFields.map((field) => field.fieldName)).toEqual(['channel']);
|
|
9281
|
+
});
|
|
9282
|
+
},
|
|
9283
|
+
};
|
|
@@ -2326,6 +2326,9 @@ const FormEngineImpl = ({
|
|
|
2326
2326
|
// The expression flag lives on the field value, not the schema — so an
|
|
2327
2327
|
// expression value is validated as an expression, not the base type.
|
|
2328
2328
|
isFunction: (availableOptions?.[optionName] as { is_expression?: boolean })?.is_expression,
|
|
2329
|
+
// A field drawn by a bespoke editor (the consumer's own included) is
|
|
2330
|
+
// not judged against `allowed_values` as fixed choices.
|
|
2331
|
+
hasOwnEditor: isRendererOnly(options?.[optionName]?.ui_type as TQorusType),
|
|
2329
2332
|
} as any);
|
|
2330
2333
|
},
|
|
2331
2334
|
[
|
|
@@ -2333,6 +2336,7 @@ const FormEngineImpl = ({
|
|
|
2333
2336
|
JSON.stringify(availableOptions),
|
|
2334
2337
|
JSON.stringify(localValue.fields),
|
|
2335
2338
|
dependencyLockedNames,
|
|
2339
|
+
isRendererOnly,
|
|
2336
2340
|
]
|
|
2337
2341
|
);
|
|
2338
2342
|
|
|
@@ -2377,6 +2381,7 @@ const FormEngineImpl = ({
|
|
|
2377
2381
|
...options?.[optionName],
|
|
2378
2382
|
// The expression flag lives on the field value, not the schema.
|
|
2379
2383
|
isFunction: (option as { is_expression?: boolean }).is_expression,
|
|
2384
|
+
hasOwnEditor: isRendererOnly(options?.[optionName]?.ui_type as TQorusType),
|
|
2380
2385
|
} as any);
|
|
2381
2386
|
}
|
|
2382
2387
|
|
|
@@ -3154,6 +3159,7 @@ const FormEngineImpl = ({
|
|
|
3154
3159
|
name={optionName}
|
|
3155
3160
|
option={{ type: resolvedType, ...other }}
|
|
3156
3161
|
getType={getTypeForOption}
|
|
3162
|
+
isRendererOnly={isRendererOnly}
|
|
3157
3163
|
untouched={!touchedOptionsRef.current.has(optionName)}
|
|
3158
3164
|
/>
|
|
3159
3165
|
{operators && size(operators) && size(other.op) ?
|
|
@@ -3266,6 +3272,7 @@ const FormEngineImpl = ({
|
|
|
3266
3272
|
handleOptionLabelClick,
|
|
3267
3273
|
removeSelectedOption,
|
|
3268
3274
|
getTypeForOption,
|
|
3275
|
+
isRendererOnly,
|
|
3269
3276
|
isOptionValid,
|
|
3270
3277
|
confirmAction,
|
|
3271
3278
|
optionActions,
|
|
@@ -3313,6 +3320,7 @@ const FormEngineImpl = ({
|
|
|
3313
3320
|
handleOptionLabelClick,
|
|
3314
3321
|
removeSelectedOption,
|
|
3315
3322
|
getTypeForOption,
|
|
3323
|
+
isRendererOnly,
|
|
3316
3324
|
isOptionValid,
|
|
3317
3325
|
confirmAction,
|
|
3318
3326
|
optionActions,
|
|
@@ -326,6 +326,14 @@ export interface IOptionFieldMessagesProps {
|
|
|
326
326
|
allOptions?: TQorusForm;
|
|
327
327
|
name: string;
|
|
328
328
|
getType: (type: string) => string;
|
|
329
|
+
/**
|
|
330
|
+
* Whether a `ui_type` names a bespoke editor, the consumer's own included.
|
|
331
|
+
*
|
|
332
|
+
* Such a field's `allowed_values` are not fixed choices (the editor decides
|
|
333
|
+
* what a value means), so a value is not judged against them. Without it only
|
|
334
|
+
* reqraft's built-in editors are known.
|
|
335
|
+
*/
|
|
336
|
+
isRendererOnly?: (type?: any) => boolean;
|
|
329
337
|
/**
|
|
330
338
|
* The reader has not edited this field in this session.
|
|
331
339
|
*
|
|
@@ -354,6 +362,7 @@ export const getOptionFieldMessages = ({
|
|
|
354
362
|
name,
|
|
355
363
|
allOptions,
|
|
356
364
|
getType,
|
|
365
|
+
isRendererOnly,
|
|
357
366
|
untouched,
|
|
358
367
|
}: IOptionFieldMessagesProps): IReqoreTagProps[] => {
|
|
359
368
|
const optionSchema = schema[name];
|
|
@@ -386,6 +395,7 @@ export const getOptionFieldMessages = ({
|
|
|
386
395
|
// config never reached the validator.
|
|
387
396
|
...(optionSchema as object),
|
|
388
397
|
optionSchema: schema,
|
|
398
|
+
hasOwnEditor: !!isRendererOnly?.(optionSchema?.ui_type),
|
|
389
399
|
}
|
|
390
400
|
);
|
|
391
401
|
if (!validationData.isValid) {
|
|
@@ -442,11 +452,28 @@ export const OptionFieldMessages = ({
|
|
|
442
452
|
name,
|
|
443
453
|
allOptions,
|
|
444
454
|
getType,
|
|
455
|
+
isRendererOnly,
|
|
445
456
|
untouched,
|
|
446
457
|
}: IOptionFieldMessagesProps) => {
|
|
447
458
|
const messages: IReqoreTagProps[] = useMemo(
|
|
448
|
-
() =>
|
|
449
|
-
|
|
459
|
+
() =>
|
|
460
|
+
getOptionFieldMessages({
|
|
461
|
+
schema,
|
|
462
|
+
option,
|
|
463
|
+
name,
|
|
464
|
+
allOptions,
|
|
465
|
+
getType,
|
|
466
|
+
isRendererOnly,
|
|
467
|
+
untouched,
|
|
468
|
+
}),
|
|
469
|
+
[
|
|
470
|
+
JSON.stringify(schema),
|
|
471
|
+
JSON.stringify(option),
|
|
472
|
+
JSON.stringify(allOptions),
|
|
473
|
+
name,
|
|
474
|
+
isRendererOnly,
|
|
475
|
+
untouched,
|
|
476
|
+
]
|
|
450
477
|
);
|
|
451
478
|
|
|
452
479
|
if (!size(messages)) {
|
|
@@ -98,6 +98,8 @@ export interface ICompactRowContext {
|
|
|
98
98
|
handleOptionLabelClick: (optionName: string) => void;
|
|
99
99
|
removeSelectedOption: (optionName: string) => void;
|
|
100
100
|
getTypeForOption: (type: string) => string;
|
|
101
|
+
/** Whether a `ui_type` names a bespoke editor, reqraft's or the consumer's own. */
|
|
102
|
+
isRendererOnly?: (type?: any) => boolean;
|
|
101
103
|
isOptionValid: (optionName: string, type: any, optionValue: any) => boolean;
|
|
102
104
|
confirmAction: ReturnType<typeof useReqoreProperty<'confirmAction'>>;
|
|
103
105
|
|
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
areQorusTypesCompatible,
|
|
29
29
|
expressionFitsReturnType,
|
|
30
30
|
getArgumentType,
|
|
31
|
+
isConditionType,
|
|
32
|
+
isTextOrDateType,
|
|
31
33
|
} from '../../../../helpers/expressions';
|
|
32
34
|
import { addMissingExpressionArgs } from '../argumentPresence';
|
|
33
35
|
import { findTemplate } from '../../../../helpers/templates';
|
|
@@ -595,13 +597,18 @@ export const Expression = ({
|
|
|
595
597
|
expressionReturnType === 'any' ||
|
|
596
598
|
areQorusTypesCompatible(returnType, expressionReturnType) ||
|
|
597
599
|
returnType === expressionReturnType ||
|
|
598
|
-
!returnType)
|
|
600
|
+
!returnType) ||
|
|
601
|
+
// a condition is decided by any result but text, a date or a time
|
|
602
|
+
(isConditionType(returnType as string | string[] | undefined) &&
|
|
603
|
+
!!expressionReturnType &&
|
|
604
|
+
!isTextOrDateType(expressionReturnType));
|
|
599
605
|
|
|
600
606
|
const defaultItems = useMemo(
|
|
601
607
|
() =>
|
|
602
608
|
expressions.value
|
|
603
|
-
// a condition (a field or an operand that must be true or false) offers the operations
|
|
604
|
-
//
|
|
609
|
+
// a condition (a field or an operand that must be true or false) offers the operations whose
|
|
610
|
+
// result decides it - any but text, a date or a time, which are compared explicitly; a group's members
|
|
611
|
+
// are its own business, and the operation already chosen
|
|
605
612
|
// stays, so a stored mismatch can be seen and fixed
|
|
606
613
|
.filter(
|
|
607
614
|
(exp) =>
|
|
@@ -1283,7 +1290,14 @@ export const Expression = ({
|
|
|
1283
1290
|
intent='danger'
|
|
1284
1291
|
size='tiny'
|
|
1285
1292
|
wrap
|
|
1286
|
-
label={
|
|
1293
|
+
label={
|
|
1294
|
+
isConditionType(returnType as string | string[] | undefined) &&
|
|
1295
|
+
!!expressionReturnType &&
|
|
1296
|
+
isTextOrDateType(expressionReturnType)
|
|
1297
|
+
? // a condition that gives text, a date or a time: say how to make it one
|
|
1298
|
+
`A condition can't give ${types.getTypeDisplayName(expressionReturnType)}: compare it explicitly, for example @status == "open" or @note != "".`
|
|
1299
|
+
: `This expression returns ${types.getTypeDisplayName(expressionReturnType) || 'nothing'} but the expected return type is ${expectedReturnTypeText}. Please select an expression that returns ${expectedReturnTypeText} or wrap this expression inside another one that does.`
|
|
1300
|
+
}
|
|
1287
1301
|
/>
|
|
1288
1302
|
</>
|
|
1289
1303
|
)}
|
|
@@ -496,43 +496,17 @@ export function useLspAutocomplete(
|
|
|
496
496
|
return () => document.removeEventListener('keydown', handleKeyDown, true);
|
|
497
497
|
}, [isOpen, filteredItems, close, selectItem]);
|
|
498
498
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
// opened it momentarily left the selection null — clicking a
|
|
508
|
-
// void inline can do that.
|
|
509
|
-
if (replacingChipPathRef.current) return;
|
|
510
|
-
close();
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
// `onChange` fires for content edits AND selection-only changes
|
|
514
|
-
// (cursor moves, click-to-focus). Only OPEN on content edits — else
|
|
515
|
-
// clicking after a trigger char (e.g. the space in `/list services `)
|
|
516
|
-
// pops the dropdown without the user typing. An all-`set_selection`
|
|
517
|
-
// op batch is selection-only.
|
|
518
|
-
const isContentChange = editor.operations.some(
|
|
519
|
-
(op) => op.type !== 'set_selection'
|
|
520
|
-
);
|
|
521
|
-
if (!isContentChange) {
|
|
522
|
-
// Replace mode anchors on a chip; the selection echo from the
|
|
523
|
-
// opening click must not close it (outside-click handler does).
|
|
524
|
-
if (isOpen && !replacingChipPathRef.current) {
|
|
525
|
-
close();
|
|
526
|
-
}
|
|
527
|
-
return;
|
|
528
|
-
}
|
|
529
|
-
// A content edit in replace mode means the user typed instead of
|
|
530
|
-
// picking a replacement — fall back to normal flow.
|
|
531
|
-
if (replacingChipPathRef.current) {
|
|
499
|
+
/**
|
|
500
|
+
* Opens, narrows or closes the completions for what the editor holds at its caret, after a content
|
|
501
|
+
* edit: a trigger character just typed, typing inside a sigil token, narrowing an open list, or
|
|
502
|
+
* autosuggest inside a bare identifier.
|
|
503
|
+
*/
|
|
504
|
+
const completeAtCaret = useCallback(
|
|
505
|
+
(editor: BaseEditor & ReactEditor & HistoryEditor, nodes: ISlateElement[]) => {
|
|
506
|
+
if (!editor.selection) {
|
|
532
507
|
close();
|
|
533
508
|
return;
|
|
534
509
|
}
|
|
535
|
-
|
|
536
510
|
const { anchor } = editor.selection;
|
|
537
511
|
const plainText = converter.fromSlateNodes(nodes);
|
|
538
512
|
const cursorOffset = converter.selectionToOffset(
|
|
@@ -604,17 +578,70 @@ export function useLspAutocomplete(
|
|
|
604
578
|
|
|
605
579
|
close();
|
|
606
580
|
},
|
|
607
|
-
[
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
581
|
+
[isOpen, close, findTokenStart, positionTrigger, requestCompletions, triggerCharacters, converter]
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
/* An edit made before the session is ready - typing `$` or `@` while the connection is still being
|
|
585
|
+
made, or its context bound - would otherwise be dropped: the list is closed and nothing asks again,
|
|
586
|
+
so the trigger the author typed never opens anything. The editor is kept, and once the session is
|
|
587
|
+
ready the completions are asked for what it holds then, as for a chip click (see
|
|
588
|
+
`pendingChipRequestRef`). */
|
|
589
|
+
const pendingTypingRef = useRef<(BaseEditor & ReactEditor & HistoryEditor) | null>(null);
|
|
590
|
+
|
|
591
|
+
const onSlateChangeImpl = useCallback(
|
|
592
|
+
(
|
|
593
|
+
editor: BaseEditor & ReactEditor & HistoryEditor,
|
|
594
|
+
nodes: ISlateElement[]
|
|
595
|
+
) => {
|
|
596
|
+
editorRef.current = editor;
|
|
597
|
+
if (!editor.selection || !isReady) {
|
|
598
|
+
// Don't tear down replace mode just because the click that
|
|
599
|
+
// opened it momentarily left the selection null — clicking a
|
|
600
|
+
// void inline can do that.
|
|
601
|
+
if (replacingChipPathRef.current) return;
|
|
602
|
+
// a content edit before the session is ready is answered once it is (see `pendingTypingRef`)
|
|
603
|
+
if (editor.selection && editor.operations.some((op) => op.type !== 'set_selection')) {
|
|
604
|
+
pendingTypingRef.current = editor;
|
|
605
|
+
}
|
|
606
|
+
close();
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
pendingTypingRef.current = null;
|
|
610
|
+
// `onChange` fires for content edits AND selection-only changes
|
|
611
|
+
// (cursor moves, click-to-focus). Only OPEN on content edits — else
|
|
612
|
+
// clicking after a trigger char (e.g. the space in `/list services `)
|
|
613
|
+
// pops the dropdown without the user typing. An all-`set_selection`
|
|
614
|
+
// op batch is selection-only.
|
|
615
|
+
const isContentChange = editor.operations.some(
|
|
616
|
+
(op) => op.type !== 'set_selection'
|
|
617
|
+
);
|
|
618
|
+
if (!isContentChange) {
|
|
619
|
+
// Replace mode anchors on a chip; the selection echo from the
|
|
620
|
+
// opening click must not close it (outside-click handler does).
|
|
621
|
+
if (isOpen && !replacingChipPathRef.current) {
|
|
622
|
+
close();
|
|
623
|
+
}
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
// A content edit in replace mode means the user typed instead of
|
|
627
|
+
// picking a replacement — fall back to normal flow.
|
|
628
|
+
if (replacingChipPathRef.current) {
|
|
629
|
+
close();
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
completeAtCaret(editor, nodes);
|
|
634
|
+
},
|
|
635
|
+
[isReady, isOpen, close, completeAtCaret]
|
|
617
636
|
);
|
|
637
|
+
|
|
638
|
+
// Answer an edit made before the session was ready, for what the editor holds now.
|
|
639
|
+
useEffect(() => {
|
|
640
|
+
const editor = pendingTypingRef.current;
|
|
641
|
+
if (!isReady || !editor) return;
|
|
642
|
+
pendingTypingRef.current = null;
|
|
643
|
+
completeAtCaret(editor, editor.children as ISlateElement[]);
|
|
644
|
+
}, [isReady, completeAtCaret]);
|
|
618
645
|
onSlateChangeImplRef.current = onSlateChangeImpl;
|
|
619
646
|
|
|
620
647
|
const onItemSelect = useCallback(
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { TQorusFormFieldSchema } from '@qoretechnologies/ts-toolkit';
|
|
11
11
|
import isEqual from 'lodash/isEqual';
|
|
12
|
+
import { isRendererOnlyUiType } from '../components/form/engine/rendererTypes';
|
|
12
13
|
import { richtextHasTag, richtextToString } from './common';
|
|
13
14
|
import { getListElementValue } from './options';
|
|
14
15
|
import { isValueTemplate } from './templates';
|
|
@@ -109,8 +110,32 @@ export interface IChoiceFieldSchema {
|
|
|
109
110
|
/** Set when the value is an expression, which is resolved at run time. */
|
|
110
111
|
isFunction?: boolean;
|
|
111
112
|
is_expression?: boolean;
|
|
113
|
+
/** The editor the field is drawn with; see {@link hasOwnEditor}. */
|
|
114
|
+
ui_type?: string | readonly string[];
|
|
115
|
+
/**
|
|
116
|
+
* Set by a form that knows the field is drawn by a bespoke editor of the
|
|
117
|
+
* consumer's own (one it declared in `rendererOnlyUiTypes`), which reqraft's
|
|
118
|
+
* built-in list cannot name.
|
|
119
|
+
*/
|
|
120
|
+
hasOwnEditor?: boolean;
|
|
112
121
|
}
|
|
113
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Does a bespoke editor, rather than reqraft's choice picker, draw this field?
|
|
125
|
+
*
|
|
126
|
+
* Then the editor alone decides what a value means, and `allowed_values` is not
|
|
127
|
+
* a closed set of values the field may hold. The AI endpoint's Tools field is
|
|
128
|
+
* the case that proved it: its `tool-catalog` editor stores SELECTORS -- `*` for
|
|
129
|
+
* every tool, `system:*`, a connection name, `connection/tool` -- and the host
|
|
130
|
+
* hangs the tool catalogue's SOURCES on `allowed_values` for the editor to
|
|
131
|
+
* browse. Judging the selectors against the sources flagged the server's own
|
|
132
|
+
* default, `["*"]`, as "not one of the choices", so no chat endpoint could be
|
|
133
|
+
* published with it. The server says the same: a custom `ui_type` "defines its
|
|
134
|
+
* own value shape".
|
|
135
|
+
*/
|
|
136
|
+
const hasOwnEditor = (field: IChoiceFieldSchema): boolean =>
|
|
137
|
+
!!field.hasOwnEditor || isRendererOnlyUiType(field.ui_type);
|
|
138
|
+
|
|
114
139
|
/**
|
|
115
140
|
* The parts of a stored value that are not among the field's fixed choices.
|
|
116
141
|
*
|
|
@@ -121,14 +146,22 @@ export interface IChoiceFieldSchema {
|
|
|
121
146
|
* all of which are resolved when the interface runs;
|
|
122
147
|
* - `allowed_values: []` — the server has no choices to offer right now, which
|
|
123
148
|
* is "unknown", not "nothing is allowed";
|
|
124
|
-
* - creatable choices, where any value may be added
|
|
149
|
+
* - creatable choices, where any value may be added;
|
|
150
|
+
* - a field drawn by a bespoke editor (a renderer-only `ui_type` such as
|
|
151
|
+
* `tool-catalog`), whose values are whatever that editor says they are.
|
|
125
152
|
*
|
|
126
153
|
* A single-valued field is judged as a whole. A multi-select field, and a list
|
|
127
154
|
* whose elements are constrained by `element_allowed_values`, are judged per
|
|
128
155
|
* element, so the answer names exactly the elements that are not choices.
|
|
129
156
|
*/
|
|
130
157
|
export const getUnlistedChoices = (value: unknown, field?: IChoiceFieldSchema): unknown[] => {
|
|
131
|
-
if (
|
|
158
|
+
if (
|
|
159
|
+
!field ||
|
|
160
|
+
isEmptyChoiceValue(value) ||
|
|
161
|
+
field.isFunction ||
|
|
162
|
+
field.is_expression ||
|
|
163
|
+
hasOwnEditor(field)
|
|
164
|
+
) {
|
|
132
165
|
return [];
|
|
133
166
|
}
|
|
134
167
|
|
|
@@ -101,9 +101,24 @@ export const areQorusTypesCompatible = (
|
|
|
101
101
|
return false;
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Whether a type is text, a date or a time: what a condition cannot be. A condition is evaluated by its
|
|
106
|
+
* truthiness, so a number (0 or not), a list or hash (empty or not), binary data and an untyped result
|
|
107
|
+
* all decide it; text, dates and times do not say plainly what is meant, and are compared explicitly
|
|
108
|
+
* instead (`@status == "open"`, `@note != ""`). The Qorus server applies the same rule.
|
|
109
|
+
*/
|
|
110
|
+
export const isTextOrDateType = (type: string): boolean =>
|
|
111
|
+
/^(string|richtext|date|time)$/.test(type.replace(/^\*/, '').replace(/^soft/, ''));
|
|
112
|
+
|
|
113
|
+
/** Whether a place takes a condition: its result must be true or false (`bool`, or a list of only that). */
|
|
114
|
+
export const isConditionType = (returnType: string | string[] | undefined): boolean => {
|
|
115
|
+
const types = isArray(returnType) ? returnType : returnType ? [returnType] : [];
|
|
116
|
+
return types.length > 0 && types.every((type) => /^\*?(bool|boolean)$/.test(type));
|
|
117
|
+
};
|
|
118
|
+
|
|
104
119
|
/**
|
|
105
120
|
* Whether an operation is offered where its result must be of `returnType`: a condition (`bool`) is
|
|
106
|
-
* built from the operations
|
|
121
|
+
* built from the operations whose result decides it, which is any result but text, a date or a time.
|
|
107
122
|
*
|
|
108
123
|
* Only a condition narrows the list. Any other type keeps every operation: a value of one type is often
|
|
109
124
|
* made from an operation that gives another (text from rich text, a number from an int), and the
|
|
@@ -114,14 +129,12 @@ export const expressionFitsReturnType = (
|
|
|
114
129
|
returnType: string | string[] | undefined,
|
|
115
130
|
expression: { ui_return_type?: string; return_type_first_arg?: boolean }
|
|
116
131
|
): boolean => {
|
|
117
|
-
|
|
118
|
-
const condition = types.length > 0 && types.every((type) => /^\*?(bool|boolean)$/.test(type));
|
|
119
|
-
if (!condition) {
|
|
132
|
+
if (!isConditionType(returnType)) {
|
|
120
133
|
return true;
|
|
121
134
|
}
|
|
122
135
|
const result = expression.ui_return_type;
|
|
123
136
|
if (expression.return_type_first_arg || !result || result === 'any' || result === 'auto') {
|
|
124
137
|
return true;
|
|
125
138
|
}
|
|
126
|
-
return
|
|
139
|
+
return !isTextOrDateType(result);
|
|
127
140
|
};
|