@itwin/saved-views-react 0.1.0

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.
Files changed (77) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +131 -0
  3. package/lib/LayeredDropdownMenu/LayeredDropdownMenu.css +11 -0
  4. package/lib/LayeredDropdownMenu/LayeredDropdownMenu.d.ts +39 -0
  5. package/lib/LayeredDropdownMenu/LayeredDropdownMenu.js +53 -0
  6. package/lib/SavedView.d.ts +18 -0
  7. package/lib/SavedView.js +1 -0
  8. package/lib/SavedViewTile/SavedViewOptions.css +26 -0
  9. package/lib/SavedViewTile/SavedViewOptions.d.ts +139 -0
  10. package/lib/SavedViewTile/SavedViewOptions.js +173 -0
  11. package/lib/SavedViewTile/SavedViewTile.css +89 -0
  12. package/lib/SavedViewTile/SavedViewTile.d.ts +55 -0
  13. package/lib/SavedViewTile/SavedViewTile.js +110 -0
  14. package/lib/SavedViewTile/SavedViewTileContext.d.ts +14 -0
  15. package/lib/SavedViewTile/SavedViewTileContext.js +20 -0
  16. package/lib/SavedViewsClient/ITwinSavedViewsClient.d.ts +30 -0
  17. package/lib/SavedViewsClient/ITwinSavedViewsClient.js +132 -0
  18. package/lib/SavedViewsClient/SavedViewsClient.d.ts +72 -0
  19. package/lib/SavedViewsClient/SavedViewsClient.js +1 -0
  20. package/lib/SavedViewsContext.d.ts +13 -0
  21. package/lib/SavedViewsContext.js +38 -0
  22. package/lib/SavedViewsWidget/SavedViewGroupTile/SavedViewGroupOptions.d.ts +9 -0
  23. package/lib/SavedViewsWidget/SavedViewGroupTile/SavedViewGroupOptions.js +14 -0
  24. package/lib/SavedViewsWidget/SavedViewGroupTile/SavedViewGroupTile.d.ts +14 -0
  25. package/lib/SavedViewsWidget/SavedViewGroupTile/SavedViewGroupTile.js +37 -0
  26. package/lib/SavedViewsWidget/SavedViewGroupTile/SavedViewGroupTileContext.d.ts +14 -0
  27. package/lib/SavedViewsWidget/SavedViewGroupTile/SavedViewGroupTileContext.js +20 -0
  28. package/lib/SavedViewsWidget/SavedViewsExpandableBlockWidget.css +50 -0
  29. package/lib/SavedViewsWidget/SavedViewsExpandableBlockWidget.d.ts +36 -0
  30. package/lib/SavedViewsWidget/SavedViewsExpandableBlockWidget.js +36 -0
  31. package/lib/SavedViewsWidget/SavedViewsFolderWidget.d.ts +14 -0
  32. package/lib/SavedViewsWidget/SavedViewsFolderWidget.js +60 -0
  33. package/lib/StickyExpandableBlock/StickyExpandableBlock.css +20 -0
  34. package/lib/StickyExpandableBlock/StickyExpandableBlock.d.ts +29 -0
  35. package/lib/StickyExpandableBlock/StickyExpandableBlock.js +63 -0
  36. package/lib/TileGrid/TileGrid.css +28 -0
  37. package/lib/TileGrid/TileGrid.d.ts +48 -0
  38. package/lib/TileGrid/TileGrid.js +32 -0
  39. package/lib/api/clients/IModelQueryClient.d.ts +10 -0
  40. package/lib/api/clients/IModelQueryClient.js +45 -0
  41. package/lib/api/clients/ISavedViewsClient.d.ts +9 -0
  42. package/lib/api/clients/ISavedViewsClient.js +16 -0
  43. package/lib/api/utilities/SavedViewTypes.d.ts +48 -0
  44. package/lib/api/utilities/SavedViewTypes.js +1 -0
  45. package/lib/api/utilities/translation/ModelsAndCategoriesHelper.d.ts +3 -0
  46. package/lib/api/utilities/translation/ModelsAndCategoriesHelper.js +57 -0
  47. package/lib/api/utilities/translation/RgbColor.d.ts +29 -0
  48. package/lib/api/utilities/translation/RgbColor.js +1 -0
  49. package/lib/api/utilities/translation/SavedViewTranslation.d.ts +22 -0
  50. package/lib/api/utilities/translation/SavedViewTranslation.js +246 -0
  51. package/lib/api/utilities/translation/SavedViewsExtensionHandlers.d.ts +13 -0
  52. package/lib/api/utilities/translation/SavedViewsExtensionHandlers.js +42 -0
  53. package/lib/api/utilities/translation/clipVectorsExtractor.d.ts +5 -0
  54. package/lib/api/utilities/translation/clipVectorsExtractor.js +56 -0
  55. package/lib/api/utilities/translation/displayStyleExtractor.d.ts +17 -0
  56. package/lib/api/utilities/translation/displayStyleExtractor.js +499 -0
  57. package/lib/api/utilities/translation/extensionExtractor.d.ts +18 -0
  58. package/lib/api/utilities/translation/extensionExtractor.js +79 -0
  59. package/lib/api/utilities/translation/extractionUtilities.d.ts +209 -0
  60. package/lib/api/utilities/translation/extractionUtilities.js +515 -0
  61. package/lib/api/utilities/translation/urlConverter.d.ts +7 -0
  62. package/lib/api/utilities/translation/urlConverter.js +42 -0
  63. package/lib/api/utilities/translation/viewExtractorSavedViewToLegacySavedView.d.ts +35 -0
  64. package/lib/api/utilities/translation/viewExtractorSavedViewToLegacySavedView.js +298 -0
  65. package/lib/experimental.d.ts +4 -0
  66. package/lib/experimental.js +8 -0
  67. package/lib/index.d.ts +12 -0
  68. package/lib/index.js +14 -0
  69. package/lib/localization.d.ts +52 -0
  70. package/lib/localization.js +51 -0
  71. package/lib/ui/viewlist/ModelCategoryOverrideProvider.d.ts +31 -0
  72. package/lib/ui/viewlist/ModelCategoryOverrideProvider.js +88 -0
  73. package/lib/useSavedViews.d.ts +52 -0
  74. package/lib/useSavedViews.js +514 -0
  75. package/lib/utils.d.ts +1 -0
  76. package/lib/utils.js +7 -0
  77. package/package.json +75 -0
