@gooddata/sdk-ui-pluggable-host 11.45.0-alpha.0 → 11.45.0-alpha.2
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/components/HostUiContainer.d.ts.map +1 -1
- package/esm/components/HostUiContainer.js +54 -7
- package/esm/index.d.ts +1 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -0
- package/esm/loader/legacyRedirect.d.ts +17 -0
- package/esm/loader/legacyRedirect.d.ts.map +1 -0
- package/esm/loader/legacyRedirect.js +51 -0
- package/esm/platformContext/backend.d.ts.map +1 -1
- package/esm/platformContext/backend.js +20 -1
- package/esm/registry/pluggableApplicationsRegistry.d.ts.map +1 -1
- package/esm/registry/pluggableApplicationsRegistry.js +14 -1
- package/esm/sdk-ui-pluggable-host.d.ts +18 -0
- package/esm/ui/DefaultHostUi.js +16 -43
- package/esm/ui/GenAIChat.d.ts +18 -1
- package/esm/ui/GenAIChat.d.ts.map +1 -1
- package/esm/ui/GenAIChat.js +69 -97
- package/esm/ui/HostChat.d.ts +64 -0
- package/esm/ui/HostChat.d.ts.map +1 -0
- package/esm/ui/HostChat.js +75 -0
- package/esm/ui/HostChrome.d.ts +12 -24
- package/esm/ui/HostChrome.d.ts.map +1 -1
- package/esm/ui/HostChrome.js +11 -52
- package/esm/ui/PluggableApplicationRenderer.d.ts +24 -2
- package/esm/ui/PluggableApplicationRenderer.d.ts.map +1 -1
- package/esm/ui/PluggableApplicationRenderer.js +31 -13
- package/esm/ui/useHostChromeChat.d.ts +12 -1
- package/esm/ui/useHostChromeChat.d.ts.map +1 -1
- package/esm/ui/useHostChromeChat.js +2 -2
- package/package.json +17 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HostUiContainer.d.ts","sourceRoot":"","sources":["../../src/components/HostUiContainer.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,
|
|
1
|
+
{"version":3,"file":"HostUiContainer.d.ts","sourceRoot":"","sources":["../../src/components/HostUiContainer.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,EAA0B,KAAK,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAEH,KAAK,gBAAgB,EAExB,MAAM,2CAA2C,CAAC;AAiBnD,OAAO,wBAAwB,CAAC;AAEhC,MAAM,WAAW,qBAAqB;IAClC,GAAG,EAAE,gBAAgB,CAAC;IACtB,IAAI,EAAE,gCAAgC,EAAE,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,gBAAgB,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,qBAAqB,2CA8Q7F"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2026 GoodData Corporation
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { createRoot } from "react-dom/client";
|
|
@@ -7,6 +7,7 @@ import { now } from "../debug.js";
|
|
|
7
7
|
import { setActiveHostHandle } from "../lib/hostNotifications.js";
|
|
8
8
|
import { getAppLifecycleCallbacks } from "../loader/pluggableApplicationsLoader.js";
|
|
9
9
|
import { getActiveInternalApplication } from "../loader/routing.js";
|
|
10
|
+
import { HostChat, } from "../ui/HostChat.js";
|
|
10
11
|
import { HostIntlProvider } from "../ui/HostIntlProvider.js";
|
|
11
12
|
import { PluggableApplicationRenderer } from "../ui/PluggableApplicationRenderer.js";
|
|
12
13
|
import { resolveHostUiModule } from "../ui/resolveHostUiModule.js";
|
|
@@ -25,9 +26,35 @@ export function HostUiContainer({ ctx, apps, pathname, routerNavigate }) {
|
|
|
25
26
|
const latestMountStateRef = useAutoupdateRef({ ctx, apps, pathname });
|
|
26
27
|
const [headerOptions, setHeaderOptions] = useState(undefined);
|
|
27
28
|
const [pageTitle, setPageTitle] = useState(undefined);
|
|
28
|
-
// Host-owned chat open-state,
|
|
29
|
+
// Host-owned chat open-state, sourced from HostChat and forwarded to the active pluggable app.
|
|
29
30
|
const [aiAssistantOpen, setAiAssistantOpen] = useState(false);
|
|
30
|
-
|
|
31
|
+
// Header chat-button state (visibility + open) pushed down to the host UI module so it can render
|
|
32
|
+
// the header button to match the host-owned chat.
|
|
33
|
+
const [chatButtonState, setChatButtonState] = useState({ showChatItem: false, isOpen: false });
|
|
34
|
+
const onChatStateChange = useCallback((state) => {
|
|
35
|
+
setChatButtonState((prev) => prev.showChatItem === state.showChatItem && prev.isOpen === state.isOpen ? prev : state);
|
|
36
|
+
}, []);
|
|
37
|
+
// Open/close/toggle requests and tag scope driving the host's single chat (HostChat). Sources:
|
|
38
|
+
// app events (via PluggableApplicationRenderer), the header chat button, and the header search.
|
|
39
|
+
const [aiVisibility, setAiVisibility] = useState(null);
|
|
40
|
+
const [aiContext, setAiContext] = useState(null);
|
|
41
|
+
const aiVisibilitySeqRef = useRef(0);
|
|
42
|
+
const requestOpenAi = useCallback((question, userContext) => {
|
|
43
|
+
setAiVisibility({ kind: "open", question, userContext, seq: ++aiVisibilitySeqRef.current });
|
|
44
|
+
}, []);
|
|
45
|
+
const requestCloseAi = useCallback(() => {
|
|
46
|
+
setAiVisibility({ kind: "close", seq: ++aiVisibilitySeqRef.current });
|
|
47
|
+
}, []);
|
|
48
|
+
const requestToggleAi = useCallback(() => {
|
|
49
|
+
setAiVisibility({ kind: "toggle", seq: ++aiVisibilitySeqRef.current });
|
|
50
|
+
}, []);
|
|
51
|
+
const setAiAssistantContext = useCallback((context) => {
|
|
52
|
+
setAiContext(context);
|
|
53
|
+
}, []);
|
|
54
|
+
// The active app's chat-link handler, populated by PluggableApplicationRenderer (which holds the
|
|
55
|
+
// app mount handle) and read by HostChat's chat so embedded apps can handle link clicks in-app.
|
|
56
|
+
const appAiLinkClickRef = useRef(undefined);
|
|
57
|
+
const onAppLinkClick = useCallback((link) => appAiLinkClickRef.current?.(link) ?? false, []);
|
|
31
58
|
const activeAppRef = useAutoupdateRef(activeInternalApplication);
|
|
32
59
|
const onHeaderChange = useCallback((appId, header) => {
|
|
33
60
|
if (activeAppRef.current?.id === appId) {
|
|
@@ -47,7 +74,12 @@ export function HostUiContainer({ ctx, apps, pathname, routerNavigate }) {
|
|
|
47
74
|
const replace = useCallback((url) => {
|
|
48
75
|
void navigateRef.current(url, { replace: true });
|
|
49
76
|
}, [navigateRef]);
|
|
50
|
-
const navigationMountRef = useAutoupdateRef({
|
|
77
|
+
const navigationMountRef = useAutoupdateRef({
|
|
78
|
+
navigate,
|
|
79
|
+
replace,
|
|
80
|
+
onChatToggleRequested: requestToggleAi,
|
|
81
|
+
onAskAiAssistant: requestOpenAi,
|
|
82
|
+
});
|
|
51
83
|
// Mount the host UI once; obtain the app container for rendering active apps
|
|
52
84
|
useEffect(() => {
|
|
53
85
|
const container = containerRef.current;
|
|
@@ -68,7 +100,8 @@ export function HostUiContainer({ ctx, apps, pathname, routerNavigate }) {
|
|
|
68
100
|
pathname: latestState.pathname,
|
|
69
101
|
navigate: navigationMountRef.current.navigate,
|
|
70
102
|
replace: navigationMountRef.current.replace,
|
|
71
|
-
|
|
103
|
+
onChatToggleRequested: navigationMountRef.current.onChatToggleRequested,
|
|
104
|
+
onAskAiAssistant: navigationMountRef.current.onAskAiAssistant,
|
|
72
105
|
});
|
|
73
106
|
handleRef.current = handle;
|
|
74
107
|
appRootRef.current = createRoot(handle.getAppContainer());
|
|
@@ -127,6 +160,13 @@ export function HostUiContainer({ ctx, apps, pathname, routerNavigate }) {
|
|
|
127
160
|
}
|
|
128
161
|
handleRef.current?.updateDocumentTitle?.(pageTitle);
|
|
129
162
|
}, [hostReady, pageTitle]);
|
|
163
|
+
// Push the host-owned chat button state (visibility + open) to the host UI whenever it changes
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (!hostReady) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
handleRef.current?.updateChatState?.(chatButtonState);
|
|
169
|
+
}, [hostReady, chatButtonState]);
|
|
130
170
|
// Track app navigation and page views when the active application changes.
|
|
131
171
|
// Also clear header options on app switch so stale customizations don't leak.
|
|
132
172
|
const prevAppIdRef = useRef(undefined);
|
|
@@ -141,6 +181,9 @@ export function HostUiContainer({ ctx, apps, pathname, routerNavigate }) {
|
|
|
141
181
|
prevAppIdRef.current = activeId;
|
|
142
182
|
setHeaderOptions(undefined);
|
|
143
183
|
setPageTitle(undefined);
|
|
184
|
+
// Clear the previous app's AI context (tag scope + embedded presentation/placement) so it
|
|
185
|
+
// does not leak into the next app, which may never emit its own aiAssistantContextChanged.
|
|
186
|
+
setAiContext(null);
|
|
144
187
|
}
|
|
145
188
|
}, [activeInternalApplication, pathname]);
|
|
146
189
|
// Render the active pluggable application into the host UI's app container
|
|
@@ -149,7 +192,7 @@ export function HostUiContainer({ ctx, apps, pathname, routerNavigate }) {
|
|
|
149
192
|
return;
|
|
150
193
|
}
|
|
151
194
|
if (activeInternalApplication) {
|
|
152
|
-
appRootRef.current.render(_jsx(HostIntlProvider, { locale: resolveLocale(ctx.preferredLocale), children: _jsx(PluggableApplicationRenderer, { app: activeInternalApplication, ctx: ctx, pathname: pathname, aiAssistantOpen: aiAssistantOpen, onHeaderChange: onHeaderChange, onDocumentTitleChange: onDocumentTitleChange }, activeInternalApplication.id) }));
|
|
195
|
+
appRootRef.current.render(_jsx(HostIntlProvider, { locale: resolveLocale(ctx.preferredLocale), children: _jsx(PluggableApplicationRenderer, { app: activeInternalApplication, ctx: ctx, pathname: pathname, aiAssistantOpen: aiAssistantOpen, onOpenAiAssistant: requestOpenAi, onCloseAiAssistant: requestCloseAi, onAiAssistantContext: setAiAssistantContext, aiLinkClickHandlerRef: appAiLinkClickRef, onHeaderChange: onHeaderChange, onDocumentTitleChange: onDocumentTitleChange }, activeInternalApplication.id) }));
|
|
153
196
|
}
|
|
154
197
|
else {
|
|
155
198
|
appRootRef.current.render(null);
|
|
@@ -162,6 +205,10 @@ export function HostUiContainer({ ctx, apps, pathname, routerNavigate }) {
|
|
|
162
205
|
onDocumentTitleChange,
|
|
163
206
|
pathname,
|
|
164
207
|
aiAssistantOpen,
|
|
208
|
+
requestOpenAi,
|
|
209
|
+
requestCloseAi,
|
|
210
|
+
setAiAssistantContext,
|
|
165
211
|
]);
|
|
166
|
-
return
|
|
212
|
+
return (_jsxs(_Fragment, { children: [
|
|
213
|
+
_jsx("div", { ref: containerRef, className: "gd-host-ui-container" }), hostReady && !ctx.isExportMode ? (_jsx(HostChat, { ctx: ctx, resolvedApplications: apps, pathname: pathname, activeAppId: activeInternalApplication?.id, visibility: aiVisibility, context: aiContext, onOpenChange: setAiAssistantOpen, onChatStateChange: onChatStateChange, onAppLinkClick: onAppLinkClick })) : null] }));
|
|
167
214
|
}
|
package/esm/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { type ILoadPlatformContextCallbacks } from "./platformContext/loadPlatfo
|
|
|
4
4
|
export { registerLocalApplicationLoaders, type LocalPluggableApplicationLoader, } from "./loader/localLoader.js";
|
|
5
5
|
export { registerLocalApplications } from "./registry/pluggableApplicationsRegistry.js";
|
|
6
6
|
export { registerAppLifecycleCallbacks } from "./loader/pluggableApplicationsLoader.js";
|
|
7
|
+
export { mapLegacyUrlToHost, type ILegacyLocation } from "./loader/legacyRedirect.js";
|
|
7
8
|
export { Root, type IRootCallbacks } from "./components/Root.js";
|
|
8
9
|
export { type IAppLifecycleCallbacks } from "./types/lifecycle.js";
|
|
9
10
|
export { STALE_CHUNK_RELOAD_PARAM, installPreloadErrorHandler, installVersionWatcher, reloadForStaleChunks, setStaleChunkReloadListener, type IStaleChunkReloadInfo, type IVersionWatcherOptions, type StaleChunkReloadListener, } from "./lib/chunkReloadGuard.js";
|
package/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,EAAE,gCAAgC,EAAE,MAAM,6CAA6C,CAAC;AAC/F,OAAO,EAAE,KAAK,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AAE9F,OAAO,EACH,+BAA+B,EAC/B,KAAK,+BAA+B,GACvC,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AAExF,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EACH,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,oBAAoB,EACpB,2BAA2B,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,GAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,OAAO,EACH,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GAC1B,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,EAAE,gCAAgC,EAAE,MAAM,6CAA6C,CAAC;AAC/F,OAAO,EAAE,KAAK,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AAE9F,OAAO,EACH,+BAA+B,EAC/B,KAAK,+BAA+B,GACvC,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AAExF,OAAO,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAEtF,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EACH,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,oBAAoB,EACpB,2BAA2B,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,GAChC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,OAAO,EACH,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GAC1B,MAAM,8BAA8B,CAAC"}
|
package/esm/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export { registerPlatformContextCallbacks } from "./platformContext/useLoadPlatf
|
|
|
4
4
|
export { registerLocalApplicationLoaders, } from "./loader/localLoader.js";
|
|
5
5
|
export { registerLocalApplications } from "./registry/pluggableApplicationsRegistry.js";
|
|
6
6
|
export { registerAppLifecycleCallbacks } from "./loader/pluggableApplicationsLoader.js";
|
|
7
|
+
export { mapLegacyUrlToHost } from "./loader/legacyRedirect.js";
|
|
7
8
|
export { Root } from "./components/Root.js";
|
|
8
9
|
export { STALE_CHUNK_RELOAD_PARAM, installPreloadErrorHandler, installVersionWatcher, reloadForStaleChunks, setStaleChunkReloadListener, } from "./lib/chunkReloadGuard.js";
|
|
9
10
|
export { dispatchHostNotification } from "./lib/hostNotifications.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @alpha
|
|
3
|
+
*/
|
|
4
|
+
export interface ILegacyLocation {
|
|
5
|
+
pathname: string;
|
|
6
|
+
hash: string;
|
|
7
|
+
search: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Maps a legacy KD/AD/modeler/metrics URL (embedded or standalone) to its host equivalent, or
|
|
11
|
+
* `null` when it is not a recognized legacy URL. Mirrors the standalone→host redirects that live
|
|
12
|
+
* in the legacy apps; runs client-side because the workspace id is in the (server-invisible) hash.
|
|
13
|
+
*
|
|
14
|
+
* @alpha
|
|
15
|
+
*/
|
|
16
|
+
export declare function mapLegacyUrlToHost(location: ILegacyLocation): string | null;
|
|
17
|
+
//# sourceMappingURL=legacyRedirect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacyRedirect.d.ts","sourceRoot":"","sources":["../../src/loader/legacyRedirect.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAClB;AAoBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CA2C3E"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
function isUnder(pathname, prefix) {
|
|
3
|
+
return pathname === prefix || pathname.startsWith(`${prefix}/`);
|
|
4
|
+
}
|
|
5
|
+
// [/embedded]/workspace/<ws>/<app>/#/<rest> — KD and AD keep their route in the hash; the only
|
|
6
|
+
// embedded difference is the /embedded path prefix.
|
|
7
|
+
function toHashHostUrl(embedded, app, workspaceId, remainder, search) {
|
|
8
|
+
const prefix = embedded ? "/embedded" : "";
|
|
9
|
+
const hash = remainder ? `#${remainder}` : "";
|
|
10
|
+
return `${prefix}/workspace/${workspaceId}/${app}/${search}${hash}`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Maps a legacy KD/AD/modeler/metrics URL (embedded or standalone) to its host equivalent, or
|
|
14
|
+
* `null` when it is not a recognized legacy URL. Mirrors the standalone→host redirects that live
|
|
15
|
+
* in the legacy apps; runs client-side because the workspace id is in the (server-invisible) hash.
|
|
16
|
+
*
|
|
17
|
+
* @alpha
|
|
18
|
+
*/
|
|
19
|
+
export function mapLegacyUrlToHost(location) {
|
|
20
|
+
const { pathname, hash, search } = location;
|
|
21
|
+
// KD legacy hash: #/workspace|project|client/<ws>/<rest>. Lift <ws> to the path, keep <rest>.
|
|
22
|
+
if (isUnder(pathname, "/dashboards")) {
|
|
23
|
+
const match = /^#\/(?:workspace|project|client)\/([^/?]+)(.*)$/.exec(hash);
|
|
24
|
+
return match
|
|
25
|
+
? toHashHostUrl(isUnder(pathname, "/dashboards/embedded"), "dashboards", match[1], match[2], search)
|
|
26
|
+
: null;
|
|
27
|
+
}
|
|
28
|
+
// AD legacy hash: #/<ws>/<rest> — workspace is the bare first segment.
|
|
29
|
+
if (isUnder(pathname, "/analyze")) {
|
|
30
|
+
const match = /^#\/([^/?]+)(.*)$/.exec(hash);
|
|
31
|
+
return match
|
|
32
|
+
? toHashHostUrl(isUnder(pathname, "/analyze/embedded"), "analyze", match[1], match[2], search)
|
|
33
|
+
: null;
|
|
34
|
+
}
|
|
35
|
+
// Metric editor (standalone only): hash #/<ws>[/rest] becomes the path /workspace/<ws>/metrics[/rest].
|
|
36
|
+
if (isUnder(pathname, "/metrics")) {
|
|
37
|
+
const match = /^#\/([^/?]+)(.*)$/.exec(hash);
|
|
38
|
+
return match ? `/workspace/${match[1]}/metrics${match[2]}` : null;
|
|
39
|
+
}
|
|
40
|
+
// LDM modeler (standalone only): #/<ws>[/...] → /workspace/<ws>/modeler. Deep routes have no host
|
|
41
|
+
// equivalent yet; edit-mode intent is preserved as ?displayEditMode.
|
|
42
|
+
if (isUnder(pathname, "/modeler")) {
|
|
43
|
+
const match = /^#\/([^/?]+)/.exec(hash);
|
|
44
|
+
if (!match) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const editMode = /displayEditMode/.test(hash + search) ? "?displayEditMode" : "";
|
|
48
|
+
return `/workspace/${match[1]}/modeler${editMode}`;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/platformContext/backend.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AASlG,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAIlF,MAAM,WAAW,qBAAqB;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,kBAAkB,CAAC;IACrC,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;IAC3C,0BAA0B,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACvE,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,0CAA0C,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtF;
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/platformContext/backend.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AASlG,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAIlF,MAAM,WAAW,qBAAqB;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,kBAAkB,CAAC;IACrC,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;IAC3C,0BAA0B,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACvE,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,0CAA0C,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtF;AAsCD,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,qBAA0B,GAAG,eAAe,CAiGzF;AAYD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAExD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAEjE;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,kBAAkB,CAE/C;AAED,wBAAgB,kBAAkB,IAAI,gBAAgB,CAErD;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAEjF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,0CAA0C,CAAC,EAAE,MAAM,GAAG,IAAI,CAE7F"}
|
|
@@ -5,12 +5,31 @@ import { createNotAuthenticatedHandler } from "./tigerNotAuthenticatedHandler.js
|
|
|
5
5
|
const decorateBackend = (backend) => {
|
|
6
6
|
return withCaching(backend, RecommendedCachingConfiguration);
|
|
7
7
|
};
|
|
8
|
+
const EMBEDDED_PATH_PREFIX = "/embedded/";
|
|
9
|
+
const EXTERNAL_PROVIDER_ID_PARAM = "externalproviderid";
|
|
10
|
+
function readExternalProviderIdFromUrl() {
|
|
11
|
+
if (typeof window === "undefined" || !window.location.pathname.startsWith(EMBEDDED_PATH_PREFIX)) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const fromQuery = (query) => {
|
|
15
|
+
for (const [key, value] of new URLSearchParams(query)) {
|
|
16
|
+
if (key.toLowerCase() === EXTERNAL_PROVIDER_ID_PARAM && value) {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
};
|
|
22
|
+
const hash = window.location.hash;
|
|
23
|
+
const hashQuery = hash.includes("?") ? hash.slice(hash.indexOf("?") + 1) : "";
|
|
24
|
+
return fromQuery(window.location.search.replace(/^\?/, "")) ?? fromQuery(hashQuery);
|
|
25
|
+
}
|
|
8
26
|
function getDefaultAuthCredentials() {
|
|
9
27
|
const apiToken = typeof TIGER_API_TOKEN === "string" && TIGER_API_TOKEN.length ? TIGER_API_TOKEN : undefined;
|
|
10
28
|
if (apiToken) {
|
|
11
29
|
return { type: "apiToken", token: apiToken };
|
|
12
30
|
}
|
|
13
|
-
|
|
31
|
+
const externalProviderId = readExternalProviderIdFromUrl();
|
|
32
|
+
return externalProviderId ? { type: "contextDeferred", externalProviderId } : { type: "contextDeferred" };
|
|
14
33
|
}
|
|
15
34
|
export function createBackendFactory(options = {}) {
|
|
16
35
|
let setApiTokenHandler = undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pluggableApplicationsRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/pluggableApplicationsRegistry.tsx"],"names":[],"mappings":"AAIA,OAAO,EACH,KAAK,gBAAgB,EAKrB,KAAK,kCAAkC,EACvC,KAAK,gCAAgC,EACrC,KAAK,mCAAmC,EAE3C,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEH,KAAK,gBAAgB,EACxB,MAAM,2CAA2C,CAAC;AAMnD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,kCAAkC,GAAG,IAAI,CAE5F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,mCAAmC,GAAG,SAAS,CAaxG;
|
|
1
|
+
{"version":3,"file":"pluggableApplicationsRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/pluggableApplicationsRegistry.tsx"],"names":[],"mappings":"AAIA,OAAO,EACH,KAAK,gBAAgB,EAKrB,KAAK,kCAAkC,EACvC,KAAK,gCAAgC,EACrC,KAAK,mCAAmC,EAE3C,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEH,KAAK,gBAAgB,EACxB,MAAM,2CAA2C,CAAC;AAMnD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,kCAAkC,GAAG,IAAI,CAE5F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,mCAAmC,GAAG,SAAS,CAaxG;AAyND,UAAU,2BAA2B;IACjC;;OAEG;IACH,SAAS,EAAE,gCAAgC,EAAE,CAAC;IAC9C;;OAEG;IACH,cAAc,EAAE,mCAAmC,GAAG,SAAS,CAAC;IAChE;;OAEG;IACH,GAAG,EAAE,gBAAgB,CAAC;IACtB;;OAEG;IACH,KAAK,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,EAChC,SAAS,EACT,cAAc,EACd,GAAG,EACH,KAAK,EACR,EAAE,2BAA2B,GAAG,gCAAgC,EAAE,CAelE;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,gBAAgB,GAAG,gCAAgC,EAAE,CAWlG"}
|
|
@@ -120,8 +120,21 @@ function toPluggableApplicationOrganizationPermissions(permissions) {
|
|
|
120
120
|
hasBaseUiAccess: permissions.hasBaseUiAccess ?? false,
|
|
121
121
|
};
|
|
122
122
|
}
|
|
123
|
+
// Embedded mode forces the shell flags on so each remote becomes eligible and its legacy-external
|
|
124
|
+
// twin (which requires the flag false) drops out — exactly one survives. Non-embedded is untouched.
|
|
125
|
+
function settingsForRequirements(ctx) {
|
|
126
|
+
if (ctx.embeddingMode !== "iframe") {
|
|
127
|
+
return ctx.settings;
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
...ctx.settings,
|
|
131
|
+
enableShellApplication_dashboards: true,
|
|
132
|
+
enableShellApplication_analyticalDesigner: true,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
123
135
|
function appMeetsRequirements({ requiredSettings, requiredWorkspacePermissions, requiredOrganizationPermissions, requiredEntitlements, }, ctx) {
|
|
124
|
-
if (requiredSettings !== undefined &&
|
|
136
|
+
if (requiredSettings !== undefined &&
|
|
137
|
+
!evaluateCondition(requiredSettings, settingsForRequirements(ctx))) {
|
|
125
138
|
return false;
|
|
126
139
|
}
|
|
127
140
|
if (requiredWorkspacePermissions !== undefined) {
|
|
@@ -60,6 +60,15 @@ export declare interface IHostChromePricing {
|
|
|
60
60
|
onUpsellButtonClick: () => void;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* @alpha
|
|
65
|
+
*/
|
|
66
|
+
export declare interface ILegacyLocation {
|
|
67
|
+
pathname: string;
|
|
68
|
+
hash: string;
|
|
69
|
+
search: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
63
72
|
/**
|
|
64
73
|
* @alpha
|
|
65
74
|
*/
|
|
@@ -134,6 +143,15 @@ export declare type LocalPluggableApplicationLoader = () => Promise<{
|
|
|
134
143
|
pluggableApp?: IPluggableApp;
|
|
135
144
|
}>;
|
|
136
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Maps a legacy KD/AD/modeler/metrics URL (embedded or standalone) to its host equivalent, or
|
|
148
|
+
* `null` when it is not a recognized legacy URL. Mirrors the standalone→host redirects that live
|
|
149
|
+
* in the legacy apps; runs client-side because the workspace id is in the (server-invisible) hash.
|
|
150
|
+
*
|
|
151
|
+
* @alpha
|
|
152
|
+
*/
|
|
153
|
+
export declare function mapLegacyUrlToHost(location: ILegacyLocation): string | null;
|
|
154
|
+
|
|
137
155
|
/**
|
|
138
156
|
* Registers app lifecycle callbacks used by the loader (e.g. for preload telemetry).
|
|
139
157
|
* Called by the host or harness at startup.
|
package/esm/ui/DefaultHostUi.js
CHANGED
|
@@ -1,71 +1,38 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2026 GoodData Corporation
|
|
3
|
-
import {
|
|
3
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { flushSync } from "react-dom";
|
|
5
5
|
import { createRoot } from "react-dom/client";
|
|
6
6
|
import { HostChrome } from "./HostChrome.js";
|
|
7
7
|
import { e } from "./hostChromeBem.js";
|
|
8
8
|
import "./DefaultHostUi.scss";
|
|
9
|
-
function HostUiBridge({ initialCtx, initialApps, initialPathname, navigate, replace,
|
|
9
|
+
function HostUiBridge({ initialCtx, initialApps, initialPathname, navigate, replace, onChatToggleRequested, onAskAiAssistant, onAppContainerReady, onReady, }) {
|
|
10
10
|
const [ctx, setCtx] = useState(initialCtx);
|
|
11
11
|
const [apps, setApps] = useState(initialApps);
|
|
12
12
|
const [pathname, setPathname] = useState(initialPathname);
|
|
13
13
|
const [headerOptions, setHeaderOptions] = useState(undefined);
|
|
14
14
|
const [notification, setNotification] = useState(null);
|
|
15
15
|
const [pageTitle, setPageTitle] = useState(undefined);
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
// other (a single shared slot would drop the earlier one — LX-2544).
|
|
20
|
-
const [aiVisibility, setAiVisibility] = useState(null);
|
|
21
|
-
const [aiContext, setAiContext] = useState(null);
|
|
22
|
-
const aiVisibilitySeqRef = useRef(0);
|
|
16
|
+
// The host runtime owns the single chat instance (outside this UI module); it pushes the chat
|
|
17
|
+
// button state here so the header button reflects the chat's availability and open-state.
|
|
18
|
+
const [chatState, setChatState] = useState({ showChatItem: false, isOpen: false });
|
|
23
19
|
const appContainerRef = useRef(null);
|
|
24
|
-
const handleNotify = useCallback((notification) => {
|
|
25
|
-
if (notification === null) {
|
|
26
|
-
setNotification(null);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
switch (notification.type) {
|
|
30
|
-
case "openAiAssistant":
|
|
31
|
-
setAiVisibility({
|
|
32
|
-
kind: "open",
|
|
33
|
-
question: notification.question,
|
|
34
|
-
userContext: notification.userContext,
|
|
35
|
-
// A fresh seq on every request re-triggers the host effect even when the
|
|
36
|
-
// question is identical to the previous one (e.g. "Summarize" clicked again).
|
|
37
|
-
seq: ++aiVisibilitySeqRef.current,
|
|
38
|
-
});
|
|
39
|
-
break;
|
|
40
|
-
case "closeAiAssistant":
|
|
41
|
-
setAiVisibility({ kind: "close", seq: ++aiVisibilitySeqRef.current });
|
|
42
|
-
break;
|
|
43
|
-
case "aiAssistantContext":
|
|
44
|
-
setAiContext({
|
|
45
|
-
includeTags: notification.includeTags,
|
|
46
|
-
excludeTags: notification.excludeTags,
|
|
47
|
-
});
|
|
48
|
-
break;
|
|
49
|
-
default:
|
|
50
|
-
setNotification(notification);
|
|
51
|
-
}
|
|
52
|
-
}, []);
|
|
53
20
|
// Layout effect runs in the same synchronous commit as flushSync.
|
|
54
21
|
useLayoutEffect(() => {
|
|
55
|
-
onReady(setCtx, setApps, setPathname, setHeaderOptions,
|
|
22
|
+
onReady(setCtx, setApps, setPathname, setHeaderOptions, setNotification, setPageTitle, setChatState);
|
|
56
23
|
if (appContainerRef.current) {
|
|
57
24
|
onAppContainerReady(appContainerRef.current);
|
|
58
25
|
}
|
|
59
26
|
// Only call once on mount
|
|
60
27
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
61
28
|
}, []);
|
|
62
|
-
return (_jsx(HostChrome, { ctx: ctx, resolvedApplications: apps, pathname: pathname, onNavigate: navigate, onReplace: replace, headerOptions: headerOptions, notification: notification,
|
|
29
|
+
return (_jsx(HostChrome, { ctx: ctx, resolvedApplications: apps, pathname: pathname, onNavigate: navigate, onReplace: replace, headerOptions: headerOptions, notification: notification, showChatItem: chatState.showChatItem, chatIsOpen: chatState.isOpen, onChatToggle: onChatToggleRequested, onAskAiAssistant: onAskAiAssistant, appPageTitle: pageTitle, children: _jsx("div", { ref: appContainerRef, className: e("app-container") }) }));
|
|
63
30
|
}
|
|
64
31
|
// ---------------------------------------------------------------------------
|
|
65
32
|
// Imperative mount function conforming to IHostUiModule
|
|
66
33
|
// ---------------------------------------------------------------------------
|
|
67
34
|
function mountDefaultHostUi(options) {
|
|
68
|
-
const { container, ctx, resolvedApplications, pathname, navigate, replace,
|
|
35
|
+
const { container, ctx, resolvedApplications, pathname, navigate, replace, onChatToggleRequested, onAskAiAssistant, } = options;
|
|
69
36
|
let reactRoot = createRoot(container);
|
|
70
37
|
let appContainer = null;
|
|
71
38
|
let updateCtxFn = null;
|
|
@@ -74,18 +41,20 @@ function mountDefaultHostUi(options) {
|
|
|
74
41
|
let updateHeaderFn = null;
|
|
75
42
|
let updateNotificationFn = null;
|
|
76
43
|
let updateDocumentTitleFn = null;
|
|
44
|
+
let updateChatStateFn = null;
|
|
77
45
|
// Use flushSync so that the DOM is ready synchronously after mount() returns,
|
|
78
46
|
// making getAppContainer() safe to call immediately.
|
|
79
47
|
flushSync(() => {
|
|
80
|
-
reactRoot?.render(_jsx(HostUiBridge, { initialCtx: ctx, initialApps: resolvedApplications, initialPathname: pathname, navigate: navigate, replace: replace,
|
|
48
|
+
reactRoot?.render(_jsx(HostUiBridge, { initialCtx: ctx, initialApps: resolvedApplications, initialPathname: pathname, navigate: navigate, replace: replace, onChatToggleRequested: onChatToggleRequested, onAskAiAssistant: onAskAiAssistant, onAppContainerReady: (el) => {
|
|
81
49
|
appContainer = el;
|
|
82
|
-
}, onReady: (setCtx, setApps, setPathname, setHeaderOptions, setNotification, setPageTitle) => {
|
|
50
|
+
}, onReady: (setCtx, setApps, setPathname, setHeaderOptions, setNotification, setPageTitle, setChatState) => {
|
|
83
51
|
updateCtxFn = setCtx;
|
|
84
52
|
updateAppsFn = setApps;
|
|
85
53
|
updatePathnameFn = setPathname;
|
|
86
54
|
updateHeaderFn = setHeaderOptions;
|
|
87
55
|
updateNotificationFn = setNotification;
|
|
88
56
|
updateDocumentTitleFn = setPageTitle;
|
|
57
|
+
updateChatStateFn = setChatState;
|
|
89
58
|
} }));
|
|
90
59
|
});
|
|
91
60
|
return {
|
|
@@ -100,6 +69,7 @@ function mountDefaultHostUi(options) {
|
|
|
100
69
|
updateHeaderFn = null;
|
|
101
70
|
updateNotificationFn = null;
|
|
102
71
|
updateDocumentTitleFn = null;
|
|
72
|
+
updateChatStateFn = null;
|
|
103
73
|
root.unmount();
|
|
104
74
|
}
|
|
105
75
|
},
|
|
@@ -118,6 +88,9 @@ function mountDefaultHostUi(options) {
|
|
|
118
88
|
updateDocumentTitle(pageTitle) {
|
|
119
89
|
updateDocumentTitleFn?.(pageTitle);
|
|
120
90
|
},
|
|
91
|
+
updateChatState(state) {
|
|
92
|
+
updateChatStateFn?.(state);
|
|
93
|
+
},
|
|
121
94
|
getAppContainer() {
|
|
122
95
|
if (!appContainer) {
|
|
123
96
|
throw new Error("Host UI app container is not available. " +
|
package/esm/ui/GenAIChat.d.ts
CHANGED
|
@@ -58,7 +58,24 @@ export interface IGenAIChatProps {
|
|
|
58
58
|
canAnalyzeProject?: boolean;
|
|
59
59
|
canFullControl?: boolean;
|
|
60
60
|
settings?: IUserWorkspaceSettings;
|
|
61
|
+
/** Where to place the chat (e.g. an embedded dashboard's left/right `showassistant` param). */
|
|
62
|
+
dialogPosition?: "left" | "right";
|
|
63
|
+
/** Whether the active app is embedded; switches the chat to the embedded presentation. */
|
|
64
|
+
embedded?: boolean;
|
|
65
|
+
/** Delegates a chat link click to the active app; returns true if the app handled it. */
|
|
66
|
+
onAppLinkClick?: (link: {
|
|
67
|
+
type?: string;
|
|
68
|
+
id?: string;
|
|
69
|
+
itemUrl?: string;
|
|
70
|
+
newTab?: boolean;
|
|
71
|
+
}) => boolean;
|
|
61
72
|
onEvent?: (event: GenAIChatEvent) => void;
|
|
62
73
|
}
|
|
63
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Host chrome's chat adapter. The generic chat wiring (object types, the seeded-question dispatch flow,
|
|
76
|
+
* default link handling, event normalization) lives in `GenAIChatDialogConnected`
|
|
77
|
+
* (`@gooddata/sdk-ui-gen-ai/internal`); this adapter only supplies the host's data sources, renders the
|
|
78
|
+
* host's own save-visualization / copy toasts, and forwards telemetry events through `onEvent`.
|
|
79
|
+
*/
|
|
80
|
+
export declare function GenAIChat({ workspaceId, open, onOpen, onClose, askedQuestion, askSeq, userContext, includeTags, excludeTags, canManageProject, canAnalyzeProject, canFullControl, settings, dialogPosition, embedded, onAppLinkClick, onEvent }: IGenAIChatProps): import("react/jsx-runtime").JSX.Element;
|
|
64
81
|
//# sourceMappingURL=GenAIChat.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenAIChat.d.ts","sourceRoot":"","sources":["../../src/ui/GenAIChat.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"GenAIChat.d.ts","sourceRoot":"","sources":["../../src/ui/GenAIChat.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,OAAO,EACH,KAAK,yBAAyB,EAC9B,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EAE5B,MAAM,yBAAyB,CAAC;AAUjC;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GACpB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,OAAO,EAAE,yBAAyB,CAAA;CAAE,CAAC;AAE7E,MAAM,WAAW,eAAe;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,+FAA+F;IAC/F,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yFAAyF;IACzF,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;IACvG,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EACtB,WAAW,EACX,IAAI,EACJ,MAAM,EACN,OAAO,EACP,aAAa,EACb,MAAM,EACN,WAAW,EACX,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,cAAc,EACd,OAAO,EACV,EAAE,eAAe,2CAiGjB"}
|