@gooddata/sdk-ui-application-header 11.40.0-alpha.3
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/LICENSE +19 -0
- package/README.md +16 -0
- package/esm/AppHeaderNotifications/AppHeaderNotifications.d.ts +11 -0
- package/esm/AppHeaderNotifications/AppHeaderNotifications.js +22 -0
- package/esm/AppHeaderNotifications/dashboardUrl.d.ts +2 -0
- package/esm/AppHeaderNotifications/dashboardUrl.js +36 -0
- package/esm/WorkspacePicker/WorkspacePicker.d.ts +17 -0
- package/esm/WorkspacePicker/WorkspacePicker.js +26 -0
- package/esm/WorkspacePicker/usePagedWorkspaces.d.ts +40 -0
- package/esm/WorkspacePicker/usePagedWorkspaces.js +149 -0
- package/esm/index.d.ts +3 -0
- package/esm/index.js +5 -0
- package/esm/sdk-ui-application-header.d.ts +79 -0
- package/esm/tsdoc-metadata.json +11 -0
- package/package.json +102 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2022-2026 GoodData Corporation
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# GoodData.UI SDK - Application Header
|
|
2
|
+
|
|
3
|
+
This package is a part of the [GoodData.UI SDK](https://sdk.gooddata.com/gooddata-ui/docs/about_gooddataui.html).
|
|
4
|
+
To learn more, check [the source monorepo](https://github.com/gooddata/gooddata-ui-sdk).
|
|
5
|
+
|
|
6
|
+
This package provides React components for the GoodData application header — the notifications dropdown, the workspace picker, and supporting hooks for paged workspace lookups.
|
|
7
|
+
|
|
8
|
+
## Stability
|
|
9
|
+
|
|
10
|
+
The API surface is marked `@alpha` and may change between minor releases.
|
|
11
|
+
|
|
12
|
+
## License
|
|
13
|
+
|
|
14
|
+
(C) 2022-2026 GoodData Corporation
|
|
15
|
+
|
|
16
|
+
This project is under MIT License. See [LICENSE](https://github.com/gooddata/gooddata-ui-sdk/blob/master/libs/sdk-ui-application-header/LICENSE).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ILocale } from "@gooddata/sdk-ui";
|
|
2
|
+
/**
|
|
3
|
+
* @alpha
|
|
4
|
+
*/
|
|
5
|
+
export declare function AppHeaderNotifications({ isMobile, closeNotificationsOverlay, locale, useAsOfDateParam, enableExportToDocumentStorage }: {
|
|
6
|
+
isMobile?: boolean;
|
|
7
|
+
closeNotificationsOverlay?: () => void;
|
|
8
|
+
locale?: ILocale;
|
|
9
|
+
useAsOfDateParam?: boolean;
|
|
10
|
+
enableExportToDocumentStorage?: boolean;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { DefaultNotificationsPanelButton, NotificationsPanel } from "@gooddata/sdk-ui-ext";
|
|
3
|
+
import { getDashboardUrl } from "./dashboardUrl.js";
|
|
4
|
+
/**
|
|
5
|
+
* @alpha
|
|
6
|
+
*/
|
|
7
|
+
export function AppHeaderNotifications({ isMobile = false, closeNotificationsOverlay, locale, useAsOfDateParam, enableExportToDocumentStorage, }) {
|
|
8
|
+
const onNotificationClick = (notification) => {
|
|
9
|
+
const url = getDashboardUrl(notification, useAsOfDateParam);
|
|
10
|
+
if (url && notification.notificationType === "alertNotification") {
|
|
11
|
+
closeNotificationsOverlay?.();
|
|
12
|
+
// When query params do not change, we want to trigger router with location change manually
|
|
13
|
+
if (window.location.href === url) {
|
|
14
|
+
window.dispatchEvent(new HashChangeEvent("hashchange"));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
window.location.assign(url);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return (_jsx(NotificationsPanel, { NotificationsPanelButton: DefaultNotificationsPanelButton, onNotificationClick: onNotificationClick, renderInline: isMobile, enableScheduleNotifications: enableExportToDocumentStorage, locale: locale }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// (C) 2025-2026 GoodData Corporation
|
|
2
|
+
import { isAlertNotification } from "@gooddata/sdk-model";
|
|
3
|
+
export function getDashboardUrl(notification, useAsOfDateParam = false) {
|
|
4
|
+
if (!isAlertNotification(notification)) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const dashboardURL = notification.details.data.automation.dashboardURL;
|
|
8
|
+
const isCustomDashboardURL = notification.details.data.automation.isCustomDashboardURL;
|
|
9
|
+
if (isCustomDashboardURL || !notification.automationId) {
|
|
10
|
+
return dashboardURL;
|
|
11
|
+
}
|
|
12
|
+
const url = new URL(dashboardURL);
|
|
13
|
+
// Add parameters function
|
|
14
|
+
const addParams = (params) => {
|
|
15
|
+
if (!params.has("automationId")) {
|
|
16
|
+
params.append("automationId", notification.automationId);
|
|
17
|
+
}
|
|
18
|
+
if (useAsOfDateParam && !params.has("asOfDate")) {
|
|
19
|
+
params.append("asOfDate", notification.details.timestamp);
|
|
20
|
+
}
|
|
21
|
+
return params;
|
|
22
|
+
};
|
|
23
|
+
// If URL has a hash, add parameters to the hash part
|
|
24
|
+
if (url.hash) {
|
|
25
|
+
const baseUrl = `${url.origin}${url.pathname}${url.search}`;
|
|
26
|
+
const hashPath = url.hash.substring(1);
|
|
27
|
+
// Split hash into route and params if it contains a query string
|
|
28
|
+
const [hashRoute, paramString] = hashPath.includes("?") ? hashPath.split("?", 2) : [hashPath, ""];
|
|
29
|
+
// Add parameters to hash part
|
|
30
|
+
const hashParams = addParams(new URLSearchParams(paramString));
|
|
31
|
+
return `${baseUrl}#${hashRoute}?${hashParams.toString()}`;
|
|
32
|
+
}
|
|
33
|
+
// For URLs without hash, add parameters to the URL search
|
|
34
|
+
url.search = addParams(new URLSearchParams(url.search)).toString();
|
|
35
|
+
return url.toString();
|
|
36
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type MouseEvent } from "react";
|
|
2
|
+
import { type IAnalyticalBackend } from "@gooddata/sdk-backend-spi";
|
|
3
|
+
import { type IHeaderWorkspace } from "@gooddata/sdk-ui-kit";
|
|
4
|
+
/**
|
|
5
|
+
* @alpha
|
|
6
|
+
*/
|
|
7
|
+
export interface IWorkspacePickerProps {
|
|
8
|
+
backend: IAnalyticalBackend;
|
|
9
|
+
userId: string;
|
|
10
|
+
selectedWorkspace?: IHeaderWorkspace;
|
|
11
|
+
onWorkspaceSelect: (workspace: IHeaderWorkspace) => void;
|
|
12
|
+
onHomepageLinkClick?: (evt: MouseEvent) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* @alpha
|
|
16
|
+
*/
|
|
17
|
+
export declare function WorkspacePicker({ backend, userId, selectedWorkspace, onWorkspaceSelect, onHomepageLinkClick }: IWorkspacePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { DomainHomepageLink, HeaderWorkspacePicker } from "@gooddata/sdk-ui-kit";
|
|
5
|
+
import { usePagedWorkspaces } from "./usePagedWorkspaces.js";
|
|
6
|
+
/**
|
|
7
|
+
* @alpha
|
|
8
|
+
*/
|
|
9
|
+
export function WorkspacePicker({ backend, userId, selectedWorkspace, onWorkspaceSelect, onHomepageLinkClick, }) {
|
|
10
|
+
const { items, totalItemsCount, isLoading, search, onSearch, loadInitialItems, reset, initialLoadCompleted, hasNextPage, skeletonItemsCount, isNextPageLoading, shouldLoadNextPage, loadNextPage, } = usePagedWorkspaces({
|
|
11
|
+
backend,
|
|
12
|
+
userId,
|
|
13
|
+
});
|
|
14
|
+
const handleOpenStateChanged = useCallback((opened) => {
|
|
15
|
+
if (opened) {
|
|
16
|
+
// Fetch initial items when dropdown opens
|
|
17
|
+
loadInitialItems();
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
reset();
|
|
21
|
+
}
|
|
22
|
+
}, [loadInitialItems, reset]);
|
|
23
|
+
return (_jsx(HeaderWorkspacePicker, { projectPickerFooter: _jsx(DomainHomepageLink, { onClick: onHomepageLinkClick }), workspaces: items, selectedWorkspace: selectedWorkspace, totalWorkspacesCount: totalItemsCount, searchString: search, showSearch: initialLoadCompleted, isLoading: isLoading ? items.length === 0 : false, onSelect: onWorkspaceSelect, onSearch: onSearch, onOpenStateChanged: handleOpenStateChanged,
|
|
24
|
+
//paging props
|
|
25
|
+
loadNextPage: loadNextPage, hasNextPage: hasNextPage, skeletonItemsCount: skeletonItemsCount, isNextPageLoading: isNextPageLoading, shouldLoadNextPage: shouldLoadNextPage }));
|
|
26
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type IAnalyticalBackend, type IAnalyticalWorkspace, type IWorkspaceDescriptor } from "@gooddata/sdk-backend-spi";
|
|
2
|
+
/**
|
|
3
|
+
* Conditional type that resolves workspace items based on resolveWorkspaceDescriptor flag.
|
|
4
|
+
* - When true (default): returns IWorkspaceDescriptor[] (resolved descriptors with id, title, description)
|
|
5
|
+
* - When false: returns IAnalyticalWorkspace[] (workspace handles with service methods)
|
|
6
|
+
*
|
|
7
|
+
* @alpha
|
|
8
|
+
*/
|
|
9
|
+
export type WorkspaceItems<TResolve extends boolean> = TResolve extends true ? IWorkspaceDescriptor[] : IAnalyticalWorkspace[];
|
|
10
|
+
/**
|
|
11
|
+
* @alpha
|
|
12
|
+
*/
|
|
13
|
+
export interface IPagedWorkspacesConfig<TResolve extends boolean = true> {
|
|
14
|
+
backend: IAnalyticalBackend;
|
|
15
|
+
userId: string;
|
|
16
|
+
resolveWorkspaceDescriptor?: TResolve;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* @alpha
|
|
20
|
+
*/
|
|
21
|
+
export interface IPagedWorkspacesResult<TResolve extends boolean = true> {
|
|
22
|
+
items: WorkspaceItems<TResolve>;
|
|
23
|
+
totalItemsCount: number | undefined;
|
|
24
|
+
isLoading: boolean;
|
|
25
|
+
isNextPageLoading: boolean;
|
|
26
|
+
initialLoadCompleted: boolean;
|
|
27
|
+
currentPage: number;
|
|
28
|
+
search: string;
|
|
29
|
+
hasNextPage: boolean;
|
|
30
|
+
skeletonItemsCount: number;
|
|
31
|
+
loadNextPage: () => void;
|
|
32
|
+
onSearch: (searchString: string) => void;
|
|
33
|
+
reset: () => void;
|
|
34
|
+
loadInitialItems: () => void;
|
|
35
|
+
shouldLoadNextPage: (lastItemIndex: number, itemsCount: number) => boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* @alpha
|
|
39
|
+
*/
|
|
40
|
+
export declare function usePagedWorkspaces<TResolve extends boolean = true>({ backend, userId, resolveWorkspaceDescriptor }: IPagedWorkspacesConfig<TResolve>): IPagedWorkspacesResult<TResolve>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { useCallback, useRef, useState } from "react";
|
|
3
|
+
import { debounce } from "lodash-es";
|
|
4
|
+
const ITEMS_PER_PAGE = 50;
|
|
5
|
+
/**
|
|
6
|
+
* @alpha
|
|
7
|
+
*/
|
|
8
|
+
export function usePagedWorkspaces({ backend, userId, resolveWorkspaceDescriptor = true, }) {
|
|
9
|
+
const [items, setItems] = useState([]);
|
|
10
|
+
const [totalItemsCount, setTotalItemsCount] = useState(undefined);
|
|
11
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
12
|
+
const [isNextPageLoading, setIsNextPageLoading] = useState(false);
|
|
13
|
+
const [initialLoadCompleted, setInitialLoadCompleted] = useState(false);
|
|
14
|
+
const [currentPage, setCurrentPage] = useState(0);
|
|
15
|
+
const [search, setSearch] = useState("");
|
|
16
|
+
const initialLoadCompletedRef = useRef(false);
|
|
17
|
+
const abortControllerRef = useRef(null);
|
|
18
|
+
const totalItems = totalItemsCount ?? items.length;
|
|
19
|
+
const hasNextPage = totalItems > items.length;
|
|
20
|
+
const skeletonItemsCount = hasNextPage ? Math.min(ITEMS_PER_PAGE, totalItems - items.length) : 0;
|
|
21
|
+
const fetchItems = useCallback(async (params) => {
|
|
22
|
+
const { page, search, resetItems = false } = params;
|
|
23
|
+
// Cancel any ongoing request
|
|
24
|
+
if (abortControllerRef.current) {
|
|
25
|
+
abortControllerRef.current.abort();
|
|
26
|
+
}
|
|
27
|
+
abortControllerRef.current = new AbortController();
|
|
28
|
+
// Capture the current signal before the await to check the correct one after
|
|
29
|
+
const currentSignal = abortControllerRef.current.signal;
|
|
30
|
+
const isFirstPage = page === 0;
|
|
31
|
+
// Show global loading when resetting items (tab switch, search) or on first page
|
|
32
|
+
if (resetItems || isFirstPage) {
|
|
33
|
+
setIsLoading(true);
|
|
34
|
+
// Clear items immediately to show loading spinner
|
|
35
|
+
if (resetItems) {
|
|
36
|
+
setItems([]);
|
|
37
|
+
setTotalItemsCount(undefined);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
setIsNextPageLoading(true);
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const limit = ITEMS_PER_PAGE;
|
|
45
|
+
const offset = page * ITEMS_PER_PAGE;
|
|
46
|
+
const searchValue = search;
|
|
47
|
+
let resultWorkspaces;
|
|
48
|
+
if (searchValue) {
|
|
49
|
+
resultWorkspaces = await backend
|
|
50
|
+
.workspaces()
|
|
51
|
+
.forUser(userId)
|
|
52
|
+
.withLimit(limit)
|
|
53
|
+
.withOffset(offset)
|
|
54
|
+
.withSearch(searchValue)
|
|
55
|
+
.query();
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
resultWorkspaces = await backend
|
|
59
|
+
.workspaces()
|
|
60
|
+
.forUser(userId)
|
|
61
|
+
.withLimit(limit)
|
|
62
|
+
.withOffset(offset)
|
|
63
|
+
.query();
|
|
64
|
+
}
|
|
65
|
+
let fetchedItems;
|
|
66
|
+
if (resolveWorkspaceDescriptor) {
|
|
67
|
+
fetchedItems = (await Promise.all(resultWorkspaces.items.map((workspace) => workspace?.getDescriptor())));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
fetchedItems = resultWorkspaces.items;
|
|
71
|
+
}
|
|
72
|
+
const totalItemsCount = resultWorkspaces.totalCount;
|
|
73
|
+
// Check if THIS request was aborted (using captured signal, not current ref)
|
|
74
|
+
if (currentSignal.aborted) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
setTotalItemsCount(totalItemsCount);
|
|
78
|
+
if (resetItems || isFirstPage) {
|
|
79
|
+
setItems(fetchedItems);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
setItems((prevItems) => [...prevItems, ...fetchedItems]);
|
|
83
|
+
}
|
|
84
|
+
// Handle initial load completion
|
|
85
|
+
if (!initialLoadCompletedRef.current) {
|
|
86
|
+
initialLoadCompletedRef.current = true;
|
|
87
|
+
setInitialLoadCompleted(true);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
// Ignore abort errors
|
|
92
|
+
if (error.name !== "AbortError") {
|
|
93
|
+
console.error("Failed to fetch insights:", error);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
// Only update loading state if this request wasn't superseded
|
|
98
|
+
if (!currentSignal.aborted) {
|
|
99
|
+
setIsLoading(false);
|
|
100
|
+
setIsNextPageLoading(false);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}, [backend, userId, resolveWorkspaceDescriptor]);
|
|
104
|
+
const loadNextPage = useCallback(() => {
|
|
105
|
+
if (!hasNextPage || isNextPageLoading || isLoading) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const nextPage = currentPage + 1;
|
|
109
|
+
setCurrentPage(nextPage);
|
|
110
|
+
void fetchItems({ page: nextPage, search });
|
|
111
|
+
}, [hasNextPage, isNextPageLoading, isLoading, currentPage, search, fetchItems]);
|
|
112
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
113
|
+
const onSearch = useCallback(debounce((searchString) => {
|
|
114
|
+
setCurrentPage(0);
|
|
115
|
+
setSearch(searchString);
|
|
116
|
+
void fetchItems({ page: 0, search: searchString, resetItems: true });
|
|
117
|
+
}, 500), [fetchItems]);
|
|
118
|
+
const reset = useCallback(() => {
|
|
119
|
+
if (abortControllerRef.current) {
|
|
120
|
+
abortControllerRef.current.abort();
|
|
121
|
+
}
|
|
122
|
+
setItems([]);
|
|
123
|
+
setTotalItemsCount(undefined);
|
|
124
|
+
setIsLoading(false);
|
|
125
|
+
setIsNextPageLoading(false);
|
|
126
|
+
setCurrentPage(0);
|
|
127
|
+
setSearch("");
|
|
128
|
+
}, []);
|
|
129
|
+
const shouldLoadNextPage = useCallback((lastItemIndex, itemsCount) => lastItemIndex >= itemsCount - 5, []);
|
|
130
|
+
const loadInitialItems = useCallback(() => {
|
|
131
|
+
void fetchItems({ page: 0, search: "", resetItems: true });
|
|
132
|
+
}, [fetchItems]);
|
|
133
|
+
return {
|
|
134
|
+
items,
|
|
135
|
+
totalItemsCount,
|
|
136
|
+
isLoading,
|
|
137
|
+
isNextPageLoading,
|
|
138
|
+
initialLoadCompleted,
|
|
139
|
+
currentPage,
|
|
140
|
+
search,
|
|
141
|
+
hasNextPage,
|
|
142
|
+
skeletonItemsCount,
|
|
143
|
+
loadInitialItems,
|
|
144
|
+
loadNextPage,
|
|
145
|
+
onSearch,
|
|
146
|
+
reset,
|
|
147
|
+
shouldLoadNextPage,
|
|
148
|
+
};
|
|
149
|
+
}
|
package/esm/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { AppHeaderNotifications } from "./AppHeaderNotifications/AppHeaderNotifications.js";
|
|
2
|
+
export { WorkspacePicker, type IWorkspacePickerProps } from "./WorkspacePicker/WorkspacePicker.js";
|
|
3
|
+
export { usePagedWorkspaces, type IPagedWorkspacesConfig, type IPagedWorkspacesResult, type WorkspaceItems, } from "./WorkspacePicker/usePagedWorkspaces.js";
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// (C) 2022-2026 GoodData Corporation
|
|
2
|
+
/* oxlint-disable no-barrel-files/no-barrel-files */
|
|
3
|
+
export { AppHeaderNotifications } from "./AppHeaderNotifications/AppHeaderNotifications.js";
|
|
4
|
+
export { WorkspacePicker } from "./WorkspacePicker/WorkspacePicker.js";
|
|
5
|
+
export { usePagedWorkspaces, } from "./WorkspacePicker/usePagedWorkspaces.js";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { IAnalyticalBackend } from '@gooddata/sdk-backend-spi';
|
|
2
|
+
import { IAnalyticalWorkspace } from '@gooddata/sdk-backend-spi';
|
|
3
|
+
import { IHeaderWorkspace } from '@gooddata/sdk-ui-kit';
|
|
4
|
+
import { ILocale } from '@gooddata/sdk-ui';
|
|
5
|
+
import { IWorkspaceDescriptor } from '@gooddata/sdk-backend-spi';
|
|
6
|
+
import { JSX } from 'react/jsx-runtime';
|
|
7
|
+
import { MouseEvent as MouseEvent_2 } from 'react';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @alpha
|
|
11
|
+
*/
|
|
12
|
+
export declare function AppHeaderNotifications({ isMobile, closeNotificationsOverlay, locale, useAsOfDateParam, enableExportToDocumentStorage }: {
|
|
13
|
+
isMobile?: boolean;
|
|
14
|
+
closeNotificationsOverlay?: () => void;
|
|
15
|
+
locale?: ILocale;
|
|
16
|
+
useAsOfDateParam?: boolean;
|
|
17
|
+
enableExportToDocumentStorage?: boolean;
|
|
18
|
+
}): JSX.Element;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @alpha
|
|
22
|
+
*/
|
|
23
|
+
export declare interface IPagedWorkspacesConfig<TResolve extends boolean = true> {
|
|
24
|
+
backend: IAnalyticalBackend;
|
|
25
|
+
userId: string;
|
|
26
|
+
resolveWorkspaceDescriptor?: TResolve;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @alpha
|
|
31
|
+
*/
|
|
32
|
+
export declare interface IPagedWorkspacesResult<TResolve extends boolean = true> {
|
|
33
|
+
items: WorkspaceItems<TResolve>;
|
|
34
|
+
totalItemsCount: number | undefined;
|
|
35
|
+
isLoading: boolean;
|
|
36
|
+
isNextPageLoading: boolean;
|
|
37
|
+
initialLoadCompleted: boolean;
|
|
38
|
+
currentPage: number;
|
|
39
|
+
search: string;
|
|
40
|
+
hasNextPage: boolean;
|
|
41
|
+
skeletonItemsCount: number;
|
|
42
|
+
loadNextPage: () => void;
|
|
43
|
+
onSearch: (searchString: string) => void;
|
|
44
|
+
reset: () => void;
|
|
45
|
+
loadInitialItems: () => void;
|
|
46
|
+
shouldLoadNextPage: (lastItemIndex: number, itemsCount: number) => boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @alpha
|
|
51
|
+
*/
|
|
52
|
+
export declare interface IWorkspacePickerProps {
|
|
53
|
+
backend: IAnalyticalBackend;
|
|
54
|
+
userId: string;
|
|
55
|
+
selectedWorkspace?: IHeaderWorkspace;
|
|
56
|
+
onWorkspaceSelect: (workspace: IHeaderWorkspace) => void;
|
|
57
|
+
onHomepageLinkClick?: (evt: MouseEvent_2) => void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @alpha
|
|
62
|
+
*/
|
|
63
|
+
export declare function usePagedWorkspaces<TResolve extends boolean = true>({ backend, userId, resolveWorkspaceDescriptor }: IPagedWorkspacesConfig<TResolve>): IPagedWorkspacesResult<TResolve>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Conditional type that resolves workspace items based on resolveWorkspaceDescriptor flag.
|
|
67
|
+
* - When true (default): returns IWorkspaceDescriptor[] (resolved descriptors with id, title, description)
|
|
68
|
+
* - When false: returns IAnalyticalWorkspace[] (workspace handles with service methods)
|
|
69
|
+
*
|
|
70
|
+
* @alpha
|
|
71
|
+
*/
|
|
72
|
+
export declare type WorkspaceItems<TResolve extends boolean> = TResolve extends true ? IWorkspaceDescriptor[] : IAnalyticalWorkspace[];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @alpha
|
|
76
|
+
*/
|
|
77
|
+
export declare function WorkspacePicker({ backend, userId, selectedWorkspace, onWorkspaceSelect, onHomepageLinkClick }: IWorkspacePickerProps): JSX.Element;
|
|
78
|
+
|
|
79
|
+
export { }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
+
{
|
|
4
|
+
"tsdocVersion": "0.12",
|
|
5
|
+
"toolPackages": [
|
|
6
|
+
{
|
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
|
8
|
+
"packageVersion": "7.55.2"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gooddata/sdk-ui-application-header",
|
|
3
|
+
"version": "11.40.0-alpha.3",
|
|
4
|
+
"description": "GoodData SDK application header components — workspace picker, notifications dropdown",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "GoodData Corporation",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/gooddata/gooddata-ui-sdk.git",
|
|
10
|
+
"directory": "libs/sdk-ui-application-header"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"esm/**/*.js",
|
|
14
|
+
"esm/**/*.json",
|
|
15
|
+
"esm/**/*.d.ts",
|
|
16
|
+
"esm/**/*.map"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"browser": "./esm/index.js",
|
|
21
|
+
"types": "esm/index.d.ts",
|
|
22
|
+
"exports": "./esm/index.js",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"lodash-es": "^4.17.23",
|
|
25
|
+
"@gooddata/sdk-backend-spi": "11.40.0-alpha.3",
|
|
26
|
+
"@gooddata/sdk-ui": "11.40.0-alpha.3",
|
|
27
|
+
"@gooddata/sdk-model": "11.40.0-alpha.3",
|
|
28
|
+
"@gooddata/sdk-ui-ext": "11.40.0-alpha.3",
|
|
29
|
+
"@gooddata/sdk-ui-kit": "11.40.0-alpha.3",
|
|
30
|
+
"@gooddata/util": "11.40.0-alpha.3"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@microsoft/api-documenter": "^7.17.0",
|
|
34
|
+
"@microsoft/api-extractor": "^7.55.2",
|
|
35
|
+
"@testing-library/dom": "10.4.1",
|
|
36
|
+
"@testing-library/react": "16.3.0",
|
|
37
|
+
"@types/lodash-es": "^4.17.12",
|
|
38
|
+
"@types/node": "24.12.0",
|
|
39
|
+
"@types/react": "19.1.11",
|
|
40
|
+
"@types/react-dom": "19.1.7",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "8.58.0",
|
|
42
|
+
"@typescript-eslint/parser": "8.58.0",
|
|
43
|
+
"@typescript/native-preview": "7.0.0-dev.20260202.1",
|
|
44
|
+
"@vitest/coverage-v8": "4.1.0",
|
|
45
|
+
"@vitest/eslint-plugin": "1.6.6",
|
|
46
|
+
"eslint": "^9.39.2",
|
|
47
|
+
"eslint-import-resolver-typescript": "4.4.4",
|
|
48
|
+
"eslint-plugin-headers": "1.3.3",
|
|
49
|
+
"eslint-plugin-import-esm": "1.2.1",
|
|
50
|
+
"eslint-plugin-import-x": "4.16.1",
|
|
51
|
+
"eslint-plugin-jsdoc": "62.1.0",
|
|
52
|
+
"eslint-plugin-no-barrel-files": "1.2.2",
|
|
53
|
+
"eslint-plugin-no-only-tests": "3.3.0",
|
|
54
|
+
"eslint-plugin-react": "7.37.5",
|
|
55
|
+
"eslint-plugin-react-hooks": "5.2.0",
|
|
56
|
+
"eslint-plugin-regexp": "1.15.0",
|
|
57
|
+
"eslint-plugin-sonarjs": "3.0.6",
|
|
58
|
+
"eslint-plugin-tsdoc": "0.2.14",
|
|
59
|
+
"happy-dom": "18.0.1",
|
|
60
|
+
"jiti": "2.6.1",
|
|
61
|
+
"npm-run-all": "^4.1.5",
|
|
62
|
+
"oxfmt": "0.45.0",
|
|
63
|
+
"oxlint": "^1.43.0",
|
|
64
|
+
"oxlint-tsgolint": "0.11.4",
|
|
65
|
+
"react": "19.1.1",
|
|
66
|
+
"react-dom": "19.1.1",
|
|
67
|
+
"react-intl": "7.1.11",
|
|
68
|
+
"rolldown": "1.0.0-rc.9",
|
|
69
|
+
"tslib": "2.8.1",
|
|
70
|
+
"typescript": "5.9.3",
|
|
71
|
+
"vite": "8.0.0",
|
|
72
|
+
"vitest": "4.1.0",
|
|
73
|
+
"vitest-dom": "0.1.1",
|
|
74
|
+
"@gooddata/eslint-config": "11.40.0-alpha.3",
|
|
75
|
+
"@gooddata/oxlint-config": "11.40.0-alpha.3",
|
|
76
|
+
"@gooddata/sdk-ui-theme-provider": "11.40.0-alpha.3"
|
|
77
|
+
},
|
|
78
|
+
"peerDependencies": {
|
|
79
|
+
"react": ">=18.3.1",
|
|
80
|
+
"react-dom": ">=18.3.1",
|
|
81
|
+
"react-intl": ">=7"
|
|
82
|
+
},
|
|
83
|
+
"scripts": {
|
|
84
|
+
"_phase:build": "npm run build",
|
|
85
|
+
"_phase:test": "npm run test-once",
|
|
86
|
+
"_phase:validate": "npm run validate",
|
|
87
|
+
"api-extractor": "mkdir -p api && [ -z \"${CI}\" ] && (api-extractor run -l) || (api-extractor run)",
|
|
88
|
+
"build": "npm-run-all -p build-check build-ts && npm run api-extractor",
|
|
89
|
+
"build-check": "tsgo",
|
|
90
|
+
"build-ts": "tsgo -p ./tsconfig.build.json",
|
|
91
|
+
"clean": "../../common/scripts/clean-command-state.sh && rm -rf esm *.log",
|
|
92
|
+
"format-check": "oxfmt --check .",
|
|
93
|
+
"format-write": "oxfmt .",
|
|
94
|
+
"lint": "oxlint . --type-aware --quiet && eslint .",
|
|
95
|
+
"lint-fix": "oxlint . --type-aware --quiet --fix && eslint . --fix",
|
|
96
|
+
"test": "vitest",
|
|
97
|
+
"test-once": "vitest run",
|
|
98
|
+
"validate": "npm run lint && npm run format-check",
|
|
99
|
+
"validate-esm": "node --input-type=module --eval 'import \"@gooddata/sdk-ui-application-header\"'",
|
|
100
|
+
"validate-theming": "node scripts/validateCss.mjs"
|
|
101
|
+
}
|
|
102
|
+
}
|