@gooddata/sdk-ui-catalog 11.46.0-alpha.2 → 11.46.0-alpha.4
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 +112 -0
- 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 +7 -7
- package/esm/parameter/ParameterYamlEditor.js +1 -1
- 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,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;AAM9E,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,2CAyJ3C"}
|
|
@@ -4,6 +4,7 @@ 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";
|
|
7
8
|
import { serializeParameterToYaml } from "./parameterSerialization.js";
|
|
8
9
|
import { validateParameterYaml } from "./parameterValidation.js";
|
|
9
10
|
import { ParameterYamlEditor } from "./ParameterYamlEditor.js";
|
|
@@ -69,8 +70,7 @@ export function ParameterDialog(props) {
|
|
|
69
70
|
await onSubmit(result.parameter);
|
|
70
71
|
}
|
|
71
72
|
catch (error) {
|
|
72
|
-
|
|
73
|
-
setSubmitError(message ?? intl.formatMessage(messages.dialogSubmitError));
|
|
73
|
+
setSubmitError(extractBackendErrorDetail(error) ?? intl.formatMessage(messages.dialogSubmitError));
|
|
74
74
|
}
|
|
75
75
|
finally {
|
|
76
76
|
setIsSubmitting(false);
|
|
@@ -88,12 +88,12 @@ export function ParameterDialog(props) {
|
|
|
88
88
|
}
|
|
89
89
|
onDuplicate(result.parameter);
|
|
90
90
|
}, [intl, onDuplicate, validate]);
|
|
91
|
-
const footerLeftRenderer = useCallback(() => (_jsxs("div", { className: "gd-
|
|
91
|
+
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
92
|
_jsx(UiIcon, { type: "question", size: 14, color: "complementary-6" }), _jsx(FormattedMessage, { id: "analyticsCatalog.parameter.dialog.help" })
|
|
93
93
|
] })), 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-
|
|
94
|
+
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: [
|
|
95
|
+
_jsxs("div", { className: "gd-ascode-dialog-section-header", children: [
|
|
96
96
|
_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-
|
|
97
|
+
] }), _jsx("div", { className: "gd-ascode-dialog-editor", children: _jsx(ParameterYamlEditor, { initialValue: initialYaml, onChange: handleChange, disabled: isSubmitting }) }), validationError || submitError ? (_jsxs("div", { className: "gd-ascode-dialog-error", children: [
|
|
98
|
+
_jsx("span", { className: "gd-ascode-dialog-error-label", children: _jsx(FormattedMessage, { id: "analyticsCatalog.dialog.error.label" }) }), " ", validationError ?? submitError] })) : null] }) }));
|
|
99
99
|
}
|
|
@@ -16,5 +16,5 @@ export function ParameterYamlEditor({ initialValue, onChange, disabled = false }
|
|
|
16
16
|
setValue(nextValue);
|
|
17
17
|
onChange?.(nextValue);
|
|
18
18
|
}, [onChange]);
|
|
19
|
-
return (_jsx(SyntaxHighlightingInput, { className: "gd-
|
|
19
|
+
return (_jsx(SyntaxHighlightingInput, { className: "gd-ascode-dialog-editor-input", value: value, onChange: handleChange, extensions: extensions, onCompletion: parameterSchemaCompletions, disabled: disabled }));
|
|
20
20
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { type IntlShape } from "react-intl";
|
|
2
2
|
/**
|
|
3
3
|
* Creates a CodeMirror linter extension that reports YAML syntax errors
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* This reuses the tree already built by `@codemirror/lang-yaml` for
|
|
7
|
-
* highlighting — no extra parsing or dependencies required.
|
|
4
|
+
* using the parameter-specific syntax error message.
|
|
8
5
|
*/
|
|
9
6
|
export declare function createYamlLinter(intl: IntlShape): import("@codemirror/state").Extension;
|
|
10
7
|
//# sourceMappingURL=yamlLinter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yamlLinter.d.ts","sourceRoot":"","sources":["../../src/parameter/yamlLinter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"yamlLinter.d.ts","sourceRoot":"","sources":["../../src/parameter/yamlLinter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAkB,MAAM,YAAY,CAAC;AAQ5D;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,yCAE/C"}
|
|
@@ -1,34 +1,13 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
|
-
import { syntaxTree } from "@codemirror/language";
|
|
3
|
-
import { linter } from "@codemirror/lint";
|
|
4
2
|
import { defineMessages } from "react-intl";
|
|
3
|
+
import { createYamlSyntaxLinter } from "../utils/yamlSyntaxLinter.js";
|
|
5
4
|
const messages = defineMessages({
|
|
6
5
|
syntaxError: { id: "analyticsCatalog.parameter.validation.syntax" },
|
|
7
6
|
});
|
|
8
7
|
/**
|
|
9
8
|
* Creates a CodeMirror linter extension that reports YAML syntax errors
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* This reuses the tree already built by `@codemirror/lang-yaml` for
|
|
13
|
-
* highlighting — no extra parsing or dependencies required.
|
|
9
|
+
* using the parameter-specific syntax error message.
|
|
14
10
|
*/
|
|
15
11
|
export function createYamlLinter(intl) {
|
|
16
|
-
|
|
17
|
-
return linter((view) => {
|
|
18
|
-
const diagnostics = [];
|
|
19
|
-
const tree = syntaxTree(view.state);
|
|
20
|
-
tree.iterate({
|
|
21
|
-
enter(node) {
|
|
22
|
-
if (node.type.isError) {
|
|
23
|
-
diagnostics.push({
|
|
24
|
-
from: node.from,
|
|
25
|
-
to: Math.max(node.to, node.from + 1),
|
|
26
|
-
severity: "error",
|
|
27
|
-
message,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
return diagnostics;
|
|
33
|
-
});
|
|
12
|
+
return createYamlSyntaxLinter(intl.formatMessage(messages.syntaxError));
|
|
34
13
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the human-readable reason from a backend error, if present.
|
|
3
|
+
*
|
|
4
|
+
* For a generic `UnexpectedResponseError` the meaningful reason lives in Tiger's RFC 7807
|
|
5
|
+
* `responseBody.detail`, while `error.message` carries only the transport-level "Request failed
|
|
6
|
+
* with status code NNN" — so that message is intentionally ignored. Other typed backend errors
|
|
7
|
+
* (e.g. `LimitReached` → "Upgrade your plan to create more objects.") carry a curated, user-facing
|
|
8
|
+
* message, which is preserved. Callers fall back to a localized generic message otherwise.
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractBackendErrorDetail(error: unknown): string | undefined;
|
|
11
|
+
//# sourceMappingURL=backendError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backendError.d.ts","sourceRoot":"","sources":["../../src/utils/backendError.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAS5E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { isAnalyticalBackendError, isUnexpectedResponseError } from "@gooddata/sdk-backend-spi";
|
|
3
|
+
/**
|
|
4
|
+
* Extracts the human-readable reason from a backend error, if present.
|
|
5
|
+
*
|
|
6
|
+
* For a generic `UnexpectedResponseError` the meaningful reason lives in Tiger's RFC 7807
|
|
7
|
+
* `responseBody.detail`, while `error.message` carries only the transport-level "Request failed
|
|
8
|
+
* with status code NNN" — so that message is intentionally ignored. Other typed backend errors
|
|
9
|
+
* (e.g. `LimitReached` → "Upgrade your plan to create more objects.") carry a curated, user-facing
|
|
10
|
+
* message, which is preserved. Callers fall back to a localized generic message otherwise.
|
|
11
|
+
*/
|
|
12
|
+
export function extractBackendErrorDetail(error) {
|
|
13
|
+
if (isUnexpectedResponseError(error)) {
|
|
14
|
+
const detail = error.responseBody?.detail;
|
|
15
|
+
return typeof detail === "string" && detail.trim() !== "" ? detail : undefined;
|
|
16
|
+
}
|
|
17
|
+
if (isAnalyticalBackendError(error) && error.message.trim() !== "") {
|
|
18
|
+
return error.message;
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a CodeMirror linter extension that reports YAML syntax errors
|
|
3
|
+
* by walking the parse tree for error nodes.
|
|
4
|
+
*
|
|
5
|
+
* This reuses the tree already built by `@codemirror/lang-yaml` for
|
|
6
|
+
* highlighting — no extra parsing or dependencies required.
|
|
7
|
+
*
|
|
8
|
+
* @param message - localized message shown on each syntax error diagnostic
|
|
9
|
+
*/
|
|
10
|
+
export declare function createYamlSyntaxLinter(message: string): import("@codemirror/state").Extension;
|
|
11
|
+
//# sourceMappingURL=yamlSyntaxLinter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yamlSyntaxLinter.d.ts","sourceRoot":"","sources":["../../src/utils/yamlSyntaxLinter.ts"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,yCAoBrD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { syntaxTree } from "@codemirror/language";
|
|
3
|
+
import { linter } from "@codemirror/lint";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a CodeMirror linter extension that reports YAML syntax errors
|
|
6
|
+
* by walking the parse tree for error nodes.
|
|
7
|
+
*
|
|
8
|
+
* This reuses the tree already built by `@codemirror/lang-yaml` for
|
|
9
|
+
* highlighting — no extra parsing or dependencies required.
|
|
10
|
+
*
|
|
11
|
+
* @param message - localized message shown on each syntax error diagnostic
|
|
12
|
+
*/
|
|
13
|
+
export function createYamlSyntaxLinter(message) {
|
|
14
|
+
return linter((view) => {
|
|
15
|
+
const diagnostics = [];
|
|
16
|
+
const tree = syntaxTree(view.state);
|
|
17
|
+
tree.iterate({
|
|
18
|
+
enter(node) {
|
|
19
|
+
if (node.type.isError) {
|
|
20
|
+
diagnostics.push({
|
|
21
|
+
from: node.from,
|
|
22
|
+
to: Math.max(node.to, node.from + 1),
|
|
23
|
+
severity: "error",
|
|
24
|
+
message,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
return diagnostics;
|
|
30
|
+
});
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-catalog",
|
|
3
|
-
"version": "11.46.0-alpha.
|
|
3
|
+
"version": "11.46.0-alpha.4",
|
|
4
4
|
"description": "GoodData SDK - Analytics Catalog",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -45,14 +45,15 @@
|
|
|
45
45
|
"tslib": "2.8.1",
|
|
46
46
|
"yaml": "2.8.3",
|
|
47
47
|
"zod": "4.3.6",
|
|
48
|
-
"@gooddata/sdk-backend-spi": "11.46.0-alpha.
|
|
49
|
-
"@gooddata/sdk-
|
|
50
|
-
"@gooddata/sdk-ui": "11.46.0-alpha.
|
|
51
|
-
"@gooddata/sdk-
|
|
52
|
-
"@gooddata/sdk-ui-ext": "11.46.0-alpha.
|
|
53
|
-
"@gooddata/sdk-ui-
|
|
54
|
-
"@gooddata/sdk-ui-
|
|
55
|
-
"@gooddata/
|
|
48
|
+
"@gooddata/sdk-backend-spi": "11.46.0-alpha.4",
|
|
49
|
+
"@gooddata/sdk-code-schemas": "11.46.0-alpha.4",
|
|
50
|
+
"@gooddata/sdk-ui": "11.46.0-alpha.4",
|
|
51
|
+
"@gooddata/sdk-model": "11.46.0-alpha.4",
|
|
52
|
+
"@gooddata/sdk-ui-ext": "11.46.0-alpha.4",
|
|
53
|
+
"@gooddata/sdk-ui-kit": "11.46.0-alpha.4",
|
|
54
|
+
"@gooddata/sdk-ui-semantic-search": "11.46.0-alpha.4",
|
|
55
|
+
"@gooddata/sdk-ui-theme-provider": "11.46.0-alpha.4",
|
|
56
|
+
"@gooddata/util": "11.46.0-alpha.4"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -92,11 +93,11 @@
|
|
|
92
93
|
"typescript": "5.9.3",
|
|
93
94
|
"vitest": "4.1.8",
|
|
94
95
|
"vitest-dom": "0.1.1",
|
|
95
|
-
"@gooddata/
|
|
96
|
-
"@gooddata/i18n-toolkit": "11.46.0-alpha.
|
|
97
|
-
"@gooddata/
|
|
98
|
-
"@gooddata/
|
|
99
|
-
"@gooddata/stylelint-config": "11.46.0-alpha.
|
|
96
|
+
"@gooddata/oxlint-config": "11.46.0-alpha.4",
|
|
97
|
+
"@gooddata/i18n-toolkit": "11.46.0-alpha.4",
|
|
98
|
+
"@gooddata/eslint-config": "11.46.0-alpha.4",
|
|
99
|
+
"@gooddata/sdk-backend-mockingbird": "11.46.0-alpha.4",
|
|
100
|
+
"@gooddata/stylelint-config": "11.46.0-alpha.4"
|
|
100
101
|
},
|
|
101
102
|
"peerDependencies": {
|
|
102
103
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
.gd-
|
|
1
|
+
.gd-ascode-dialog {
|
|
2
2
|
width: 640px;
|
|
3
3
|
height: 560px;
|
|
4
4
|
flex-direction: column;
|
|
5
5
|
display: flex;
|
|
6
6
|
overflow: hidden;
|
|
7
7
|
}
|
|
8
|
-
.gd-
|
|
8
|
+
.gd-ascode-dialog.overlay.gd-dialog:not(.gd-dropdown) {
|
|
9
9
|
max-width: calc(100vw - 40px);
|
|
10
10
|
padding: 0;
|
|
11
11
|
}
|
|
12
|
-
.gd-
|
|
12
|
+
.gd-ascode-dialog .gd-dialog-header-wrapper {
|
|
13
13
|
padding: 20px 20px 0;
|
|
14
14
|
}
|
|
15
|
-
.gd-
|
|
15
|
+
.gd-ascode-dialog .gd-dialog-content {
|
|
16
16
|
flex: auto;
|
|
17
17
|
padding: 0;
|
|
18
18
|
overflow: hidden;
|
|
19
19
|
}
|
|
20
|
-
.gd-
|
|
20
|
+
.gd-ascode-dialog .gd-dialog-footer {
|
|
21
21
|
display: flex;
|
|
22
22
|
align-items: center;
|
|
23
23
|
margin-top: 0;
|
|
@@ -25,15 +25,23 @@
|
|
|
25
25
|
border-top: 1px solid var(--gd-palette-complementary-3);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
.gd-
|
|
28
|
+
.gd-ascode-dialog-content {
|
|
29
29
|
display: grid;
|
|
30
30
|
grid-template-rows: auto 1fr;
|
|
31
31
|
height: 100%;
|
|
32
|
-
background-color: #fcfcfd;
|
|
32
|
+
background-color: var(--gd-palette-complementary-0-from-theme, #fcfcfd);
|
|
33
33
|
border-top: 1px solid var(--gd-palette-complementary-3);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
.gd-
|
|
36
|
+
.gd-ascode-dialog-loading {
|
|
37
|
+
grid-row: 1/-1;
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
height: 100%;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.gd-ascode-dialog-section-header {
|
|
37
45
|
display: flex;
|
|
38
46
|
align-items: center;
|
|
39
47
|
gap: 5px;
|
|
@@ -45,38 +53,38 @@
|
|
|
45
53
|
color: var(--gd-palette-complementary-6);
|
|
46
54
|
}
|
|
47
55
|
|
|
48
|
-
.gd-
|
|
56
|
+
.gd-ascode-dialog-editor {
|
|
49
57
|
height: 100%;
|
|
50
58
|
overflow: hidden;
|
|
51
59
|
padding: 10px 20px 20px;
|
|
52
60
|
}
|
|
53
|
-
.gd-
|
|
61
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input {
|
|
54
62
|
height: 100%;
|
|
55
63
|
font-family: "Andale Mono", monospace;
|
|
56
64
|
font-size: 14px;
|
|
57
65
|
line-height: 22px;
|
|
58
66
|
}
|
|
59
|
-
.gd-
|
|
67
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input .cm-editor {
|
|
60
68
|
height: 100%;
|
|
61
69
|
border-color: transparent;
|
|
62
70
|
background-color: transparent;
|
|
63
71
|
box-shadow: none;
|
|
64
72
|
transition: none;
|
|
65
73
|
}
|
|
66
|
-
.gd-
|
|
74
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input .cm-editor.cm-focused {
|
|
67
75
|
border-color: var(--gd-palette-primary-base, #14b2e2);
|
|
68
76
|
}
|
|
69
|
-
.gd-
|
|
77
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input .cm-content {
|
|
70
78
|
font-family: "Andale Mono", monospace;
|
|
71
79
|
}
|
|
72
|
-
.gd-
|
|
80
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input .cm-gutters {
|
|
73
81
|
background-color: transparent;
|
|
74
82
|
border-right: none;
|
|
75
83
|
color: var(--gd-palette-complementary-6);
|
|
76
84
|
padding-right: 10px;
|
|
77
85
|
}
|
|
78
86
|
|
|
79
|
-
.gd-
|
|
87
|
+
.gd-ascode-dialog-error {
|
|
80
88
|
background-color: var(--gd-palette-error-lightest, #fff2f1);
|
|
81
89
|
color: var(--gd-palette-error-base, #e54d42);
|
|
82
90
|
font-size: 14px;
|
|
@@ -85,11 +93,11 @@
|
|
|
85
93
|
margin: 0 20px 10px;
|
|
86
94
|
border-radius: 3px;
|
|
87
95
|
}
|
|
88
|
-
.gd-
|
|
96
|
+
.gd-ascode-dialog-error .gd-ascode-dialog-error-label {
|
|
89
97
|
font-weight: 700;
|
|
90
98
|
}
|
|
91
99
|
|
|
92
|
-
.gd-
|
|
100
|
+
.gd-ascode-dialog-footer-left {
|
|
93
101
|
display: flex;
|
|
94
102
|
align-items: center;
|
|
95
103
|
justify-content: space-between;
|
|
@@ -98,4 +106,4 @@
|
|
|
98
106
|
margin-right: 10px;
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
/*# sourceMappingURL=
|
|
109
|
+
/*# sourceMappingURL=codeDialog.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sourceRoot":"","sources":["../scss/codeDialog.scss","../../node_modules/@gooddata/sdk-ui-kit/styles/scss/variables.scss"],"names":[],"mappings":"AAIA;EACI;EACA;EACA;EACA;EACA;;AAGA;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI,cCpCU;;ADwClB;EACI;;AAGJ;EACI;EACA;EACA;EACA;;;AAKZ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA","file":"codeDialog.css"}
|
package/styles/css/detail.css
CHANGED
|
@@ -14,26 +14,26 @@
|
|
|
14
14
|
--catalog-object-type-icon-color: #f18600;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
.gd-
|
|
17
|
+
.gd-ascode-dialog {
|
|
18
18
|
width: 640px;
|
|
19
19
|
height: 560px;
|
|
20
20
|
flex-direction: column;
|
|
21
21
|
display: flex;
|
|
22
22
|
overflow: hidden;
|
|
23
23
|
}
|
|
24
|
-
.gd-
|
|
24
|
+
.gd-ascode-dialog.overlay.gd-dialog:not(.gd-dropdown) {
|
|
25
25
|
max-width: calc(100vw - 40px);
|
|
26
26
|
padding: 0;
|
|
27
27
|
}
|
|
28
|
-
.gd-
|
|
28
|
+
.gd-ascode-dialog .gd-dialog-header-wrapper {
|
|
29
29
|
padding: 20px 20px 0;
|
|
30
30
|
}
|
|
31
|
-
.gd-
|
|
31
|
+
.gd-ascode-dialog .gd-dialog-content {
|
|
32
32
|
flex: auto;
|
|
33
33
|
padding: 0;
|
|
34
34
|
overflow: hidden;
|
|
35
35
|
}
|
|
36
|
-
.gd-
|
|
36
|
+
.gd-ascode-dialog .gd-dialog-footer {
|
|
37
37
|
display: flex;
|
|
38
38
|
align-items: center;
|
|
39
39
|
margin-top: 0;
|
|
@@ -41,15 +41,23 @@
|
|
|
41
41
|
border-top: 1px solid var(--gd-palette-complementary-3);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
.gd-
|
|
44
|
+
.gd-ascode-dialog-content {
|
|
45
45
|
display: grid;
|
|
46
46
|
grid-template-rows: auto 1fr;
|
|
47
47
|
height: 100%;
|
|
48
|
-
background-color: #fcfcfd;
|
|
48
|
+
background-color: var(--gd-palette-complementary-0-from-theme, #fcfcfd);
|
|
49
49
|
border-top: 1px solid var(--gd-palette-complementary-3);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
.gd-
|
|
52
|
+
.gd-ascode-dialog-loading {
|
|
53
|
+
grid-row: 1/-1;
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
height: 100%;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.gd-ascode-dialog-section-header {
|
|
53
61
|
display: flex;
|
|
54
62
|
align-items: center;
|
|
55
63
|
gap: 5px;
|
|
@@ -61,38 +69,38 @@
|
|
|
61
69
|
color: var(--gd-palette-complementary-6);
|
|
62
70
|
}
|
|
63
71
|
|
|
64
|
-
.gd-
|
|
72
|
+
.gd-ascode-dialog-editor {
|
|
65
73
|
height: 100%;
|
|
66
74
|
overflow: hidden;
|
|
67
75
|
padding: 10px 20px 20px;
|
|
68
76
|
}
|
|
69
|
-
.gd-
|
|
77
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input {
|
|
70
78
|
height: 100%;
|
|
71
79
|
font-family: "Andale Mono", monospace;
|
|
72
80
|
font-size: 14px;
|
|
73
81
|
line-height: 22px;
|
|
74
82
|
}
|
|
75
|
-
.gd-
|
|
83
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input .cm-editor {
|
|
76
84
|
height: 100%;
|
|
77
85
|
border-color: transparent;
|
|
78
86
|
background-color: transparent;
|
|
79
87
|
box-shadow: none;
|
|
80
88
|
transition: none;
|
|
81
89
|
}
|
|
82
|
-
.gd-
|
|
90
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input .cm-editor.cm-focused {
|
|
83
91
|
border-color: var(--gd-palette-primary-base, #14b2e2);
|
|
84
92
|
}
|
|
85
|
-
.gd-
|
|
93
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input .cm-content {
|
|
86
94
|
font-family: "Andale Mono", monospace;
|
|
87
95
|
}
|
|
88
|
-
.gd-
|
|
96
|
+
.gd-ascode-dialog-editor .gd-input-syntax-highlighting-input .cm-gutters {
|
|
89
97
|
background-color: transparent;
|
|
90
98
|
border-right: none;
|
|
91
99
|
color: var(--gd-palette-complementary-6);
|
|
92
100
|
padding-right: 10px;
|
|
93
101
|
}
|
|
94
102
|
|
|
95
|
-
.gd-
|
|
103
|
+
.gd-ascode-dialog-error {
|
|
96
104
|
background-color: var(--gd-palette-error-lightest, #fff2f1);
|
|
97
105
|
color: var(--gd-palette-error-base, #e54d42);
|
|
98
106
|
font-size: 14px;
|
|
@@ -101,11 +109,11 @@
|
|
|
101
109
|
margin: 0 20px 10px;
|
|
102
110
|
border-radius: 3px;
|
|
103
111
|
}
|
|
104
|
-
.gd-
|
|
112
|
+
.gd-ascode-dialog-error .gd-ascode-dialog-error-label {
|
|
105
113
|
font-weight: 700;
|
|
106
114
|
}
|
|
107
115
|
|
|
108
|
-
.gd-
|
|
116
|
+
.gd-ascode-dialog-footer-left {
|
|
109
117
|
display: flex;
|
|
110
118
|
align-items: center;
|
|
111
119
|
justify-content: space-between;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sourceRoot":"","sources":["../scss/objectType.scss","../scss/
|
|
1
|
+
{"version":3,"sourceRoot":"","sources":["../scss/objectType.scss","../scss/codeDialog.scss","../../node_modules/@gooddata/sdk-ui-kit/styles/scss/variables.scss","../scss/detail.scss"],"names":[],"mappings":"AAKI;EAEI;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EAEI;;AAGJ;EACI;;;ACpBR;EACI;EACA;EACA;EACA;EACA;;AAGA;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI,cCpCU;;ADwClB;EACI;;AAGJ;EACI;EACA;EACA;EACA;;;AAKZ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;;;AE1GJ;EACI,aDwFc;ECvFd,WAJgB;EAKhB,OAVI;EAWJ;;AAEA;EANJ;IAOQ;;;AAGJ;EAEI;EACA;;AAGJ;EACI;EACA;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;;AAGA;EACI;EACA;EACA;;AAIJ;EACI;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA,ODzCA;EC0CA,WAtEE;EAuEF,aAtES;EAuET;EACA;;AAEA;EACI;;AAOJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI,OD3EG;;AC8EP;EACI;EACA,OD7EJ;EC8EI;EACA;;AAGJ;EAEI;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI,ODnGJ;ECoGI,aAzHQ;EA0HR,WA3HC;EA4HD;EACA;EACA;;AAGJ;EACI,ODxGJ;ECyGI,WAjIA;EAkIA;EACA;EACA;EACA;EACA;;AAGJ;EACI,ODzHG;;AC4HP;EACI;EACA,OD3HJ;;AC+HJ;EACI;;AAEA;EACI;;AAKZ;EACI;EACA;;AAIR;EACI;EACA;EACA;;AAEA;EACI;;AAKR;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;;AAMR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;;AAEA;EACI;;AAKZ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAIR;EACI;EACA;EACA;EACA,ODhQQ;ECiQR;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAKJ;EACI;;AAGJ;EACI;EACA;;AAKJ;EACI;EACA;;AAGJ;EACI,ODjSW;;ACoSf;EACI;EACA,ODnSI;;ACuSZ;EACI,ODpSQ;ECqSR;EACA;EACA;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,ODvTW;ECwTX;EACA;EACA;EACA;;AAIR;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;;AAEJ;EACI;EACA;;AAEJ;EACI;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAIR;EACI,MD7XS;;AC+Xb;AAAA;EAEI,MDhYQ;;ACkYZ;AAAA;EAEI,MDlYO;;ACoYX;EACI;;AAEJ;EACI;;AAGJ;EACI,QD3XW;;;ACiYnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA,kBD9YS;EC+YT;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAGI;EACI;EACA;;AAIR;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,kBD/bK;ECgcL;EACA;EACA,ODrbI;;ACubJ;EACI;EACA;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI","file":"detail.css"}
|