@gooddata/sdk-ui-catalog 11.46.0-alpha.3 → 11.46.0-alpha.5
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/esm/AnalyticsCatalogDetail.d.ts.map +1 -1
- package/esm/AnalyticsCatalogDetail.js +2 -1
- package/esm/catalog/Catalog.d.ts.map +1 -1
- package/esm/catalog/Catalog.js +5 -2
- package/esm/catalogDetail/CatalogDetailActionBar.d.ts +6 -4
- package/esm/catalogDetail/CatalogDetailActionBar.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailActionBar.js +5 -6
- package/esm/catalogDetail/CatalogDetailActions.d.ts +2 -1
- package/esm/catalogDetail/CatalogDetailActions.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailActions.js +6 -2
- package/esm/catalogDetail/CatalogDetailContent.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailContent.js +3 -1
- package/esm/catalogItem/query.d.ts +7 -2
- package/esm/catalogItem/query.d.ts.map +1 -1
- package/esm/catalogItem/query.js +16 -1
- package/esm/header/CreateObjectButton.d.ts +2 -1
- package/esm/header/CreateObjectButton.d.ts.map +1 -1
- package/esm/header/CreateObjectButton.js +42 -38
- package/esm/localization/bundles/en-US.localization-bundle.d.ts +112 -0
- package/esm/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/en-US.localization-bundle.js +121 -9
- package/esm/main/Main.d.ts.map +1 -1
- package/esm/main/Main.js +2 -3
- package/esm/metric/MetricCreateDialog.d.ts +11 -0
- package/esm/metric/MetricCreateDialog.d.ts.map +1 -0
- package/esm/metric/MetricCreateDialog.js +55 -0
- package/esm/metric/MetricDeleteDialog.d.ts +9 -0
- package/esm/metric/MetricDeleteDialog.d.ts.map +1 -0
- package/esm/metric/MetricDeleteDialog.js +68 -0
- package/esm/metric/MetricDetailActions.d.ts +23 -0
- package/esm/metric/MetricDetailActions.d.ts.map +1 -0
- package/esm/metric/MetricDetailActions.js +101 -0
- package/esm/metric/MetricDialog.d.ts +14 -0
- package/esm/metric/MetricDialog.d.ts.map +1 -0
- package/esm/metric/MetricDialog.js +100 -0
- package/esm/metric/MetricEditDialog.d.ts +11 -0
- package/esm/metric/MetricEditDialog.d.ts.map +1 -0
- package/esm/metric/MetricEditDialog.js +51 -0
- package/esm/metric/MetricMutationContext.d.ts +16 -0
- package/esm/metric/MetricMutationContext.d.ts.map +1 -0
- package/esm/metric/MetricMutationContext.js +32 -0
- package/esm/metric/MetricYamlEditor.d.ts +8 -0
- package/esm/metric/MetricYamlEditor.d.ts.map +1 -0
- package/esm/metric/MetricYamlEditor.js +20 -0
- package/esm/metric/gate.d.ts +9 -0
- package/esm/metric/gate.d.ts.map +1 -0
- package/esm/metric/gate.js +16 -0
- package/esm/metric/metricCompletions.d.ts +7 -0
- package/esm/metric/metricCompletions.d.ts.map +1 -0
- package/esm/metric/metricCompletions.js +59 -0
- package/esm/metric/metricConverter.d.ts +49 -0
- package/esm/metric/metricConverter.d.ts.map +1 -0
- package/esm/metric/metricConverter.js +101 -0
- package/esm/metric/metricCopy.d.ts +4 -0
- package/esm/metric/metricCopy.d.ts.map +1 -0
- package/esm/metric/metricCopy.js +60 -0
- package/esm/metric/metricMutationPort.d.ts +18 -0
- package/esm/metric/metricMutationPort.d.ts.map +1 -0
- package/esm/metric/metricMutationPort.js +39 -0
- package/esm/metric/metricSchema.d.ts +29 -0
- package/esm/metric/metricSchema.d.ts.map +1 -0
- package/esm/metric/metricSchema.js +30 -0
- package/esm/metric/metricSerialization.d.ts +10 -0
- package/esm/metric/metricSerialization.d.ts.map +1 -0
- package/esm/metric/metricSerialization.js +33 -0
- package/esm/metric/metricValidation.d.ts +15 -0
- package/esm/metric/metricValidation.d.ts.map +1 -0
- package/esm/metric/metricValidation.js +47 -0
- package/esm/metric/metricYamlLinter.d.ts +7 -0
- package/esm/metric/metricYamlLinter.d.ts.map +1 -0
- package/esm/metric/metricYamlLinter.js +13 -0
- package/esm/metric/tests/metricMutationPort.test.utils.d.ts +7 -0
- package/esm/metric/tests/metricMutationPort.test.utils.d.ts.map +1 -0
- package/esm/metric/tests/metricMutationPort.test.utils.js +43 -0
- package/esm/parameter/ParameterDialog.d.ts.map +1 -1
- package/esm/parameter/ParameterDialog.js +19 -12
- package/esm/parameter/ParameterYamlEditor.d.ts +3 -1
- package/esm/parameter/ParameterYamlEditor.d.ts.map +1 -1
- package/esm/parameter/ParameterYamlEditor.js +4 -3
- package/esm/parameter/gate.d.ts +5 -0
- package/esm/parameter/gate.d.ts.map +1 -1
- package/esm/parameter/gate.js +8 -0
- package/esm/parameter/parameterCompletions.d.ts +9 -3
- package/esm/parameter/parameterCompletions.d.ts.map +1 -1
- package/esm/parameter/parameterCompletions.js +68 -43
- package/esm/parameter/parameterSchema.d.ts +23 -3
- package/esm/parameter/parameterSchema.d.ts.map +1 -1
- package/esm/parameter/parameterSchema.js +32 -10
- package/esm/parameter/parameterValidation.d.ts +4 -1
- package/esm/parameter/parameterValidation.d.ts.map +1 -1
- package/esm/parameter/parameterValidation.js +22 -9
- package/esm/parameter/yamlLinter.d.ts +1 -4
- package/esm/parameter/yamlLinter.d.ts.map +1 -1
- package/esm/parameter/yamlLinter.js +3 -24
- package/esm/utils/backendError.d.ts +11 -0
- package/esm/utils/backendError.d.ts.map +1 -0
- package/esm/utils/backendError.js +21 -0
- package/esm/utils/yamlSyntaxLinter.d.ts +11 -0
- package/esm/utils/yamlSyntaxLinter.d.ts.map +1 -0
- package/esm/utils/yamlSyntaxLinter.js +31 -0
- package/package.json +15 -14
- package/styles/css/{parameter.css → codeDialog.css} +26 -18
- package/styles/css/codeDialog.css.map +1 -0
- package/styles/css/detail.css +25 -17
- package/styles/css/detail.css.map +1 -1
- package/styles/css/main.css +25 -17
- package/styles/css/main.css.map +1 -1
- package/styles/scss/{parameter.scss → codeDialog.scss} +17 -8
- package/styles/scss/detail.scss +1 -1
- package/styles/css/parameter.css.map +0 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IMeasureMetadataObjectDefinition } from "@gooddata/sdk-model";
|
|
2
|
+
export type MetricValidationResult = {
|
|
3
|
+
isValid: true;
|
|
4
|
+
measure: IMeasureMetadataObjectDefinition;
|
|
5
|
+
} | {
|
|
6
|
+
isValid: false;
|
|
7
|
+
errorCode: MetricValidationErrorCode;
|
|
8
|
+
};
|
|
9
|
+
export type MetricValidationErrorCode = "empty" | "syntax" | "invalidStructure" | "idImmutable" | "missingMaql" | "invalidTags";
|
|
10
|
+
type ValidateMetricYamlOptions = {
|
|
11
|
+
fixedIdentifier?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function validateMetricYaml(value: string, options?: ValidateMetricYamlOptions): MetricValidationResult;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=metricValidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metricValidation.d.ts","sourceRoot":"","sources":["../../src/metric/metricValidation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;AAK5E,MAAM,MAAM,sBAAsB,GAC5B;IACI,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,gCAAgC,CAAC;CAC7C,GACD;IACI,OAAO,EAAE,KAAK,CAAC;IACf,SAAS,EAAE,yBAAyB,CAAC;CACxC,CAAC;AAER,MAAM,MAAM,yBAAyB,GAC/B,OAAO,GACP,QAAQ,GACR,kBAAkB,GAClB,aAAa,GACb,aAAa,GACb,aAAa,CAAC;AAEpB,KAAK,yBAAyB,GAAG;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,yBAA8B,GACxC,sBAAsB,CAyBxB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { parse as parseYaml } from "yaml";
|
|
3
|
+
import { metricYamlToDefinition } from "./metricConverter.js";
|
|
4
|
+
import { metricSchema } from "./metricSchema.js";
|
|
5
|
+
export function validateMetricYaml(value, options = {}) {
|
|
6
|
+
if (value.trim() === "") {
|
|
7
|
+
return invalid("empty");
|
|
8
|
+
}
|
|
9
|
+
let parsed;
|
|
10
|
+
try {
|
|
11
|
+
parsed = parseYaml(value, { strict: true });
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return invalid("syntax");
|
|
15
|
+
}
|
|
16
|
+
const result = metricSchema.safeParse(parsed);
|
|
17
|
+
if (!result.success) {
|
|
18
|
+
return classifySchemaError(result.error, parsed);
|
|
19
|
+
}
|
|
20
|
+
if (options.fixedIdentifier !== undefined && result.data.id !== options.fixedIdentifier) {
|
|
21
|
+
return invalid("idImmutable");
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
isValid: true,
|
|
25
|
+
measure: metricYamlToDefinition(result.data),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function classifySchemaError(error, parsed) {
|
|
29
|
+
const maqlProvided = typeof parsed === "object" && parsed !== null && parsed.maql !== undefined;
|
|
30
|
+
for (const issue of error.issues) {
|
|
31
|
+
const path = issue.path.map(String).join(".");
|
|
32
|
+
if (path === "maql") {
|
|
33
|
+
// A present-but-wrong-typed maql is a structural error, not a missing field.
|
|
34
|
+
return invalid(maqlProvided ? "invalidStructure" : "missingMaql");
|
|
35
|
+
}
|
|
36
|
+
if (path === "tags" || path.startsWith("tags.")) {
|
|
37
|
+
return invalid("invalidTags");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return invalid("invalidStructure");
|
|
41
|
+
}
|
|
42
|
+
function invalid(code) {
|
|
43
|
+
return {
|
|
44
|
+
isValid: false,
|
|
45
|
+
errorCode: code,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type IntlShape } from "react-intl";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a CodeMirror linter extension that reports YAML syntax errors
|
|
4
|
+
* using the metric-specific syntax error message.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createMetricYamlLinter(intl: IntlShape): import("@codemirror/state").Extension;
|
|
7
|
+
//# sourceMappingURL=metricYamlLinter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metricYamlLinter.d.ts","sourceRoot":"","sources":["../../src/metric/metricYamlLinter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAkB,MAAM,YAAY,CAAC;AAQ5D;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,SAAS,yCAErD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { defineMessages } from "react-intl";
|
|
3
|
+
import { createYamlSyntaxLinter } from "../utils/yamlSyntaxLinter.js";
|
|
4
|
+
const messages = defineMessages({
|
|
5
|
+
syntaxError: { id: "analyticsCatalog.metric.validation.syntax" },
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* Creates a CodeMirror linter extension that reports YAML syntax errors
|
|
9
|
+
* using the metric-specific syntax error message.
|
|
10
|
+
*/
|
|
11
|
+
export function createMetricYamlLinter(intl) {
|
|
12
|
+
return createYamlSyntaxLinter(intl.formatMessage(messages.syntaxError));
|
|
13
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { IMetricMutationPort } from "../metricMutationPort.js";
|
|
2
|
+
/**
|
|
3
|
+
* Test utility. Returns a metric mutation port with vi.fn() stubs.
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export declare function createTestMetricMutationPort(overrides?: Partial<IMetricMutationPort>): IMetricMutationPort;
|
|
7
|
+
//# sourceMappingURL=metricMutationPort.test.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metricMutationPort.test.utils.d.ts","sourceRoot":"","sources":["../../../src/metric/tests/metricMutationPort.test.utils.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAiBpE;;;GAGG;AACH,wBAAgB,4BAA4B,CACxC,SAAS,GAAE,OAAO,CAAC,mBAAmB,CAAM,GAC7C,mBAAmB,CAsBrB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { vi } from "vitest";
|
|
3
|
+
const defaultSavedItem = {
|
|
4
|
+
identifier: "test-metric",
|
|
5
|
+
type: "measure",
|
|
6
|
+
title: "Test Metric",
|
|
7
|
+
description: "",
|
|
8
|
+
tags: [],
|
|
9
|
+
createdBy: "test",
|
|
10
|
+
updatedBy: "test",
|
|
11
|
+
createdAt: null,
|
|
12
|
+
updatedAt: null,
|
|
13
|
+
isLocked: false,
|
|
14
|
+
isEditable: true,
|
|
15
|
+
format: "#,##0.00",
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Test utility. Returns a metric mutation port with vi.fn() stubs.
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export function createTestMetricMutationPort(overrides = {}) {
|
|
22
|
+
return {
|
|
23
|
+
create: vi.fn().mockResolvedValue(defaultSavedItem),
|
|
24
|
+
update: vi.fn().mockResolvedValue(defaultSavedItem),
|
|
25
|
+
delete: vi.fn().mockResolvedValue(undefined),
|
|
26
|
+
load: vi.fn().mockResolvedValue({
|
|
27
|
+
id: "test-metric",
|
|
28
|
+
uri: "test-metric",
|
|
29
|
+
ref: { identifier: "test-metric", type: "measure" },
|
|
30
|
+
type: "measure",
|
|
31
|
+
title: "Test Metric",
|
|
32
|
+
description: "",
|
|
33
|
+
tags: [],
|
|
34
|
+
production: true,
|
|
35
|
+
deprecated: false,
|
|
36
|
+
unlisted: false,
|
|
37
|
+
expression: "SELECT 1",
|
|
38
|
+
format: "#,##0.00",
|
|
39
|
+
}),
|
|
40
|
+
getReferencingObjects: vi.fn().mockResolvedValue({ insights: [], measures: [] }),
|
|
41
|
+
...overrides,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParameterDialog.d.ts","sourceRoot":"","sources":["../../src/parameter/ParameterDialog.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"ParameterDialog.d.ts","sourceRoot":"","sources":["../../src/parameter/ParameterDialog.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,qBAAqB,CAAC;AAO9E,OAAO,EAAE,KAAK,cAAc,EAA4B,MAAM,6BAA6B,CAAC;AAyB5F,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEpD,KAAK,KAAK,GAAG;IACT,IAAI,EAAE,mBAAmB,CAAC;IAC1B,gBAAgB,CAAC,EAAE,cAAc,CAAC;IAClC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,SAAS,EAAE,kCAAkC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,kCAAkC,KAAK,IAAI,CAAC;CACzE,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,2CAqK3C"}
|
|
@@ -4,6 +4,8 @@ import { useCallback, useRef, useState } from "react";
|
|
|
4
4
|
import { FormattedMessage, defineMessages, useIntl } from "react-intl";
|
|
5
5
|
import { ConfirmDialog, UiButton, UiIcon, UiLink, UiTooltip } from "@gooddata/sdk-ui-kit";
|
|
6
6
|
import { useIsWhiteLabeled } from "../permission/PermissionsContext.js";
|
|
7
|
+
import { extractBackendErrorDetail } from "../utils/backendError.js";
|
|
8
|
+
import { useEnabledParameterTypes } from "./gate.js";
|
|
7
9
|
import { serializeParameterToYaml } from "./parameterSerialization.js";
|
|
8
10
|
import { validateParameterYaml } from "./parameterValidation.js";
|
|
9
11
|
import { ParameterYamlEditor } from "./ParameterYamlEditor.js";
|
|
@@ -41,11 +43,17 @@ export function ParameterDialog(props) {
|
|
|
41
43
|
const submitMessage = intl.formatMessage(isEdit ? messages.dialogEditSubmit : messages.dialogCreateSubmit);
|
|
42
44
|
const cancelMessage = intl.formatMessage(messages.dialogCancel);
|
|
43
45
|
const fixedIdentifier = isEdit ? initialParameter?.id : undefined;
|
|
46
|
+
const enabledTypes = useEnabledParameterTypes();
|
|
44
47
|
const validate = useCallback((value, allowIdChange = false) => {
|
|
45
48
|
return validateParameterYaml(value, {
|
|
49
|
+
enabledTypes,
|
|
46
50
|
fixedIdentifier: isEdit && !allowIdChange ? fixedIdentifier : undefined,
|
|
47
51
|
});
|
|
48
|
-
}, [fixedIdentifier, isEdit]);
|
|
52
|
+
}, [enabledTypes, fixedIdentifier, isEdit]);
|
|
53
|
+
const formatValidationError = useCallback((result) => intl.formatMessage(messages[result.errorCode], {
|
|
54
|
+
type: result.type,
|
|
55
|
+
enabledTypes: intl.formatList(enabledTypes, { type: "conjunction" }),
|
|
56
|
+
}), [enabledTypes, intl]);
|
|
49
57
|
const handleClose = useCallback(() => {
|
|
50
58
|
if (!isSubmitting) {
|
|
51
59
|
onClose();
|
|
@@ -60,7 +68,7 @@ export function ParameterDialog(props) {
|
|
|
60
68
|
const handleSubmit = useCallback(async () => {
|
|
61
69
|
const result = validate(yamlValue.current);
|
|
62
70
|
if (!result.isValid) {
|
|
63
|
-
setValidationError(
|
|
71
|
+
setValidationError(formatValidationError(result));
|
|
64
72
|
return;
|
|
65
73
|
}
|
|
66
74
|
setIsSubmitting(true);
|
|
@@ -69,13 +77,12 @@ export function ParameterDialog(props) {
|
|
|
69
77
|
await onSubmit(result.parameter);
|
|
70
78
|
}
|
|
71
79
|
catch (error) {
|
|
72
|
-
|
|
73
|
-
setSubmitError(message ?? intl.formatMessage(messages.dialogSubmitError));
|
|
80
|
+
setSubmitError(extractBackendErrorDetail(error) ?? intl.formatMessage(messages.dialogSubmitError));
|
|
74
81
|
}
|
|
75
82
|
finally {
|
|
76
83
|
setIsSubmitting(false);
|
|
77
84
|
}
|
|
78
|
-
}, [intl, onSubmit, validate]);
|
|
85
|
+
}, [formatValidationError, intl, onSubmit, validate]);
|
|
79
86
|
const handleDuplicate = useCallback(() => {
|
|
80
87
|
if (!onDuplicate) {
|
|
81
88
|
return;
|
|
@@ -83,17 +90,17 @@ export function ParameterDialog(props) {
|
|
|
83
90
|
setSubmitError(null);
|
|
84
91
|
const result = validate(yamlValue.current, true);
|
|
85
92
|
if (!result.isValid) {
|
|
86
|
-
setValidationError(
|
|
93
|
+
setValidationError(formatValidationError(result));
|
|
87
94
|
return;
|
|
88
95
|
}
|
|
89
96
|
onDuplicate(result.parameter);
|
|
90
|
-
}, [
|
|
91
|
-
const footerLeftRenderer = useCallback(() => (_jsxs("div", { className: "gd-
|
|
97
|
+
}, [formatValidationError, onDuplicate, validate]);
|
|
98
|
+
const footerLeftRenderer = useCallback(() => (_jsxs("div", { className: "gd-ascode-dialog-footer-left", children: [isWhiteLabeled ? null : (_jsxs(UiLink, { variant: "secondary", href: PARAMETER_DOCS_URL, target: "_blank", rel: "noopener noreferrer", children: [
|
|
92
99
|
_jsx(UiIcon, { type: "question", size: 14, color: "complementary-6" }), _jsx(FormattedMessage, { id: "analyticsCatalog.parameter.dialog.help" })
|
|
93
100
|
] })), isEdit && onDuplicate ? (_jsx(UiButton, { label: intl.formatMessage(messages.dialogDuplicate), variant: "tertiary", isDisabled: isSubmitting, onClick: handleDuplicate })) : null] })), [handleDuplicate, intl, isEdit, isSubmitting, isWhiteLabeled, onDuplicate]);
|
|
94
|
-
return (_jsx(ConfirmDialog, { className: "gd-
|
|
95
|
-
_jsxs("div", { className: "gd-
|
|
101
|
+
return (_jsx(ConfirmDialog, { className: "gd-ascode-dialog", containerClassName: "gd-ascode-dialog-overlay", headline: headlineMessage, cancelButtonText: cancelMessage, submitButtonText: submitMessage, isPositive: true, isSubmitDisabled: isSubmitting || (isEdit && !isDirty), isCancelDisabled: isSubmitting, shouldCloseOnEscape: !isSubmitting, onCancel: handleClose, onClose: handleClose, onSubmit: handleSubmit, displayCloseButton: !isSubmitting, footerLeftRenderer: footerLeftRenderer, children: _jsxs("div", { className: "gd-ascode-dialog-content", children: [
|
|
102
|
+
_jsxs("div", { className: "gd-ascode-dialog-section-header", children: [
|
|
96
103
|
_jsx(FormattedMessage, { id: "analyticsCatalog.parameter.dialog.sectionHeader" }), _jsx(UiTooltip, { arrowPlacement: "top", optimalPlacement: true, triggerBy: ["hover", "click", "focus"], anchor: _jsx(UiIcon, { type: "question", size: 14, color: "complementary-6" }), content: _jsx(FormattedMessage, { id: "analyticsCatalog.parameter.dialog.sectionHeader.tooltip" }) })
|
|
97
|
-
] }), _jsx("div", { className: "gd-
|
|
98
|
-
_jsx("span", { className: "gd-
|
|
104
|
+
] }), _jsx("div", { className: "gd-ascode-dialog-editor", children: _jsx(ParameterYamlEditor, { initialValue: initialYaml, enabledTypes: enabledTypes, onChange: handleChange, disabled: isSubmitting }) }), validationError || submitError ? (_jsxs("div", { className: "gd-ascode-dialog-error", children: [
|
|
105
|
+
_jsx("span", { className: "gd-ascode-dialog-error-label", children: _jsx(FormattedMessage, { id: "analyticsCatalog.dialog.error.label" }) }), " ", validationError ?? submitError] })) : null] }) }));
|
|
99
106
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { ParameterType } from "@gooddata/sdk-model";
|
|
1
2
|
type Props = {
|
|
2
3
|
initialValue: string;
|
|
4
|
+
enabledTypes: ParameterType[];
|
|
3
5
|
onChange?: (value: string) => void;
|
|
4
6
|
disabled?: boolean;
|
|
5
7
|
};
|
|
6
|
-
export declare function ParameterYamlEditor({ initialValue, onChange, disabled }: Props): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function ParameterYamlEditor({ initialValue, enabledTypes, onChange, disabled }: Props): import("react/jsx-runtime").JSX.Element;
|
|
7
9
|
export {};
|
|
8
10
|
//# sourceMappingURL=ParameterYamlEditor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParameterYamlEditor.d.ts","sourceRoot":"","sources":["../../src/parameter/ParameterYamlEditor.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ParameterYamlEditor.d.ts","sourceRoot":"","sources":["../../src/parameter/ParameterYamlEditor.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMzD,KAAK,KAAK,GAAG;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,aAAa,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAgB,EAAE,EAAE,KAAK,2CAyBpG"}
|
|
@@ -6,15 +6,16 @@ import { lintGutter } from "@codemirror/lint";
|
|
|
6
6
|
import { lineNumbers } from "@codemirror/view";
|
|
7
7
|
import { useIntl } from "react-intl";
|
|
8
8
|
import { SyntaxHighlightingInput } from "@gooddata/sdk-ui-kit";
|
|
9
|
-
import {
|
|
9
|
+
import { createParameterCompletions } from "./parameterCompletions.js";
|
|
10
10
|
import { createYamlLinter } from "./yamlLinter.js";
|
|
11
|
-
export function ParameterYamlEditor({ initialValue, onChange, disabled = false }) {
|
|
11
|
+
export function ParameterYamlEditor({ initialValue, enabledTypes, onChange, disabled = false }) {
|
|
12
12
|
const intl = useIntl();
|
|
13
13
|
const [value, setValue] = useState(initialValue);
|
|
14
14
|
const extensions = useMemo(() => [yaml(), lineNumbers(), createYamlLinter(intl), lintGutter()], [intl]);
|
|
15
|
+
const completions = useMemo(() => createParameterCompletions(enabledTypes), [enabledTypes]);
|
|
15
16
|
const handleChange = useCallback((nextValue) => {
|
|
16
17
|
setValue(nextValue);
|
|
17
18
|
onChange?.(nextValue);
|
|
18
19
|
}, [onChange]);
|
|
19
|
-
return (_jsx(SyntaxHighlightingInput, { className: "gd-
|
|
20
|
+
return (_jsx(SyntaxHighlightingInput, { className: "gd-ascode-dialog-editor-input", value: value, onChange: handleChange, extensions: extensions, onCompletion: completions, disabled: disabled }));
|
|
20
21
|
}
|
package/esm/parameter/gate.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ParameterType } from "@gooddata/sdk-model";
|
|
1
2
|
/**
|
|
2
3
|
* Catalog parameter feature gate.
|
|
3
4
|
*/
|
|
@@ -6,4 +7,8 @@ export declare function useIsParametersEnabled(): boolean;
|
|
|
6
7
|
* Whether the current user can manage parameters in the catalog.
|
|
7
8
|
*/
|
|
8
9
|
export declare function useCanManageParameter(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Parameter types authorable in the catalog, gated by `enableStringParameters`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useEnabledParameterTypes(): ParameterType[];
|
|
9
14
|
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/parameter/gate.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAI/C"}
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/parameter/gate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAI/C;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,aAAa,EAAE,CAM1D"}
|
package/esm/parameter/gate.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { useMemo } from "react";
|
|
2
3
|
import { useFeatureFlag, useWorkspacePermission } from "../permission/PermissionsContext.js";
|
|
3
4
|
/**
|
|
4
5
|
* Catalog parameter feature gate.
|
|
@@ -14,3 +15,10 @@ export function useCanManageParameter() {
|
|
|
14
15
|
const canManageProject = useWorkspacePermission("canManageProject");
|
|
15
16
|
return isParametersEnabled && canManageProject;
|
|
16
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Parameter types authorable in the catalog, gated by `enableStringParameters`.
|
|
20
|
+
*/
|
|
21
|
+
export function useEnabledParameterTypes() {
|
|
22
|
+
const enableStringParameters = useFeatureFlag("enableStringParameters");
|
|
23
|
+
return useMemo(() => (enableStringParameters ? ["NUMBER", "STRING"] : ["NUMBER"]), [enableStringParameters]);
|
|
24
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { CompletionContext, CompletionResult } from "@codemirror/autocomplete";
|
|
2
|
+
import type { ParameterType } from "@gooddata/sdk-model";
|
|
2
3
|
/**
|
|
3
|
-
* CodeMirror completion source that suggests allowed YAML property
|
|
4
|
-
*
|
|
4
|
+
* Creates a CodeMirror completion source that suggests allowed YAML property
|
|
5
|
+
* names and `type:` values.
|
|
6
|
+
*
|
|
7
|
+
* The parent mapping is derived from the cursor's indentation column. Key
|
|
8
|
+
* suggestions are narrowed to the declared `definition.type` when present
|
|
9
|
+
* (falling back to the union of the enabled types); `type:` value suggestions
|
|
10
|
+
* always offer every enabled type.
|
|
5
11
|
*/
|
|
6
|
-
export declare function
|
|
12
|
+
export declare function createParameterCompletions(enabledTypes: ParameterType[]): (context: CompletionContext) => CompletionResult | null;
|
|
7
13
|
//# sourceMappingURL=parameterCompletions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parameterCompletions.d.ts","sourceRoot":"","sources":["../../src/parameter/parameterCompletions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"parameterCompletions.d.ts","sourceRoot":"","sources":["../../src/parameter/parameterCompletions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGhG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,aAAa,EAAE,2DAuCvE"}
|
|
@@ -1,53 +1,78 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
|
-
import {
|
|
3
|
-
import { PARAMETER_SCHEMA_KEYS } from "./parameterSchema.js";
|
|
4
|
-
/** Pre-built completion options from the schema key map. */
|
|
5
|
-
const completionOptions = Object.fromEntries(Object.entries(PARAMETER_SCHEMA_KEYS).map(([parent, keys]) => [
|
|
6
|
-
parent,
|
|
7
|
-
keys.map((label) => ({ label, type: "property" })),
|
|
8
|
-
]));
|
|
2
|
+
import { parameterSchemaKeys } from "./parameterSchema.js";
|
|
9
3
|
/**
|
|
10
|
-
* CodeMirror completion source that suggests allowed YAML property
|
|
11
|
-
*
|
|
4
|
+
* Creates a CodeMirror completion source that suggests allowed YAML property
|
|
5
|
+
* names and `type:` values.
|
|
6
|
+
*
|
|
7
|
+
* The parent mapping is derived from the cursor's indentation column. Key
|
|
8
|
+
* suggestions are narrowed to the declared `definition.type` when present
|
|
9
|
+
* (falling back to the union of the enabled types); `type:` value suggestions
|
|
10
|
+
* always offer every enabled type.
|
|
12
11
|
*/
|
|
13
|
-
export function
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
12
|
+
export function createParameterCompletions(enabledTypes) {
|
|
13
|
+
const keyOptionsByType = new Map(enabledTypes.map((type) => [type, toOptions(parameterSchemaKeys([type]))]));
|
|
14
|
+
const fallbackKeyOptions = toOptions(parameterSchemaKeys(enabledTypes));
|
|
15
|
+
const typeValueOptions = {
|
|
16
|
+
"": [{ label: "parameter", type: "constant" }],
|
|
17
|
+
definition: enabledTypes.map((label) => ({ label, type: "constant" })),
|
|
18
|
+
};
|
|
19
|
+
return function completeParameter(context) {
|
|
20
|
+
const line = context.state.doc.lineAt(context.pos);
|
|
21
|
+
const before = line.text.slice(0, context.pos - line.from);
|
|
22
|
+
// Trigger on a key name at the start of a line, or on the value of a `type:` key
|
|
23
|
+
const keyMatch = before.match(/^(\s*)(\w*)$/);
|
|
24
|
+
const typeMatch = keyMatch ? null : before.match(/^(\s*)type:\s+(\w*)$/);
|
|
25
|
+
const match = keyMatch ?? typeMatch;
|
|
26
|
+
if (!match) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const indent = match[1].length;
|
|
30
|
+
const word = match[2];
|
|
31
|
+
const parentKey = getParentKey(context.state.doc, line.number, indent);
|
|
32
|
+
if (parentKey === null) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const declaredType = getDeclaredType(context.state.doc);
|
|
36
|
+
const keyOptions = (declaredType ? keyOptionsByType.get(declaredType) : undefined) ?? fallbackKeyOptions;
|
|
37
|
+
const options = (keyMatch ? keyOptions : typeValueOptions)[parentKey];
|
|
38
|
+
if (!options) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return { from: context.pos - word.length, options };
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function toOptions(keyMap) {
|
|
45
|
+
return Object.fromEntries(Object.entries(keyMap).map(([parent, keys]) => [
|
|
46
|
+
parent,
|
|
47
|
+
keys.map((label) => ({ label, type: "property" })),
|
|
48
|
+
]));
|
|
29
49
|
}
|
|
30
50
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
51
|
+
* The key whose block mapping a new entry at column `indent` would join: the
|
|
52
|
+
* nearest less-indented `key:` line above. Returns "" for the top-level
|
|
53
|
+
* mapping and null when the enclosing line is not a mapping key.
|
|
33
54
|
*/
|
|
34
|
-
function getParentKey(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const keyNode = pair.getChild("Key");
|
|
44
|
-
if (keyNode) {
|
|
45
|
-
return state.sliceDoc(keyNode.from, keyNode.to).trim();
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return "";
|
|
55
|
+
function getParentKey(doc, lineNumber, indent) {
|
|
56
|
+
if (indent === 0) {
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
for (let number = lineNumber - 1; number >= 1; number--) {
|
|
60
|
+
const text = doc.line(number).text;
|
|
61
|
+
const content = text.trimStart();
|
|
62
|
+
if (content === "" || content.startsWith("#") || text.length - content.length >= indent) {
|
|
63
|
+
continue;
|
|
49
64
|
}
|
|
50
|
-
|
|
65
|
+
return content.match(/^([\w-]+):/)?.[1] ?? null;
|
|
51
66
|
}
|
|
52
67
|
return "";
|
|
53
68
|
}
|
|
69
|
+
/** Value of the first indented `type:` key, i.e. `definition.type` (the top-level `type` is unindented). */
|
|
70
|
+
function getDeclaredType(doc) {
|
|
71
|
+
for (let number = 1; number <= doc.lines; number++) {
|
|
72
|
+
const match = doc.line(number).text.match(/^\s+type:\s*(\w+)/);
|
|
73
|
+
if (match) {
|
|
74
|
+
return match[1];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
import * as z from "zod/mini";
|
|
2
|
-
|
|
2
|
+
import type { ParameterType } from "@gooddata/sdk-model";
|
|
3
|
+
/** Full-union schema: single source for the editor vocabulary and the exported types, independent of the flag. */
|
|
4
|
+
declare const parameterSchema: z.ZodMiniObject<{
|
|
3
5
|
type: z.ZodMiniDefault<z.ZodMiniLiteral<"parameter">>;
|
|
4
6
|
id: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
5
7
|
title: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
6
8
|
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
7
9
|
tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
8
|
-
definition: z.ZodMiniDiscriminatedUnion<
|
|
10
|
+
definition: z.ZodMiniDiscriminatedUnion<[z.ZodMiniObject<{
|
|
9
11
|
type: z.ZodMiniLiteral<"NUMBER">;
|
|
10
12
|
defaultValue: z.ZodMiniNumber<number>;
|
|
11
13
|
constraints: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
12
14
|
min: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
13
15
|
max: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
14
16
|
}, z.core.$strict>>;
|
|
17
|
+
}, z.core.$strict>, z.ZodMiniObject<{
|
|
18
|
+
type: z.ZodMiniLiteral<"STRING">;
|
|
19
|
+
defaultValue: z.ZodMiniString<string>;
|
|
20
|
+
constraints: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
21
|
+
minLength: z.ZodMiniOptional<z.ZodMiniNumberFormat>;
|
|
22
|
+
maxLength: z.ZodMiniOptional<z.ZodMiniNumberFormat>;
|
|
23
|
+
}, z.core.$strict>>;
|
|
15
24
|
}, z.core.$strict>], "type">;
|
|
16
25
|
}, z.core.$strict>;
|
|
17
26
|
export type ParameterSchemaInput = z.input<typeof parameterSchema>;
|
|
18
27
|
export type ParameterSchema = z.infer<typeof parameterSchema>;
|
|
19
|
-
|
|
28
|
+
/** Parent key → allowed child keys for the schema restricted to `enabledTypes`; powers YAML editor autocompletion. */
|
|
29
|
+
export declare function parameterSchemaKeys(enabledTypes: ParameterType[]): Record<string, string[]>;
|
|
30
|
+
/** Runtime validation schema restricted to the enabled types; the static types stay the full union. */
|
|
31
|
+
export declare function buildParameterSchema(enabledTypes: ParameterType[]): z.ZodMiniObject<{
|
|
32
|
+
type: z.ZodMiniDefault<z.ZodMiniLiteral<"parameter">>;
|
|
33
|
+
id: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
34
|
+
title: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
35
|
+
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
36
|
+
tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
37
|
+
definition: z.ZodMiniDiscriminatedUnion<readonly [z.core.$ZodTypeDiscriminable, ...z.core.$ZodTypeDiscriminable[]], "type">;
|
|
38
|
+
}, z.core.$strict>;
|
|
39
|
+
export {};
|
|
20
40
|
//# sourceMappingURL=parameterSchema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parameterSchema.d.ts","sourceRoot":"","sources":["../../src/parameter/parameterSchema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"parameterSchema.d.ts","sourceRoot":"","sources":["../../src/parameter/parameterSchema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAE9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAoDzD,kHAAkH;AAClH,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;kBAOnB,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACnE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,wHAAsH;AACtH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAE3F;AAED,uGAAuG;AACvG,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,aAAa,EAAE;;;;;;;mBAMjE"}
|
|
@@ -17,9 +17,22 @@ const numberConstraintsSchema = z
|
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const lengthSchema = z.int().check(z.nonnegative());
|
|
21
|
+
const stringConstraintsSchema = z
|
|
22
|
+
.strictObject({
|
|
23
|
+
minLength: z.optional(lengthSchema),
|
|
24
|
+
maxLength: z.optional(lengthSchema),
|
|
25
|
+
})
|
|
26
|
+
.check((ctx) => {
|
|
27
|
+
const { minLength, maxLength } = ctx.value;
|
|
28
|
+
if (minLength !== undefined && maxLength !== undefined && minLength > maxLength) {
|
|
29
|
+
ctx.issues.push({
|
|
30
|
+
code: "custom",
|
|
31
|
+
message: "invalidConstraintRange",
|
|
32
|
+
input: ctx.value,
|
|
33
|
+
path: [],
|
|
34
|
+
});
|
|
35
|
+
}
|
|
23
36
|
});
|
|
24
37
|
/** One arm per model type; `satisfies` breaks the build if the model gains a type without an arm. */
|
|
25
38
|
const definitionSchemas = {
|
|
@@ -34,19 +47,28 @@ const definitionSchemas = {
|
|
|
34
47
|
constraints: z.optional(stringConstraintsSchema),
|
|
35
48
|
}),
|
|
36
49
|
};
|
|
37
|
-
/**
|
|
38
|
-
const
|
|
39
|
-
const definitionSchema = z.discriminatedUnion("type", supportedDefinitionSchemas);
|
|
40
|
-
export const parameterSchema = z.strictObject({
|
|
50
|
+
/** Full-union schema: single source for the editor vocabulary and the exported types, independent of the flag. */
|
|
51
|
+
const parameterSchema = z.strictObject({
|
|
41
52
|
type: z._default(z.literal("parameter"), "parameter"),
|
|
42
53
|
id: z.optional(z.string()),
|
|
43
54
|
title: z.optional(z.string()),
|
|
44
55
|
description: z.optional(z.string()),
|
|
45
56
|
tags: z.optional(z.array(z.string())),
|
|
46
|
-
definition:
|
|
57
|
+
definition: z.discriminatedUnion("type", [definitionSchemas.NUMBER, definitionSchemas.STRING]),
|
|
47
58
|
});
|
|
48
|
-
|
|
49
|
-
|
|
59
|
+
/** Parent key → allowed child keys for the schema restricted to `enabledTypes`; powers YAML editor autocompletion. */
|
|
60
|
+
export function parameterSchemaKeys(enabledTypes) {
|
|
61
|
+
return deriveSchemaKeys(buildParameterSchema(enabledTypes));
|
|
62
|
+
}
|
|
63
|
+
/** Runtime validation schema restricted to the enabled types; the static types stay the full union. */
|
|
64
|
+
export function buildParameterSchema(enabledTypes) {
|
|
65
|
+
// Re-spread to a non-empty tuple: `discriminatedUnion` requires it and it preserves the inferred union.
|
|
66
|
+
const [first, ...rest] = enabledTypes.map((type) => definitionSchemas[type]);
|
|
67
|
+
return z.extend(parameterSchema, {
|
|
68
|
+
definition: z.discriminatedUnion("type", [first, ...rest]),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Map of parent key → allowed child keys. */
|
|
50
72
|
function deriveSchemaKeys(schema, parentKey = "", result = {}) {
|
|
51
73
|
for (const object of objectSchemasOf(schema)) {
|
|
52
74
|
const { shape } = object._zod.def;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ParameterType } from "@gooddata/sdk-model";
|
|
1
2
|
import { type ParameterSchema } from "./parameterSchema.js";
|
|
2
3
|
export type ParameterValidationResult = {
|
|
3
4
|
isValid: true;
|
|
@@ -5,11 +6,13 @@ export type ParameterValidationResult = {
|
|
|
5
6
|
} | {
|
|
6
7
|
isValid: false;
|
|
7
8
|
errorCode: ParameterValidationErrorCode;
|
|
9
|
+
type?: ParameterType;
|
|
8
10
|
};
|
|
9
11
|
export type ParameterValidationErrorCode = "empty" | "syntax" | "invalidStructure" | "idImmutable" | "unsupportedType" | "invalidDefaultValue" | "invalidConstraints" | "invalidConstraintRange" | "invalidTags";
|
|
10
12
|
type ValidateParameterYamlOptions = {
|
|
13
|
+
enabledTypes: ParameterType[];
|
|
11
14
|
fixedIdentifier?: string;
|
|
12
15
|
};
|
|
13
|
-
export declare function validateParameterYaml(value: string, options
|
|
16
|
+
export declare function validateParameterYaml(value: string, options: ValidateParameterYamlOptions): ParameterValidationResult;
|
|
14
17
|
export {};
|
|
15
18
|
//# sourceMappingURL=parameterValidation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parameterValidation.d.ts","sourceRoot":"","sources":["../../src/parameter/parameterValidation.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,eAAe,
|
|
1
|
+
{"version":3,"file":"parameterValidation.d.ts","sourceRoot":"","sources":["../../src/parameter/parameterValidation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAAE,KAAK,eAAe,EAAwB,MAAM,sBAAsB,CAAC;AAElF,MAAM,MAAM,yBAAyB,GAC/B;IACI,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,eAAe,CAAC;CAC9B,GACD;IACI,OAAO,EAAE,KAAK,CAAC;IACf,SAAS,EAAE,4BAA4B,CAAC;IACxC,IAAI,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AAER,MAAM,MAAM,4BAA4B,GAClC,OAAO,GACP,QAAQ,GACR,kBAAkB,GAClB,aAAa,GACb,iBAAiB,GACjB,qBAAqB,GACrB,oBAAoB,GACpB,wBAAwB,GACxB,aAAa,CAAC;AAEpB,KAAK,4BAA4B,GAAG;IAChC,YAAY,EAAE,aAAa,EAAE,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAgB,qBAAqB,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,4BAA4B,GACtC,yBAAyB,CAyB3B"}
|