@@ -0,0 +1,37 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ import { SvgFolder } from "@itwin/itwinui-icons-react";
7
+ import { Text, Tile } from "@itwin/itwinui-react";
8
+ import { useLayoutEffect, useMemo, useRef, useState } from "react";
9
+ import { EditableTileName } from "../../SavedViewTile/SavedViewTile.js";
10
+ import { SavedViewGroupTileContextProvider } from "./SavedViewGroupTileContext.js";
11
+ export function SavedViewGroupTile(props) {
12
+ const divRef = useRef(null);
13
+ const [editingName, setEditingName] = useState(false);
14
+ useLayoutEffect(() => {
15
+ if (props.focused && divRef.current) {
16
+ const scrollContainer = divRef.current.closest(".svr-saved-views-widget");
17
+ if (scrollContainer) {
18
+ scrollContainer.scrollTop = props.initialScrollTop;
19
+ }
20
+ divRef.current.querySelector("button")?.focus();
21
+ divRef.current.scrollIntoView({ block: "nearest" });
22
+ }
23
+ },
24
+ // eslint-disable-next-line react-hooks/exhaustive-deps
25
+ []);
26
+ const dispatchOpenGroup = () => props.onOpen(props.group.id);
27
+ const savedViewGroupTileContext = useMemo(() => ({ group: props.group, setEditingName }), [props.group]);
28
+ return (_jsx(SavedViewGroupTileContextProvider, { value: savedViewGroupTileContext, children: _jsx("div", { ref: divRef, children: _jsx(Tile, { className: "svr-folder", variant: "folder", name: _jsx(EditableTileName, { displayName: props.group.displayName, editable: props.editable || editingName, editing: editingName, actions: {
29
+ onStartEditing: () => setEditingName(true),
30
+ onEndEditing: (newName) => {
31
+ setEditingName(false);
32
+ if (newName !== props.group.displayName) {
33
+ props.onRename?.(props.group.id, newName);
34
+ }
35
+ },
36
+ } }), thumbnail: _jsxs("div", { className: "svr-folder-edit", onClick: dispatchOpenGroup, children: [_jsx("div", { style: { position: "absolute" } }), _jsx(SvgFolder, { className: "iui-thumbnail-icon" })] }), isActionable: !props.editable && !editingName, moreOptions: (props.options && props.options.length > 0) ? props.options : undefined, onClick: dispatchOpenGroup, children: _jsxs(Text, { isMuted: true, children: [props.numItems, " items"] }) }) }) }));
37
+ }
@@ -0,0 +1,14 @@
1
+ /// <reference types="react" />
2
+ import type { SavedViewGroup } from "../../SavedView.js";
3
+ /** Context that's accessable within `<SavedViewGroupTile />` component. */
4
+ export interface SavedViewGroupTileContext {
5
+ group: SavedViewGroup;
6
+ setEditingName: (value: boolean) => void;
7
+ }
8
+ /** @internal */
9
+ export declare const SavedViewGroupTileContextProvider: import("react").Provider<SavedViewGroupTileContext | undefined>;
10
+ /**
11
+ * Context that's accessable within `<SavedViewGroupTile />` component. You can use this to make custom actions for
12
+ * `SavedViewGroupTile`.
13
+ */
14
+ export declare function useSavedViewGroupTileContext(): SavedViewGroupTileContext;
@@ -0,0 +1,20 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import { createContext, useContext } from "react";
6
+ const savedViewGroupTileContext = createContext(undefined);
7
+ savedViewGroupTileContext.displayName = "SavedViewGroupTileContext";
8
+ /** @internal */
9
+ export const SavedViewGroupTileContextProvider = savedViewGroupTileContext.Provider;
10
+ /**
11
+ * Context that's accessable within `<SavedViewGroupTile />` component. You can use this to make custom actions for
12
+ * `SavedViewGroupTile`.
13
+ */
14
+ export function useSavedViewGroupTileContext() {
15
+ const contextValue = useContext(savedViewGroupTileContext);
16
+ return contextValue ?? {
17
+ group: { id: "SavedViewGroupTileContext_NoContext", displayName: "" },
18
+ setEditingName: () => { },
19
+ };
20
+ }
@@ -0,0 +1,50 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ @layer itwin-svr {
7
+ .svr-saved-views-widget {
8
+ --itwin-svr-tile-width: calc(8 * var(--iui-size-xl));
9
+ --itwin-svr-thumbnail-height: calc(4 * var(--iui-size-xl));
10
+
11
+ overflow: auto;
12
+ }
13
+
14
+ .svr-group-grid {
15
+ --itwin-svr-tile-width: calc(3 * var(--iui-size-3xl));
16
+ }
17
+
18
+ .svr-folder .iui-tile-thumbnail {
19
+ position: relative;
20
+ }
21
+
22
+ .svr-folder-edit.svr-folder-edit {
23
+ width: 100%;
24
+ height: 100%;
25
+ display: grid;
26
+ place-items: center;
27
+ cursor: pointer;
28
+ }
29
+
30
+ .svr-folder-edit.svr-folder-edit > div {
31
+ height: 100%;
32
+ width: 100%;
33
+ visibility: hidden;
34
+ display: grid;
35
+ place-items: center;
36
+ background: var(--iui-color-background-transparent-hover);
37
+ }
38
+
39
+ .svr-folder .svr-folder-edit.svr-folder-edit:hover > div {
40
+ visibility: visible;
41
+ }
42
+
43
+ .svr-borderless-expandable-block-title {
44
+ display: flex;
45
+ gap: var(--iui-size-xs);
46
+ align-items: center;
47
+ }
48
+ }
49
+
50
+ /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9TYXZlZFZpZXdzV2lkZ2V0L1NhdmVkVmlld3NFeHBhbmRhYmxlQmxvY2tXaWRnZXQuY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBIiwiZmlsZSI6IlNhdmVkVmlld3NFeHBhbmRhYmxlQmxvY2tXaWRnZXQuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiogQ29weXJpZ2h0IChjKSBCZW50bGV5IFN5c3RlbXMsIEluY29ycG9yYXRlZC4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiogU2VlIExJQ0VOU0UubWQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSB0ZXJtcyBhbmQgZnVsbCBjb3B5cmlnaHQgbm90aWNlLlxuKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuQGxheWVyIGl0d2luLXN2ciB7XG4gIC5zdnItc2F2ZWQtdmlld3Mtd2lkZ2V0IHtcbiAgICAtLWl0d2luLXN2ci10aWxlLXdpZHRoOiBjYWxjKDggKiB2YXIoLS1pdWktc2l6ZS14bCkpO1xuICAgIC0taXR3aW4tc3ZyLXRodW1ibmFpbC1oZWlnaHQ6IGNhbGMoNCAqIHZhcigtLWl1aS1zaXplLXhsKSk7XG5cbiAgICBvdmVyZmxvdzogYXV0bztcbiAgfVxuXG4gIC5zdnItZ3JvdXAtZ3JpZCB7XG4gICAgLS1pdHdpbi1zdnItdGlsZS13aWR0aDogY2FsYygzICogdmFyKC0taXVpLXNpemUtM3hsKSk7XG4gIH1cblxuICAuc3ZyLWZvbGRlciAuaXVpLXRpbGUtdGh1bWJuYWlsIHtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIH1cblxuICAuc3ZyLWZvbGRlci1lZGl0LnN2ci1mb2xkZXItZWRpdCB7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIGRpc3BsYXk6IGdyaWQ7XG4gICAgcGxhY2UtaXRlbXM6IGNlbnRlcjtcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG4gIH1cblxuICAuc3ZyLWZvbGRlci1lZGl0LnN2ci1mb2xkZXItZWRpdCA+IGRpdiB7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIHdpZHRoOiAxMDAlO1xuICAgIHZpc2liaWxpdHk6IGhpZGRlbjtcbiAgICBkaXNwbGF5OiBncmlkO1xuICAgIHBsYWNlLWl0ZW1zOiBjZW50ZXI7XG4gICAgYmFja2dyb3VuZDogdmFyKC0taXVpLWNvbG9yLWJhY2tncm91bmQtdHJhbnNwYXJlbnQtaG92ZXIpO1xuICB9XG5cbiAgLnN2ci1mb2xkZXIgLnN2ci1mb2xkZXItZWRpdC5zdnItZm9sZGVyLWVkaXQ6aG92ZXIgPiBkaXYge1xuICAgIHZpc2liaWxpdHk6IHZpc2libGU7XG4gIH1cblxuICAuc3ZyLWJvcmRlcmxlc3MtZXhwYW5kYWJsZS1ibG9jay10aXRsZSB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBnYXA6IHZhcigtLWl1aS1zaXplLXhzKTtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICB9XG59XG4iXX0= */
@@ -0,0 +1,36 @@
1
+ import { type ReactElement, type ReactNode } from "react";
2
+ import type { SavedView, SavedViewGroup, SavedViewTag } from "../SavedView.js";
3
+ import type { SavedViewActions } from "../useSavedViews.js";
4
+ import "./SavedViewsExpandableBlockWidget.css";
5
+ interface SavedViewsExpandableBlockWidgetProps {
6
+ savedViews: Map<string, SavedView>;
7
+ groups: Map<string, SavedViewGroup>;
8
+ tags: Map<string, SavedViewTag>;
9
+ actions?: Partial<SavedViewActions> | undefined;
10
+ editable?: boolean | undefined;
11
+ options?: ((savedView: SavedView) => (((close: () => void) => ReactElement[]) | ReactElement[])) | undefined;
12
+ }
13
+ export declare function SavedViewsExpandableBlockWidget(props: SavedViewsExpandableBlockWidgetProps): ReactElement;
14
+ interface SavedViewsGroupProps {
15
+ group: SavedViewGroup | undefined;
16
+ savedViews: Map<string, SavedView>;
17
+ groups: Map<string, SavedViewGroup>;
18
+ tags: Map<string, SavedViewTag>;
19
+ expanded?: boolean | undefined;
20
+ actions?: Partial<SavedViewActions> | undefined;
21
+ editable?: boolean | undefined;
22
+ options?: ((savedView: SavedView) => (((close: () => void) => ReactElement[]) | ReactElement[])) | undefined;
23
+ }
24
+ export declare function SavedViewsGroup(props: SavedViewsGroupProps): ReactElement;
25
+ interface BorderlessExpandableBlockProps {
26
+ displayName: string;
27
+ numItems: number;
28
+ expanded?: boolean | undefined;
29
+ shared?: boolean | undefined;
30
+ editable?: boolean | undefined;
31
+ onExpandToggle?: (expanded: boolean) => void;
32
+ className?: string | undefined;
33
+ children: ReactNode;
34
+ }
35
+ export declare function BorderlessExpandableBlock(props: BorderlessExpandableBlockProps): ReactElement;
36
+ export {};
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ import { SvgBlank, SvgEdit, SvgMore, SvgShare } from "@itwin/itwinui-icons-react";
7
+ import { DropdownMenu, IconButton, MenuItem, Text } from "@itwin/itwinui-react";
8
+ import { useState } from "react";
9
+ import { SavedViewTile } from "../SavedViewTile/SavedViewTile.js";
10
+ import { StickyExpandableBlock } from "../StickyExpandableBlock/StickyExpandableBlock.js";
11
+ import { TileGrid } from "../TileGrid/TileGrid.js";
12
+ import "./SavedViewsExpandableBlockWidget.css";
13
+ export function SavedViewsExpandableBlockWidget(props) {
14
+ return (_jsxs("div", { className: "svr-saved-views-widget", children: [_jsx(SavedViewsGroup, { group: undefined, savedViews: props.savedViews, actions: props.actions, groups: props.groups, tags: props.tags, editable: props.editable, options: props.options, expanded: true }), [...props.groups.values()].map((group) => _jsx(SavedViewsGroup, { group: group, savedViews: props.savedViews, groups: props.groups, tags: props.tags, actions: props.actions, editable: props.editable, options: props.options }, group.id))] }));
15
+ }
16
+ export function SavedViewsGroup(props) {
17
+ const savedViews = [...props.savedViews.values()].filter(({ groupId }) => groupId === props.group?.id);
18
+ return (_jsx(BorderlessExpandableBlock, { displayName: props.group?.displayName ?? "Ungrouped", numItems: savedViews.length, expanded: props.expanded, shared: props.group?.shared, editable: props.editable, children: _jsx(TileGrid, { gridItems: savedViews, children: (savedView) => (_jsx(SavedViewTile, { savedView: savedView, tags: props.tags, editable: props.editable, onRename: props.actions?.renameSavedView, options: props.options?.(savedView) }, savedView.id)) }) }));
19
+ }
20
+ export function BorderlessExpandableBlock(props) {
21
+ const handleEditGroupClick = (closeDropdown) => {
22
+ closeDropdown();
23
+ };
24
+ const [expanded, setExpanded] = useState(props.expanded ?? false);
25
+ const handleExpandToggle = (expanded) => {
26
+ setExpanded(expanded);
27
+ props.onExpandToggle?.(expanded);
28
+ };
29
+ return (_jsx(StickyExpandableBlock, { titleClassName: "svr-borderless-expandable-block-title", title: _jsxs(_Fragment, { children: [props.shared && _jsx(SvgShare, {}), _jsx(Text, { children: props.displayName }), _jsxs(Text, { isMuted: true, children: ["(", props.numItems, ")"] })] }), endIcon: props.editable &&
30
+ _jsx(DropdownMenu, { menuItems: (close) => [
31
+ _jsx(MenuItem, { startIcon: _jsx(SvgEdit, {}), onClick: () => handleEditGroupClick(close), children: "Edit" }, "edit"),
32
+ props.shared
33
+ ? _jsx(MenuItem, { startIcon: _jsx(SvgBlank, {}), children: "Unshare" }, "unshare")
34
+ : _jsx(MenuItem, { startIcon: _jsx(SvgBlank, {}), children: "Share" }, "share"),
35
+ ], children: _jsx(IconButton, { styleType: "borderless", size: "small", children: _jsx(SvgMore, {}) }) }), isExpanded: expanded, onToggle: handleExpandToggle, children: expanded && props.children }));
36
+ }
@@ -0,0 +1,14 @@
1
+ import { type ReactElement } from "react";
2
+ import type { SavedView, SavedViewGroup, SavedViewTag } from "../SavedView.js";
3
+ import type { SavedViewActions } from "../useSavedViews.js";
4
+ interface SavedViewsFolderWidgetProps {
5
+ savedViews: Map<string, SavedView>;
6
+ groups: Map<string, SavedViewGroup>;
7
+ tags: Map<string, SavedViewTag>;
8
+ actions?: Partial<SavedViewActions> | undefined;
9
+ editable?: boolean | undefined;
10
+ options?: ((savedView: SavedView) => (((close: () => void) => ReactElement[]) | ReactElement[])) | undefined;
11
+ onTileClick?: ((selectedViewId: string) => void) | undefined;
12
+ }
13
+ export declare function SavedViewsFolderWidget(props: SavedViewsFolderWidgetProps): ReactElement;
14
+ export {};
@@ -0,0 +1,60 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ import { SvgChevronLeft, SvgHome } from "@itwin/itwinui-icons-react";
7
+ import { Breadcrumbs, Button, DropdownButton, IconButton, MenuItem } from "@itwin/itwinui-react";
8
+ import { useCallback, useMemo, useState } from "react";
9
+ import { SavedViewTile } from "../SavedViewTile/SavedViewTile.js";
10
+ import { TileGrid } from "../TileGrid/TileGrid.js";
11
+ import { SavedViewGroupOptions } from "./SavedViewGroupTile/SavedViewGroupOptions.js";
12
+ import { SavedViewGroupTile } from "./SavedViewGroupTile/SavedViewGroupTile.js";
13
+ import { BorderlessExpandableBlock } from "./SavedViewsExpandableBlockWidget.js";
14
+ export function SavedViewsFolderWidget(props) {
15
+ const groupedSavedViews = useMemo(() => {
16
+ const ungrouped = [];
17
+ const groups = new Map([[undefined, ungrouped]]);
18
+ for (const groupId of props.groups.keys()) {
19
+ groups.set(groupId, []);
20
+ }
21
+ for (const savedView of props.savedViews.values()) {
22
+ const group = groups.get(savedView.groupId) ?? ungrouped;
23
+ group.push(savedView);
24
+ }
25
+ return groups;
26
+ }, [props.savedViews, props.groups]);
27
+ const [state, setState] = useState({ activeGroupId: undefined, focusedGroupId: undefined });
28
+ const [storedScrollOffset, setStoredScrollOffset] = useState(0);
29
+ const handleGroupOpen = useCallback((activeGroupId) => setState({ activeGroupId, focusedGroupId: undefined }), []);
30
+ const activeGroup = state.activeGroupId !== undefined && props.groups.get(state.activeGroupId);
31
+ if (!activeGroup) {
32
+ return (_jsx(SavedViewsHomeScreen, { groupedSavedViews: groupedSavedViews, groups: props.groups, tags: props.tags, focusedGroupId: state.focusedGroupId, clearFocusedGroup: () => setState(({ activeGroupId }) => ({ activeGroupId, focusedGroupId: undefined })), onGroupOpen: handleGroupOpen, initialScrollTop: storedScrollOffset, storeScrollOffset: setStoredScrollOffset, actions: props.actions, editable: props.editable, savedViewOptions: props.options, onTileClick: props.onTileClick }));
33
+ }
34
+ return (_jsx(SavedViewsGroupScreen, { activeGroup: activeGroup, groups: props.groups, tags: props.tags, savedViews: groupedSavedViews.get(activeGroup.id) ?? [], setActiveGroup: (activeGroupId) => setState({ activeGroupId, focusedGroupId: state.activeGroupId }), actions: props.actions, editable: props.editable, options: props.options, onTileClick: props.onTileClick }, activeGroup.id));
35
+ }
36
+ function SavedViewsHomeScreen(props) {
37
+ const ungroupedSavedViews = props.groupedSavedViews.get(undefined) ?? [];
38
+ const groupTiles = useMemo(() => [...props.groups.values()].map((group) => _jsx(SavedViewGroupTile, { group: group, numItems: props.groupedSavedViews.get(group.id)?.length ?? 0, onOpen: props.onGroupOpen, focused: group.id === props.focusedGroupId, initialScrollTop: props.initialScrollTop, editable: props.editable, options: [
39
+ _jsx(SavedViewGroupOptions.Rename, {}, "rename"),
40
+ _jsx(MenuItem, { onClick: () => props.actions?.deleteGroup?.(group.id), children: "Delete" }, "delete"),
41
+ ], onRename: props.actions?.renameGroup }, group.id)), [
42
+ props.groups,
43
+ props.groupedSavedViews,
44
+ props.onGroupOpen,
45
+ props.focusedGroupId,
46
+ props.initialScrollTop,
47
+ props.editable,
48
+ props.actions,
49
+ ]);
50
+ return (_jsxs("div", { className: "svr-saved-views-widget", style: { overflow: "auto" }, onScroll: (event) => props.storeScrollOffset(event.target.scrollTop), children: [_jsx(BorderlessExpandableBlock, { displayName: "Saved views", numItems: ungroupedSavedViews.length, expanded: true, children: _jsx(TileGrid, { gridItems: ungroupedSavedViews, children: (savedView) => _jsx(SavedViewTile, { savedView: savedView, tags: props.tags, editable: props.editable, onRename: props.actions?.renameSavedView, options: props.savedViewOptions?.(savedView), onClick: props.onTileClick }, savedView.id) }) }), _jsx(BorderlessExpandableBlock, { className: "svr-group-grid", displayName: "Groups", numItems: props.groups.size, expanded: true, onExpandToggle: (expanded) => !expanded && props.clearFocusedGroup?.(), editable: props.editable, children: _jsx("div", { className: "svr-tile-grid", children: groupTiles }) })] }));
51
+ }
52
+ function SavedViewsGroupScreen(props) {
53
+ const groups = useMemo(() => [...props.groups.values()], [props.groups]);
54
+ return (_jsxs("div", { className: "svr-saved-views-widget", style: { display: "grid", grid: "auto 1fr / 1fr" }, children: [_jsxs("div", { style: {
55
+ display: "flex",
56
+ gap: "var(--iui-size-s)",
57
+ background: "var(--iui-color-background)",
58
+ padding: "var(--iui-size-s)",
59
+ }, children: [_jsx(Button, { startIcon: _jsx(SvgChevronLeft, {}), onClick: () => props.setActiveGroup(undefined), children: "Back" }), _jsxs(Breadcrumbs, { children: [_jsx(IconButton, { onClick: () => props.setActiveGroup(undefined), children: _jsx(SvgHome, {}) }), _jsx(DropdownButton, { menuItems: (close) => groups.map((group) => _jsx(MenuItem, { onClick: () => { close(); props.setActiveGroup(group.id); }, children: group.displayName }, group.id)), children: props.activeGroup.displayName })] })] }), _jsx("div", { style: { overflow: "auto" }, children: _jsx(TileGrid, { gridItems: props.savedViews, children: (savedView) => (_jsx(SavedViewTile, { savedView: savedView, tags: props.tags, editable: props.editable, options: props.options?.(savedView), onClick: props.onTileClick }, savedView.id)) }) })] }));
60
+ }
@@ -0,0 +1,20 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ .svr-expandable-block-header {
7
+ position: sticky;
8
+ top: 0;
9
+ z-index: 1;
10
+ }
11
+
12
+ .svr-expandable-block-header[data-stuck=true] {
13
+ box-shadow: var(--iui-shadow-1);
14
+ }
15
+
16
+ .svr-expandable-block-header:not(:hover) {
17
+ background: var(--iui-color-background);
18
+ }
19
+
20
+ /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9TdGlja3lFeHBhbmRhYmxlQmxvY2svU3RpY2t5RXhwYW5kYWJsZUJsb2NrLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSIsImZpbGUiOiJTdGlja3lFeHBhbmRhYmxlQmxvY2suY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiogQ29weXJpZ2h0IChjKSBCZW50bGV5IFN5c3RlbXMsIEluY29ycG9yYXRlZC4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiogU2VlIExJQ0VOU0UubWQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSB0ZXJtcyBhbmQgZnVsbCBjb3B5cmlnaHQgbm90aWNlLlxuKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuLnN2ci1leHBhbmRhYmxlLWJsb2NrLWhlYWRlciB7XG4gIHBvc2l0aW9uOiBzdGlja3k7XG4gIHRvcDogMDtcbiAgei1pbmRleDogMTtcbn1cblxuLnN2ci1leHBhbmRhYmxlLWJsb2NrLWhlYWRlcltkYXRhLXN0dWNrPXRydWVdIHtcbiAgYm94LXNoYWRvdzogdmFyKC0taXVpLXNoYWRvdy0xKTtcbn1cblxuLnN2ci1leHBhbmRhYmxlLWJsb2NrLWhlYWRlcjpub3QoOmhvdmVyKSB7XG4gIGJhY2tncm91bmQ6IHZhcigtLWl1aS1jb2xvci1iYWNrZ3JvdW5kKTtcbn1cbiJdfQ== */
@@ -0,0 +1,29 @@
1
+ import { type ReactElement, type ReactNode } from "react";
2
+ import "./StickyExpandableBlock.css";
3
+ interface StickyExpandableBlockProps {
4
+ /** Expandable block title. */
5
+ title: ReactNode;
6
+ /** Icon that goes after the expandable block title. */
7
+ endIcon?: ReactNode | undefined;
8
+ /** Forwarded to iTwinUI `<ExpandableBlock />`. */
9
+ isExpanded?: boolean | undefined;
10
+ /** Forwarded to iTwinUI `<ExpandableBlock />`. */
11
+ onToggle?: ((expanded: boolean) => void) | undefined;
12
+ /** `className` of the wrapping container. */
13
+ className?: string | undefined;
14
+ /** `className` of the title container. */
15
+ titleClassName?: string | undefined;
16
+ /** Expandable block content. */
17
+ children?: ReactNode | undefined;
18
+ }
19
+ /**
20
+ * Alternative to <ExpandableBlock /> component from iTwinUI. Its label sticks to the top of scroll container when user
21
+ * scrolls down.
22
+ *
23
+ * @example
24
+ * <StickyExpandableBlock title="Block">
25
+ * Content
26
+ * </StickyExpandableBlock>
27
+ */
28
+ export declare function StickyExpandableBlock(props: StickyExpandableBlockProps): ReactElement;
29
+ export {};
@@ -0,0 +1,63 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ import { ExpandableBlock } from "@itwin/itwinui-react";
7
+ import { useLayoutEffect, useRef, useState, } from "react";
8
+ import "./StickyExpandableBlock.css";
9
+ /**
10
+ * Alternative to <ExpandableBlock /> component from iTwinUI. Its label sticks to the top of scroll container when user
11
+ * scrolls down.
12
+ *
13
+ * @example
14
+ * <StickyExpandableBlock title="Block">
15
+ * Content
16
+ * </StickyExpandableBlock>
17
+ */
18
+ export function StickyExpandableBlock(props) {
19
+ // Prevent clicks on the end icon toggling expansion state
20
+ const handleGroupMenuClick = (event) => {
21
+ event.stopPropagation();
22
+ };
23
+ // When clicking the label while it's stuck at the top, we want the label to remain visible after the expandable block
24
+ // collapses
25
+ const scrollbackRef = useRef(null);
26
+ const handleExpandToggle = (expanded) => {
27
+ props.onToggle?.(expanded);
28
+ if (!expanded) {
29
+ scrollbackRef.current?.scrollIntoView({ block: "nearest" });
30
+ }
31
+ };
32
+ const stickyRef = useRef(null);
33
+ const stuck = useSticky(stickyRef);
34
+ return (_jsxs(ExpandableBlock.Wrapper, { className: props.className, styleType: "borderless", isExpanded: props.isExpanded, onToggle: handleExpandToggle, children: [_jsx("div", { ref: scrollbackRef }), _jsxs(ExpandableBlock.Trigger, { ref: stickyRef, as: "div", className: "svr-expandable-block-header", "data-stuck": stuck, role: "button", children: [_jsx(ExpandableBlock.ExpandIcon, {}), _jsx(ExpandableBlock.LabelArea, { children: _jsx(ExpandableBlock.Title, { className: props.titleClassName, children: props.title }) }), props.endIcon &&
35
+ _jsx(ExpandableBlock.EndIcon, { onClick: handleGroupMenuClick, children: props.endIcon })] }), _jsx(ExpandableBlock.Content, { children: props.children })] }));
36
+ }
37
+ function useSticky(ref) {
38
+ const [stuck, setStuck] = useState(false);
39
+ useLayoutEffect(() => {
40
+ const stuckElement = ref.current;
41
+ if (!stuckElement) {
42
+ return;
43
+ }
44
+ const scrollableParent = findScrollableParent(stuckElement.parentElement);
45
+ const handleScroll = () => {
46
+ const parentOffset = stuckElement.parentElement?.offsetTop ?? stuckElement.offsetTop;
47
+ setStuck(parentOffset < stuckElement.offsetTop);
48
+ };
49
+ scrollableParent?.addEventListener("scroll", handleScroll);
50
+ return () => scrollableParent?.removeEventListener("scroll", handleScroll);
51
+ }, [ref]);
52
+ return stuck;
53
+ }
54
+ function findScrollableParent(element) {
55
+ if (!element) {
56
+ return undefined;
57
+ }
58
+ const style = getComputedStyle(element);
59
+ if (style.overflowY !== "visible" && style.overflowY !== "hidden") {
60
+ return element;
61
+ }
62
+ return findScrollableParent(element.parentElement);
63
+ }
@@ -0,0 +1,28 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ @layer itwin-svr {
7
+ .svr-tile-grid {
8
+ display: grid;
9
+ grid-template-columns: repeat(auto-fill, var(--itwin-svr-tile-width));
10
+ place-content: start space-around;
11
+ place-items: center;
12
+ gap: var(--iui-size-m);
13
+ margin: var(--iui-size-xs) var(--iui-size-s);
14
+ margin-bottom: var(--iui-size-l);
15
+ }
16
+
17
+ .svr-tile-grid--more-items-tile {
18
+ padding: var(--iui-size-m);
19
+ display: grid;
20
+ gap: var(--iui-size-s);
21
+ justify-items: center;
22
+ width: calc(0.8 * var(--itwin-svr-tile-width));
23
+ text-align: center;
24
+ min-width: min-content;
25
+ }
26
+ }
27
+
28
+ /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9UaWxlR3JpZC9UaWxlR3JpZC5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEiLCJmaWxlIjoiVGlsZUdyaWQuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiogQ29weXJpZ2h0IChjKSBCZW50bGV5IFN5c3RlbXMsIEluY29ycG9yYXRlZC4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiogU2VlIExJQ0VOU0UubWQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSB0ZXJtcyBhbmQgZnVsbCBjb3B5cmlnaHQgbm90aWNlLlxuKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuQGxheWVyIGl0d2luLXN2ciB7XG4gIC5zdnItdGlsZS1ncmlkIHtcbiAgICBkaXNwbGF5OiBncmlkO1xuICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogcmVwZWF0KGF1dG8tZmlsbCwgdmFyKC0taXR3aW4tc3ZyLXRpbGUtd2lkdGgpKTtcbiAgICBwbGFjZS1jb250ZW50OiBzdGFydCBzcGFjZS1hcm91bmQ7XG4gICAgcGxhY2UtaXRlbXM6IGNlbnRlcjtcbiAgICBnYXA6IHZhcigtLWl1aS1zaXplLW0pO1xuICAgIG1hcmdpbjogdmFyKC0taXVpLXNpemUteHMpIHZhcigtLWl1aS1zaXplLXMpO1xuICAgIG1hcmdpbi1ib3R0b206IHZhcigtLWl1aS1zaXplLWwpO1xuICB9XG5cbiAgLnN2ci10aWxlLWdyaWQtLW1vcmUtaXRlbXMtdGlsZSB7XG4gICAgcGFkZGluZzogdmFyKC0taXVpLXNpemUtbSk7XG4gICAgZGlzcGxheTogZ3JpZDtcbiAgICBnYXA6IHZhcigtLWl1aS1zaXplLXMpO1xuICAgIGp1c3RpZnktaXRlbXM6IGNlbnRlcjtcbiAgICB3aWR0aDogY2FsYygwLjggKiB2YXIoLS1pdHdpbi1zdnItdGlsZS13aWR0aCkpO1xuICAgIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgICBtaW4td2lkdGg6IG1pbi1jb250ZW50O1xuICB9XG59XG4iXX0= */
@@ -0,0 +1,48 @@
1
+ import { type CSSProperties, type ReactElement, type ReactNode } from "react";
2
+ import "./TileGrid.css";
3
+ interface TileGridProps<T> {
4
+ /** Items to be displayed in the grid. */
5
+ gridItems: T[];
6
+ /**
7
+ * Amount of items to reveal with each "Show more" trigger. You can disable pagination by specifying a large number,
8
+ * e.g. `Number.MAX_VALUE`.
9
+ *
10
+ * @default 12
11
+ */
12
+ pageSize?: number | undefined;
13
+ /**
14
+ * Overrides the default "Show more" tile.
15
+ *
16
+ * @param moreAvailable Number of unrevealed items
17
+ * @param revealMore When invoked, increases the amount of revealed items
18
+ * @returns Content to be placed after all revealed items
19
+ */
20
+ moreItemsTile?: ((numMoreAvailable: number, revealMore: () => void) => ReactNode) | undefined;
21
+ /** `className` of the wrapping element. */
22
+ className?: string | undefined;
23
+ /**
24
+ * `style` of the wrapping element. You can control the column width by setting `--itwin-svr-tile-width` CSS variable.
25
+ *
26
+ * @example
27
+ * <TileGrid gridItems={items} style={{ "--itwin-svr-tile-width": "200px" }}>
28
+ * {renderItem}
29
+ * </TileGrid>
30
+ */
31
+ style?: (CSSProperties & CustomCSSVariables) | undefined;
32
+ /** Invoked with items that are currently revealed. */
33
+ children: (gridItem: T) => ReactNode;
34
+ }
35
+ interface CustomCSSVariables {
36
+ /** Width of grid columns. */
37
+ "--itwin-svr-tile-width"?: string | undefined;
38
+ }
39
+ /**
40
+ * Grid layout for Saved View tiles. Limits the amount of visible tiles and gives option to the user to reveal more.
41
+ *
42
+ * @example
43
+ * <TileGrid gridItems={savedViews}>
44
+ * {(savedView) => <SavedViewTile key={savedView.id} savedView={savedView} />}
45
+ * </TileGrid>
46
+ */
47
+ export declare function TileGrid<T>(props: TileGridProps<T>): ReactElement;
48
+ export {};
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ import { Button, Surface, Text } from "@itwin/itwinui-react";
7
+ import { useState } from "react";
8
+ import { useSavedViewsContext } from "../SavedViewsContext.js";
9
+ import "./TileGrid.css";
10
+ /**
11
+ * Grid layout for Saved View tiles. Limits the amount of visible tiles and gives option to the user to reveal more.
12
+ *
13
+ * @example
14
+ * <TileGrid gridItems={savedViews}>
15
+ * {(savedView) => <SavedViewTile key={savedView.id} savedView={savedView} />}
16
+ * </TileGrid>
17
+ */
18
+ export function TileGrid(props) {
19
+ const pageSize = props.pageSize ?? 12;
20
+ const [softLimit, setSoftLimit] = useState(pageSize - 1);
21
+ const tiles = props.gridItems
22
+ .slice(0, props.gridItems.length > softLimit + pageSize ? softLimit : undefined)
23
+ .map((gridItem) => props.children(gridItem));
24
+ const numMoreAvailable = props.gridItems.length - tiles.length;
25
+ const moreItemsTile = props.moreItemsTile ?? ((numMoreAvailable, revealMore) => (_jsx(MoreItemsTile, { numMoreAvailable: numMoreAvailable, revealMore: revealMore })));
26
+ return (_jsxs("div", { className: `svr-tile-grid ${props.className ?? ""}`, style: props.style, children: [tiles, numMoreAvailable > 0 &&
27
+ moreItemsTile(numMoreAvailable, () => setSoftLimit((prev) => prev + pageSize))] }));
28
+ }
29
+ function MoreItemsTile(props) {
30
+ const { localization } = useSavedViewsContext();
31
+ return (_jsxs(Surface, { className: "svr-tile-grid--more-items-tile", elevation: 0, children: [_jsx(Text, { variant: "headline", children: props.numMoreAvailable }), _jsx(Text, { variant: "leading", children: localization.tileGrid.moreAvailable }), _jsx(Button, { onClick: props.revealMore, children: localization.tileGrid.showMore })] }));
32
+ }
@@ -0,0 +1,10 @@
1
+ import type { Id64Array } from "@itwin/core-bentley";
2
+ import type { IModelConnection } from "@itwin/core-frontend";
3
+ export declare const IModelQueryClient: {
4
+ getAllModels: (iModel: IModelConnection) => Promise<Id64Array>;
5
+ getAllCategories: (iModel: IModelConnection) => Promise<Id64Array>;
6
+ getAllModelsAndCategories: (iModel: IModelConnection) => Promise<{
7
+ models: Id64Array;
8
+ categories: Id64Array;
9
+ }>;
10
+ };
@@ -0,0 +1,45 @@
1
+ import { QueryRowFormat } from "@itwin/core-common";
2
+ /**
3
+ * Helper function to execute ECSql queries.
4
+ */
5
+ const executeQuery = async (iModel, query) => {
6
+ const rows = [];
7
+ const sqlReader = iModel.createQueryReader(query, undefined, {
8
+ rowFormat: QueryRowFormat.UseJsPropertyNames,
9
+ });
10
+ const result = await sqlReader.toArray();
11
+ for (const row of result) {
12
+ rows.push(row.id);
13
+ }
14
+ return rows;
15
+ };
16
+ export const IModelQueryClient = {
17
+ getAllModels: async (iModel) => {
18
+ // Note: IsNotSpatiallyLocated was introduced in a later version of the BisCore ECSchema.
19
+ // If the iModel has an earlier version, the statement will throw because the property does not exist.
20
+ // If the iModel was created from an earlier version and later upgraded to a newer version, the property may be NULL for models created prior to the upgrade.
21
+ let query = "SELECT ECInstanceId FROM Bis.GeometricModel3D WHERE IsPrivate = false AND IsTemplate = false AND (IsNotSpatiallyLocated IS NULL OR IsNotSpatiallyLocated = false)";
22
+ let models = [];
23
+ try {
24
+ models = await executeQuery(iModel, query);
25
+ }
26
+ catch {
27
+ query =
28
+ "SELECT ECInstanceId FROM Bis.GeometricModel3D WHERE IsPrivate = false AND IsTemplate = false";
29
+ models = await executeQuery(iModel, query);
30
+ }
31
+ return models;
32
+ },
33
+ getAllCategories: async (iModel) => {
34
+ // Only use categories with elements in them
35
+ const query = "SELECT DISTINCT Category.Id AS id FROM BisCore.GeometricElement3d WHERE Category.Id IN (SELECT ECInstanceId FROM BisCore.SpatialCategory)";
36
+ const categories = await executeQuery(iModel, query);
37
+ return categories;
38
+ },
39
+ getAllModelsAndCategories: async (iModel) => {
40
+ return {
41
+ models: await IModelQueryClient.getAllModels(iModel),
42
+ categories: await IModelQueryClient.getAllCategories(iModel),
43
+ };
44
+ },
45
+ };
@@ -0,0 +1,9 @@
1
+ import type { LegacySavedView, LegacySavedViewBase } from "../utilities/SavedViewTypes.js";
2
+ /** Is a 3d saved view */
3
+ export declare function isSavedView3d(view: LegacySavedViewBase): view is LegacySavedView;
4
+ /** Is a 3d spatial saved view */
5
+ export declare function isSpatialSavedView(view: LegacySavedViewBase): boolean;
6
+ /** Is a 2d drawing saved view */
7
+ export declare function isDrawingSavedView(view: LegacySavedViewBase): boolean;
8
+ /** Is a 2d sheet saved view */
9
+ export declare function isSheetSavedView(view: LegacySavedViewBase): boolean;
@@ -0,0 +1,16 @@
1
+ /** Is a 3d saved view */
2
+ export function isSavedView3d(view) {
3
+ return !view.is2d;
4
+ }
5
+ /** Is a 3d spatial saved view */
6
+ export function isSpatialSavedView(view) {
7
+ return ((view.is2d === undefined || !view.is2d) && "modelSelectorProps" in view);
8
+ }
9
+ /** Is a 2d drawing saved view */
10
+ export function isDrawingSavedView(view) {
11
+ return view.is2d !== undefined && view.is2d && !("sheetProps" in view);
12
+ }
13
+ /** Is a 2d sheet saved view */
14
+ export function isSheetSavedView(view) {
15
+ return view.is2d !== undefined && view.is2d && "sheetProps" in view;
16
+ }