@perses-dev/dashboards 0.0.0-snapshot-ts-panel-actions-76080ec → 0.0.0-snapshot-reverse-proxy-75afbd7
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/dist/cjs/components/DashboardStickyToolbar/DashboardStickyToolbar.js +0 -2
- package/dist/cjs/components/DeletePanelGroupDialog/DeletePanelGroupDialog.js +5 -20
- package/dist/cjs/components/GridLayout/GridItemContent.js +79 -17
- package/dist/cjs/components/GridLayout/GridLayout.js +78 -126
- package/dist/cjs/components/GridLayout/Row.js +150 -0
- package/dist/cjs/components/GridLayout/index.js +1 -0
- package/dist/cjs/components/LeaveDialog/LeaveDialog.js +81 -0
- package/dist/cjs/components/LeaveDialog/index.js +30 -0
- package/dist/cjs/components/Panel/Panel.js +7 -2
- package/dist/cjs/components/Panel/PanelActions.js +37 -14
- package/dist/cjs/components/Panel/PanelHeader.js +35 -15
- package/dist/cjs/components/Panel/index.js +1 -0
- package/dist/cjs/components/PanelDrawer/PanelDrawer.js +58 -21
- package/dist/cjs/components/PanelDrawer/PanelEditorForm.js +202 -180
- package/dist/cjs/components/PanelDrawer/PanelPreview.js +3 -0
- package/dist/cjs/components/PanelGroupDialog/PanelGroupDialog.js +9 -21
- package/dist/cjs/components/PanelGroupDialog/PanelGroupEditorForm.js +35 -15
- package/dist/cjs/components/QueryViewerDialog/QueryViewerDialog.js +121 -0
- package/dist/cjs/components/QueryViewerDialog/index.js +30 -0
- package/dist/cjs/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.js +2 -1
- package/dist/cjs/components/Variables/ListVariableListBox.js +201 -0
- package/dist/cjs/components/Variables/Variable.js +130 -72
- package/dist/cjs/components/Variables/VariableEditor.js +22 -15
- package/dist/cjs/components/Variables/index.js +1 -0
- package/dist/cjs/components/index.js +3 -1
- package/dist/cjs/constants/user-interface-text.js +4 -2
- package/dist/cjs/context/DashboardProvider/DashboardProvider.js +7 -8
- package/dist/cjs/context/DashboardProvider/DashboardProviderWithQueryParams.js +4 -4
- package/dist/cjs/context/DashboardProvider/duplicate-panel-slice.js +1 -1
- package/dist/cjs/context/DashboardProvider/panel-editor-slice.js +2 -2
- package/dist/cjs/context/DashboardProvider/panel-group-editor-slice.js +6 -2
- package/dist/cjs/context/DashboardProvider/panel-group-slice.js +1 -0
- package/dist/cjs/context/DashboardProvider/view-panel-slice.js +10 -3
- package/dist/cjs/context/PanelEditorProvider/PanelEditorProvider.js +49 -0
- package/dist/cjs/context/PanelEditorProvider/index.js +23 -0
- package/dist/cjs/context/VariableProvider/VariableProvider.js +1 -1
- package/dist/cjs/context/index.js +1 -0
- package/dist/cjs/context/useDashboard.js +5 -4
- package/dist/cjs/views/ViewDashboard/DashboardApp.js +7 -3
- package/dist/cjs/views/ViewDashboard/ViewDashboard.js +9 -8
- package/dist/components/DashboardStickyToolbar/DashboardStickyToolbar.d.ts.map +1 -1
- package/dist/components/DashboardStickyToolbar/DashboardStickyToolbar.js +0 -2
- package/dist/components/DashboardStickyToolbar/DashboardStickyToolbar.js.map +1 -1
- package/dist/components/DashboardToolbar/DashboardToolbar.d.ts +2 -2
- package/dist/components/DashboardToolbar/DashboardToolbar.d.ts.map +1 -1
- package/dist/components/DashboardToolbar/DashboardToolbar.js.map +1 -1
- package/dist/components/DeletePanelGroupDialog/DeletePanelGroupDialog.d.ts.map +1 -1
- package/dist/components/DeletePanelGroupDialog/DeletePanelGroupDialog.js +5 -15
- package/dist/components/DeletePanelGroupDialog/DeletePanelGroupDialog.js.map +1 -1
- package/dist/components/GridLayout/GridItemContent.d.ts.map +1 -1
- package/dist/components/GridLayout/GridItemContent.js +39 -18
- package/dist/components/GridLayout/GridItemContent.js.map +1 -1
- package/dist/components/GridLayout/GridLayout.d.ts +8 -0
- package/dist/components/GridLayout/GridLayout.d.ts.map +1 -1
- package/dist/components/GridLayout/GridLayout.js +72 -126
- package/dist/components/GridLayout/GridLayout.js.map +1 -1
- package/dist/components/GridLayout/Row.d.ts +17 -0
- package/dist/components/GridLayout/Row.d.ts.map +1 -0
- package/dist/components/GridLayout/Row.js +142 -0
- package/dist/components/GridLayout/Row.js.map +1 -0
- package/dist/components/GridLayout/index.d.ts +1 -0
- package/dist/components/GridLayout/index.d.ts.map +1 -1
- package/dist/components/GridLayout/index.js +1 -0
- package/dist/components/GridLayout/index.js.map +1 -1
- package/dist/components/LeaveDialog/LeaveDialog.d.ts +13 -0
- package/dist/components/LeaveDialog/LeaveDialog.d.ts.map +1 -0
- package/dist/components/LeaveDialog/LeaveDialog.js +70 -0
- package/dist/components/LeaveDialog/LeaveDialog.js.map +1 -0
- package/dist/components/LeaveDialog/index.d.ts +2 -0
- package/dist/components/LeaveDialog/index.d.ts.map +1 -0
- package/dist/components/LeaveDialog/index.js +15 -0
- package/dist/components/LeaveDialog/index.js.map +1 -0
- package/dist/components/Panel/HeaderIconButton.d.ts +1 -1
- package/dist/components/Panel/Panel.d.ts +6 -0
- package/dist/components/Panel/Panel.d.ts.map +1 -1
- package/dist/components/Panel/Panel.js +7 -2
- package/dist/components/Panel/Panel.js.map +1 -1
- package/dist/components/Panel/PanelActions.d.ts +5 -0
- package/dist/components/Panel/PanelActions.d.ts.map +1 -1
- package/dist/components/Panel/PanelActions.js +37 -14
- package/dist/components/Panel/PanelActions.js.map +1 -1
- package/dist/components/Panel/PanelHeader.d.ts +7 -1
- package/dist/components/Panel/PanelHeader.d.ts.map +1 -1
- package/dist/components/Panel/PanelHeader.js +36 -16
- package/dist/components/Panel/PanelHeader.js.map +1 -1
- package/dist/components/Panel/index.d.ts +1 -0
- package/dist/components/Panel/index.d.ts.map +1 -1
- package/dist/components/Panel/index.js +1 -0
- package/dist/components/Panel/index.js.map +1 -1
- package/dist/components/PanelDrawer/PanelDrawer.d.ts.map +1 -1
- package/dist/components/PanelDrawer/PanelDrawer.js +59 -22
- package/dist/components/PanelDrawer/PanelDrawer.js.map +1 -1
- package/dist/components/PanelDrawer/PanelEditorForm.d.ts.map +1 -1
- package/dist/components/PanelDrawer/PanelEditorForm.js +205 -183
- package/dist/components/PanelDrawer/PanelEditorForm.js.map +1 -1
- package/dist/components/PanelDrawer/PanelPreview.d.ts.map +1 -1
- package/dist/components/PanelDrawer/PanelPreview.js +4 -1
- package/dist/components/PanelDrawer/PanelPreview.js.map +1 -1
- package/dist/components/PanelGroupDialog/PanelGroupDialog.d.ts.map +1 -1
- package/dist/components/PanelGroupDialog/PanelGroupDialog.js +8 -15
- package/dist/components/PanelGroupDialog/PanelGroupDialog.js.map +1 -1
- package/dist/components/PanelGroupDialog/PanelGroupEditorForm.d.ts +1 -0
- package/dist/components/PanelGroupDialog/PanelGroupEditorForm.d.ts.map +1 -1
- package/dist/components/PanelGroupDialog/PanelGroupEditorForm.js +36 -16
- package/dist/components/PanelGroupDialog/PanelGroupEditorForm.js.map +1 -1
- package/dist/components/QueryViewerDialog/QueryViewerDialog.d.ts +9 -0
- package/dist/components/QueryViewerDialog/QueryViewerDialog.d.ts.map +1 -0
- package/dist/components/QueryViewerDialog/QueryViewerDialog.js +72 -0
- package/dist/components/QueryViewerDialog/QueryViewerDialog.js.map +1 -0
- package/dist/components/QueryViewerDialog/index.d.ts +2 -0
- package/dist/components/QueryViewerDialog/index.d.ts.map +1 -0
- package/dist/components/QueryViewerDialog/index.js +15 -0
- package/dist/components/QueryViewerDialog/index.js.map +1 -0
- package/dist/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.d.ts.map +1 -1
- package/dist/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.js +2 -1
- package/dist/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.js.map +1 -1
- package/dist/components/Variables/ListVariableListBox.d.ts +16 -0
- package/dist/components/Variables/ListVariableListBox.d.ts.map +1 -0
- package/dist/components/Variables/ListVariableListBox.js +141 -0
- package/dist/components/Variables/ListVariableListBox.js.map +1 -0
- package/dist/components/Variables/Variable.d.ts.map +1 -1
- package/dist/components/Variables/Variable.js +134 -76
- package/dist/components/Variables/Variable.js.map +1 -1
- package/dist/components/Variables/VariableEditor.d.ts.map +1 -1
- package/dist/components/Variables/VariableEditor.js +24 -17
- package/dist/components/Variables/VariableEditor.js.map +1 -1
- package/dist/components/Variables/index.d.ts +1 -0
- package/dist/components/Variables/index.d.ts.map +1 -1
- package/dist/components/Variables/index.js +1 -0
- package/dist/components/Variables/index.js.map +1 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +3 -1
- package/dist/components/index.js.map +1 -1
- package/dist/constants/user-interface-text.d.ts +2 -0
- package/dist/constants/user-interface-text.d.ts.map +1 -1
- package/dist/constants/user-interface-text.js +4 -2
- package/dist/constants/user-interface-text.js.map +1 -1
- package/dist/context/DashboardProvider/DashboardProvider.d.ts +5 -5
- package/dist/context/DashboardProvider/DashboardProvider.d.ts.map +1 -1
- package/dist/context/DashboardProvider/DashboardProvider.js +7 -8
- package/dist/context/DashboardProvider/DashboardProvider.js.map +1 -1
- package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.d.ts.map +1 -1
- package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.js +5 -5
- package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.js.map +1 -1
- package/dist/context/DashboardProvider/common.d.ts +1 -1
- package/dist/context/DashboardProvider/common.d.ts.map +1 -1
- package/dist/context/DashboardProvider/common.js.map +1 -1
- package/dist/context/DashboardProvider/duplicate-panel-slice.js +2 -2
- package/dist/context/DashboardProvider/duplicate-panel-slice.js.map +1 -1
- package/dist/context/DashboardProvider/panel-editor-slice.d.ts +1 -0
- package/dist/context/DashboardProvider/panel-editor-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/panel-editor-slice.js +3 -3
- package/dist/context/DashboardProvider/panel-editor-slice.js.map +1 -1
- package/dist/context/DashboardProvider/panel-group-editor-slice.d.ts +1 -0
- package/dist/context/DashboardProvider/panel-group-editor-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/panel-group-editor-slice.js +6 -2
- package/dist/context/DashboardProvider/panel-group-editor-slice.js.map +1 -1
- package/dist/context/DashboardProvider/panel-group-slice.d.ts +3 -0
- package/dist/context/DashboardProvider/panel-group-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/panel-group-slice.js +1 -0
- package/dist/context/DashboardProvider/panel-group-slice.js.map +1 -1
- package/dist/context/DashboardProvider/view-panel-slice.d.ts +6 -2
- package/dist/context/DashboardProvider/view-panel-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/view-panel-slice.js +10 -3
- package/dist/context/DashboardProvider/view-panel-slice.js.map +1 -1
- package/dist/context/PanelEditorProvider/PanelEditorProvider.d.ts +13 -0
- package/dist/context/PanelEditorProvider/PanelEditorProvider.d.ts.map +1 -0
- package/dist/context/PanelEditorProvider/PanelEditorProvider.js +33 -0
- package/dist/context/PanelEditorProvider/PanelEditorProvider.js.map +1 -0
- package/dist/context/PanelEditorProvider/index.d.ts +3 -0
- package/dist/context/PanelEditorProvider/index.d.ts.map +1 -0
- package/dist/context/PanelEditorProvider/index.js +16 -0
- package/dist/context/PanelEditorProvider/index.js.map +1 -0
- package/dist/context/VariableProvider/VariableProvider.js +1 -1
- package/dist/context/VariableProvider/VariableProvider.js.map +1 -1
- package/dist/context/index.d.ts +1 -0
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +1 -0
- package/dist/context/index.js.map +1 -1
- package/dist/context/useDashboard.js +5 -4
- package/dist/context/useDashboard.js.map +1 -1
- package/dist/utils/panelUtils.d.ts +3 -0
- package/dist/utils/panelUtils.d.ts.map +1 -1
- package/dist/utils/panelUtils.js +3 -0
- package/dist/utils/panelUtils.js.map +1 -1
- package/dist/views/ViewDashboard/DashboardApp.d.ts +7 -6
- package/dist/views/ViewDashboard/DashboardApp.d.ts.map +1 -1
- package/dist/views/ViewDashboard/DashboardApp.js +8 -4
- package/dist/views/ViewDashboard/DashboardApp.js.map +1 -1
- package/dist/views/ViewDashboard/ViewDashboard.d.ts.map +1 -1
- package/dist/views/ViewDashboard/ViewDashboard.js +9 -8
- package/dist/views/ViewDashboard/ViewDashboard.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/GridLayout/index.ts"],"names":[],"mappings":"AAaA,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/GridLayout/index.ts"],"names":[],"mappings":"AAaA,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/GridLayout/index.ts"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport * from './GridContainer';\nexport * from './GridItemContent';\nexport * from './GridLayout';\nexport * from './GridTitle';\n"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,cAAc,kBAAkB;AAChC,cAAc,oBAAoB;AAClC,cAAc,eAAe;AAC7B,cAAc,cAAc"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/GridLayout/index.ts"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport * from './GridContainer';\nexport * from './GridItemContent';\nexport * from './GridLayout';\nexport * from './GridTitle';\nexport * from './Row';\n"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,cAAc,kBAAkB;AAChC,cAAc,oBAAoB;AAClC,cAAc,eAAe;AAC7B,cAAc,cAAc;AAC5B,cAAc,QAAQ"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DashboardResource, EphemeralDashboardResource } from '@perses-dev/core';
|
|
2
|
+
import { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import type { BlockerFunction } from '@remix-run/router';
|
|
4
|
+
export interface LeaveDialogProps {
|
|
5
|
+
isBlocked: BlockerFunction | boolean;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function Prompt({ isBlocked, message }: LeaveDialogProps): ReactElement;
|
|
9
|
+
export declare function LeaveDialog({ original, current, }: {
|
|
10
|
+
original: DashboardResource | EphemeralDashboardResource | undefined;
|
|
11
|
+
current: DashboardResource | EphemeralDashboardResource;
|
|
12
|
+
}): ReactNode;
|
|
13
|
+
//# sourceMappingURL=LeaveDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LeaveDialog.d.ts","sourceRoot":"","sources":["../../../src/components/LeaveDialog/LeaveDialog.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAQzD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,gBAAgB,GAAG,YAAY,CA4B7E;AAKD,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,iBAAiB,GAAG,0BAA0B,GAAG,SAAS,CAAC;IACrE,OAAO,EAAE,iBAAiB,GAAG,0BAA0B,CAAC;CACzD,GAAG,SAAS,CAYZ"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Copyright 2025 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
|
+
import { useEffect } from 'react';
|
|
15
|
+
import { useBlocker } from 'react-router-dom';
|
|
16
|
+
import { DiscardChangesConfirmationDialog } from '@perses-dev/components';
|
|
17
|
+
const handleRouteChange = (event)=>{
|
|
18
|
+
event.preventDefault();
|
|
19
|
+
event.returnValue = ''; // Required for Chrome
|
|
20
|
+
return ''; // Required for other browsers
|
|
21
|
+
};
|
|
22
|
+
/*
|
|
23
|
+
* Prompt component uses the useBlocker hook to block react-router navigation when there are unsaved changes.
|
|
24
|
+
* It also listens to the beforeunload event to show a browser confirmation dialog when the user tries to close the tab, refresh the page or change url manually.
|
|
25
|
+
*/ export function Prompt({ isBlocked, message }) {
|
|
26
|
+
const blocker = useBlocker(isBlocked);
|
|
27
|
+
const isBlockedState = blocker.state === 'blocked';
|
|
28
|
+
const isProceedingState = blocker.state === 'proceeding';
|
|
29
|
+
useEffect(()=>{
|
|
30
|
+
if (isBlocked) {
|
|
31
|
+
window.addEventListener('beforeunload', handleRouteChange);
|
|
32
|
+
} else {
|
|
33
|
+
window.removeEventListener('beforeunload', handleRouteChange);
|
|
34
|
+
}
|
|
35
|
+
return ()=>{
|
|
36
|
+
window.removeEventListener('beforeunload', handleRouteChange);
|
|
37
|
+
};
|
|
38
|
+
}, [
|
|
39
|
+
blocker,
|
|
40
|
+
isBlocked,
|
|
41
|
+
isBlockedState
|
|
42
|
+
]);
|
|
43
|
+
const handleDiscardChanges = ()=>blocker.proceed?.();
|
|
44
|
+
const handleCancel = ()=>blocker.reset?.();
|
|
45
|
+
return /*#__PURE__*/ _jsx(DiscardChangesConfirmationDialog, {
|
|
46
|
+
description: message,
|
|
47
|
+
isOpen: isBlockedState || isProceedingState,
|
|
48
|
+
onDiscardChanges: handleDiscardChanges,
|
|
49
|
+
onCancel: handleCancel
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/*
|
|
53
|
+
* LeaveDialog prompts the user with a confirmation dialog when they attempt to leave the page with unsaved changes.
|
|
54
|
+
*/ export function LeaveDialog({ original, current }) {
|
|
55
|
+
const handleIsBlocked = (ctx)=>{
|
|
56
|
+
if (JSON.stringify(original) !== JSON.stringify(current)) {
|
|
57
|
+
// Only block navigation if the pathname is changing (=> ignore search params changes)
|
|
58
|
+
if (ctx.currentLocation.pathname !== ctx.nextLocation.pathname) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
};
|
|
64
|
+
return /*#__PURE__*/ _jsx(Prompt, {
|
|
65
|
+
isBlocked: handleIsBlocked,
|
|
66
|
+
message: "You have unsaved changes, are you sure you want to leave?"
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=LeaveDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/LeaveDialog/LeaveDialog.tsx"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { DashboardResource, EphemeralDashboardResource } from '@perses-dev/core';\nimport { ReactElement, ReactNode, useEffect } from 'react';\nimport { useBlocker } from 'react-router-dom';\nimport { DiscardChangesConfirmationDialog } from '@perses-dev/components';\nimport type { BlockerFunction } from '@remix-run/router';\n\nconst handleRouteChange = (event: BeforeUnloadEvent): string => {\n event.preventDefault();\n event.returnValue = ''; // Required for Chrome\n return ''; // Required for other browsers\n};\n\nexport interface LeaveDialogProps {\n isBlocked: BlockerFunction | boolean;\n message: string;\n}\n\n/*\n * Prompt component uses the useBlocker hook to block react-router navigation when there are unsaved changes.\n * It also listens to the beforeunload event to show a browser confirmation dialog when the user tries to close the tab, refresh the page or change url manually.\n */\nexport function Prompt({ isBlocked, message }: LeaveDialogProps): ReactElement {\n const blocker = useBlocker(isBlocked);\n const isBlockedState = blocker.state === 'blocked';\n const isProceedingState = blocker.state === 'proceeding';\n\n useEffect(() => {\n if (isBlocked) {\n window.addEventListener('beforeunload', handleRouteChange);\n } else {\n window.removeEventListener('beforeunload', handleRouteChange);\n }\n\n return (): void => {\n window.removeEventListener('beforeunload', handleRouteChange);\n };\n }, [blocker, isBlocked, isBlockedState]);\n\n const handleDiscardChanges = (): void => blocker.proceed?.();\n const handleCancel = (): void => blocker.reset?.();\n\n return (\n <DiscardChangesConfirmationDialog\n description={message}\n isOpen={isBlockedState || isProceedingState}\n onDiscardChanges={handleDiscardChanges}\n onCancel={handleCancel}\n />\n );\n}\n\n/*\n * LeaveDialog prompts the user with a confirmation dialog when they attempt to leave the page with unsaved changes.\n */\nexport function LeaveDialog({\n original,\n current,\n}: {\n original: DashboardResource | EphemeralDashboardResource | undefined;\n current: DashboardResource | EphemeralDashboardResource;\n}): ReactNode {\n const handleIsBlocked: BlockerFunction = (ctx) => {\n if (JSON.stringify(original) !== JSON.stringify(current)) {\n // Only block navigation if the pathname is changing (=> ignore search params changes)\n if (ctx.currentLocation.pathname !== ctx.nextLocation.pathname) {\n return true;\n }\n }\n return false;\n };\n\n return <Prompt isBlocked={handleIsBlocked} message=\"You have unsaved changes, are you sure you want to leave?\" />;\n}\n"],"names":["useEffect","useBlocker","DiscardChangesConfirmationDialog","handleRouteChange","event","preventDefault","returnValue","Prompt","isBlocked","message","blocker","isBlockedState","state","isProceedingState","window","addEventListener","removeEventListener","handleDiscardChanges","proceed","handleCancel","reset","description","isOpen","onDiscardChanges","onCancel","LeaveDialog","original","current","handleIsBlocked","ctx","JSON","stringify","currentLocation","pathname","nextLocation"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAGjC,SAAkCA,SAAS,QAAQ,QAAQ;AAC3D,SAASC,UAAU,QAAQ,mBAAmB;AAC9C,SAASC,gCAAgC,QAAQ,yBAAyB;AAG1E,MAAMC,oBAAoB,CAACC;IACzBA,MAAMC,cAAc;IACpBD,MAAME,WAAW,GAAG,IAAI,sBAAsB;IAC9C,OAAO,IAAI,8BAA8B;AAC3C;AAOA;;;CAGC,GACD,OAAO,SAASC,OAAO,EAAEC,SAAS,EAAEC,OAAO,EAAoB;IAC7D,MAAMC,UAAUT,WAAWO;IAC3B,MAAMG,iBAAiBD,QAAQE,KAAK,KAAK;IACzC,MAAMC,oBAAoBH,QAAQE,KAAK,KAAK;IAE5CZ,UAAU;QACR,IAAIQ,WAAW;YACbM,OAAOC,gBAAgB,CAAC,gBAAgBZ;QAC1C,OAAO;YACLW,OAAOE,mBAAmB,CAAC,gBAAgBb;QAC7C;QAEA,OAAO;YACLW,OAAOE,mBAAmB,CAAC,gBAAgBb;QAC7C;IACF,GAAG;QAACO;QAASF;QAAWG;KAAe;IAEvC,MAAMM,uBAAuB,IAAYP,QAAQQ,OAAO;IACxD,MAAMC,eAAe,IAAYT,QAAQU,KAAK;IAE9C,qBACE,KAAClB;QACCmB,aAAaZ;QACba,QAAQX,kBAAkBE;QAC1BU,kBAAkBN;QAClBO,UAAUL;;AAGhB;AAEA;;CAEC,GACD,OAAO,SAASM,YAAY,EAC1BC,QAAQ,EACRC,OAAO,EAIR;IACC,MAAMC,kBAAmC,CAACC;QACxC,IAAIC,KAAKC,SAAS,CAACL,cAAcI,KAAKC,SAAS,CAACJ,UAAU;YACxD,sFAAsF;YACtF,IAAIE,IAAIG,eAAe,CAACC,QAAQ,KAAKJ,IAAIK,YAAY,CAACD,QAAQ,EAAE;gBAC9D,OAAO;YACT;QACF;QACA,OAAO;IACT;IAEA,qBAAO,KAAC1B;QAAOC,WAAWoB;QAAiBnB,SAAQ;;AACrD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/LeaveDialog/index.ts"],"names":[],"mappings":"AAaA,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Copyright 2025 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
export * from './LeaveDialog';
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/LeaveDialog/index.ts"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport * from './LeaveDialog';\n"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,cAAc,gBAAgB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
export declare const HeaderIconButton: import("@emotion/styled").StyledComponent<import("@mui/material").IconButtonOwnProps & Omit<import("@mui/material").ButtonBaseOwnProps, "classes"> & import("@mui/material/OverridableComponent").CommonProps & Omit<Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
|
|
3
3
|
ref?: ((instance: HTMLButtonElement | null) => void) | import("react").RefObject<HTMLButtonElement> | null | undefined;
|
|
4
|
-
}, "
|
|
4
|
+
}, "color" | "children" | "className" | "style" | "classes" | "action" | "centerRipple" | "disabled" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "onFocusVisible" | "sx" | "tabIndex" | "TouchRippleProps" | "touchRippleRef" | "disableFocusRipple" | "loading" | "loadingIndicator" | "size" | "edge"> & import("@mui/system").MUIStyledCommonProps<import("@mui/material").Theme>, {}, {}>;
|
|
5
5
|
//# sourceMappingURL=HeaderIconButton.d.ts.map
|
|
@@ -9,6 +9,7 @@ export interface PanelProps extends CardProps<'section'> {
|
|
|
9
9
|
editHandlers?: PanelHeaderProps['editHandlers'];
|
|
10
10
|
panelOptions?: PanelOptions;
|
|
11
11
|
panelGroupItemId?: PanelGroupItemId;
|
|
12
|
+
viewQueriesHandler?: PanelHeaderProps['viewQueriesHandler'];
|
|
12
13
|
}
|
|
13
14
|
export type PanelOptions = {
|
|
14
15
|
/**
|
|
@@ -16,6 +17,11 @@ export type PanelOptions = {
|
|
|
16
17
|
* This can be useful in embedded mode for example.
|
|
17
18
|
*/
|
|
18
19
|
hideHeader?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Whether to show panel icons always, or only when hovering over the panel.
|
|
22
|
+
* Default: if the dashboard is in editing mode or the panel is in fullscreen mode: 'always', otherwise 'hover'
|
|
23
|
+
*/
|
|
24
|
+
showIcons?: 'always' | 'hover';
|
|
19
25
|
/**
|
|
20
26
|
* Content to render in right of the panel header. (top right of the panel)
|
|
21
27
|
* It will only be rendered when the panel is in edit mode.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Panel.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/Panel.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAqB,SAAS,EAAE,MAAM,eAAe,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAsC,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAe,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,WAAW,UAAW,SAAQ,SAAS,CAAC,SAAS,CAAC;IACtD,UAAU,EAAE,eAAe,CAAC;IAC5B,YAAY,CAAC,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAChD,YAAY,CAAC,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAChD,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"Panel.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/Panel.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAqB,SAAS,EAAE,MAAM,eAAe,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAsC,MAAM,OAAO,CAAC;AAEtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAe,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,WAAW,UAAW,SAAQ,SAAS,CAAC,SAAS,CAAC;IACtD,UAAU,EAAE,eAAe,CAAC;IAC5B,YAAY,CAAC,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAChD,YAAY,CAAC,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAChD,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,kBAAkB,CAAC,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,CAAC;CAC7D;AAED,MAAM,MAAM,YAAY,GAAG;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC/B;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,SAAS,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;OAEG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,kDAyMhB,CAAC"}
|
|
@@ -26,7 +26,7 @@ import { PanelHeader } from './PanelHeader';
|
|
|
26
26
|
* <PanelContent> // renders loading, error or panel based on the queries' status
|
|
27
27
|
* <PanelPluginLoader> // loads a panel plugin from the plugin registry and renders the PanelComponent with data from props.queryResults
|
|
28
28
|
*/ export const Panel = /*#__PURE__*/ memo(function Panel(props) {
|
|
29
|
-
const { definition, readHandlers, editHandlers, onMouseEnter, onMouseLeave, sx, panelOptions, panelGroupItemId, ...others } = props;
|
|
29
|
+
const { definition, readHandlers, editHandlers, onMouseEnter, onMouseLeave, sx, panelOptions, panelGroupItemId, viewQueriesHandler, ...others } = props;
|
|
30
30
|
// Make sure we have an ID we can use for aria attributes
|
|
31
31
|
const generatedPanelId = useId('Panel');
|
|
32
32
|
const headerId = `${generatedPanelId}-header`;
|
|
@@ -134,6 +134,8 @@ import { PanelHeader } from './PanelHeader';
|
|
|
134
134
|
const handleMouseLeave = (e)=>{
|
|
135
135
|
onMouseLeave?.(e);
|
|
136
136
|
};
|
|
137
|
+
// default value for showIcons: if the dashboard is in editing mode or the panel is in fullscreen mode: 'always', otherwise 'hover'
|
|
138
|
+
const showIcons = panelOptions?.showIcons ?? (editHandlers || readHandlers?.isPanelViewed ? 'always' : 'hover');
|
|
137
139
|
return /*#__PURE__*/ _jsxs(Card, {
|
|
138
140
|
component: "section",
|
|
139
141
|
sx: combineSx({
|
|
@@ -164,11 +166,14 @@ import { PanelHeader } from './PanelHeader';
|
|
|
164
166
|
queryResults: queryResults,
|
|
165
167
|
readHandlers: readHandlers,
|
|
166
168
|
editHandlers: editHandlers,
|
|
169
|
+
viewQueriesHandler: viewQueriesHandler,
|
|
167
170
|
links: definition.spec.links,
|
|
168
171
|
pluginActions: pluginActions,
|
|
172
|
+
showIcons: showIcons,
|
|
169
173
|
sx: {
|
|
170
174
|
paddingX: `${chartsTheme.container.padding.default}px`
|
|
171
|
-
}
|
|
175
|
+
},
|
|
176
|
+
dimension: contentDimensions
|
|
172
177
|
}),
|
|
173
178
|
/*#__PURE__*/ _jsx(CardContent, {
|
|
174
179
|
component: "figure",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Panel/Panel.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Card, CardContent, CardProps } from '@mui/material';\nimport { ErrorAlert, ErrorBoundary, combineSx, useChartsTheme, useId } from '@perses-dev/components';\nimport { PanelDefinition } from '@perses-dev/core';\nimport { useDataQueriesContext, usePluginRegistry } from '@perses-dev/plugin-system';\nimport { ReactNode, memo, useMemo, useState, useEffect } from 'react';\nimport useResizeObserver from 'use-resize-observer';\nimport { PanelGroupItemId } from '../../context';\nimport { PanelContent } from './PanelContent';\nimport { PanelHeader, PanelHeaderProps } from './PanelHeader';\n\nexport interface PanelProps extends CardProps<'section'> {\n definition: PanelDefinition;\n readHandlers?: PanelHeaderProps['readHandlers'];\n editHandlers?: PanelHeaderProps['editHandlers'];\n panelOptions?: PanelOptions;\n panelGroupItemId?: PanelGroupItemId;\n}\n\nexport type PanelOptions = {\n /**\n * Allow you to hide the panel header if desired.\n * This can be useful in embedded mode for example.\n */\n hideHeader?: boolean;\n /**\n * Content to render in right of the panel header. (top right of the panel)\n * It will only be rendered when the panel is in edit mode.\n */\n extra?: (props: PanelExtraProps) => ReactNode;\n};\n\nexport type PanelExtraProps = {\n /**\n * The PanelDefinition for the panel.\n */\n panelDefinition?: PanelDefinition;\n /**\n * The PanelGroupItemId for the panel.\n */\n panelGroupItemId?: PanelGroupItemId;\n};\n\n/**\n * Renders a PanelDefinition's content inside of a Card.\n *\n * Internal structure:\n * <Panel> // renders an entire panel, incl. header and action buttons\n * <PanelContent> // renders loading, error or panel based on the queries' status\n * <PanelPluginLoader> // loads a panel plugin from the plugin registry and renders the PanelComponent with data from props.queryResults\n */\nexport const Panel = memo(function Panel(props: PanelProps) {\n const {\n definition,\n readHandlers,\n editHandlers,\n onMouseEnter,\n onMouseLeave,\n sx,\n panelOptions,\n panelGroupItemId,\n ...others\n } = props;\n\n // Make sure we have an ID we can use for aria attributes\n const generatedPanelId = useId('Panel');\n const headerId = `${generatedPanelId}-header`;\n\n const [contentElement, setContentElement] = useState<HTMLElement | null>(null);\n\n const { width, height } = useResizeObserver({ ref: contentElement });\n\n const contentDimensions = useMemo(() => {\n if (width === undefined || height === undefined) return undefined;\n return { width, height };\n }, [width, height]);\n\n const chartsTheme = useChartsTheme();\n\n const { queryResults } = useDataQueriesContext();\n const { getPlugin } = usePluginRegistry();\n\n const panelPropsForActions = useMemo(() => {\n return {\n spec: definition.spec.plugin.spec,\n queryResults: queryResults.map((query) => ({\n definition: query.definition,\n data: query.data,\n })),\n contentDimensions,\n definition,\n };\n }, [definition, contentDimensions, queryResults]);\n\n // Load plugin actions from the plugin\n const [pluginActions, setPluginActions] = useState<ReactNode[]>([]);\n\n useEffect(() => {\n let cancelled = false;\n\n const loadPluginActions = async (): Promise<void> => {\n const panelPluginKind = definition.spec.plugin.kind;\n const panelProps = panelPropsForActions;\n\n if (!panelPluginKind || !panelProps) {\n if (!cancelled) {\n setPluginActions([]);\n }\n return;\n }\n\n try {\n // Add defensive check for getPlugin availability\n if (!getPlugin || typeof getPlugin !== 'function') {\n if (!cancelled) {\n setPluginActions([]);\n }\n return;\n }\n\n const plugin = await getPlugin('Panel', panelPluginKind);\n\n if (cancelled) return;\n\n // More defensive checking for plugin and actions\n if (\n !plugin ||\n typeof plugin !== 'object' ||\n !plugin.actions ||\n !Array.isArray(plugin.actions) ||\n plugin.actions.length === 0\n ) {\n if (!cancelled) {\n setPluginActions([]);\n }\n return;\n }\n\n // Render plugin actions in header location\n const headerActions = plugin.actions\n .filter((action) => !action.location || action.location === 'header')\n .map((action, index): ReactNode | null => {\n const ActionComponent = action.component;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return <ActionComponent key={`plugin-action-${index}`} {...(panelProps as any)} />;\n } catch (error) {\n console.warn(`Failed to render plugin action ${index}:`, error);\n return null;\n }\n })\n .filter((item): item is ReactNode => Boolean(item));\n\n if (!cancelled) {\n setPluginActions(headerActions);\n }\n } catch (error) {\n if (!cancelled) {\n console.warn('Failed to load plugin actions:', error);\n setPluginActions([]);\n }\n }\n };\n\n // Use setTimeout to defer the async operation to the next tick\n const timeoutId = setTimeout(() => {\n loadPluginActions();\n }, 0);\n\n return (): void => {\n cancelled = true;\n clearTimeout(timeoutId);\n };\n }, [definition.spec.plugin.kind, panelPropsForActions, getPlugin]);\n\n const handleMouseEnter: CardProps['onMouseEnter'] = (e) => {\n onMouseEnter?.(e);\n };\n\n const handleMouseLeave: CardProps['onMouseLeave'] = (e) => {\n onMouseLeave?.(e);\n };\n\n return (\n <Card\n component=\"section\"\n sx={combineSx(\n {\n width: '100%',\n height: '100%',\n display: 'flex',\n flexFlow: 'column nowrap',\n ':hover': { '--panel-hover': 'block' },\n },\n sx\n )}\n variant=\"outlined\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n aria-labelledby={headerId}\n aria-describedby={headerId}\n data-testid=\"panel\"\n {...others}\n >\n {!panelOptions?.hideHeader && (\n <PanelHeader\n extra={panelOptions?.extra?.({ panelDefinition: definition, panelGroupItemId })}\n id={headerId}\n title={definition.spec.display.name}\n description={definition.spec.display.description}\n queryResults={queryResults}\n readHandlers={readHandlers}\n editHandlers={editHandlers}\n links={definition.spec.links}\n pluginActions={pluginActions}\n sx={{ paddingX: `${chartsTheme.container.padding.default}px` }}\n />\n )}\n <CardContent\n component=\"figure\"\n sx={{\n position: 'relative',\n overflow: 'hidden',\n flexGrow: 1,\n margin: 0,\n padding: 0,\n // Override MUI default style for last-child\n ':last-child': {\n padding: 0,\n },\n }}\n ref={setContentElement}\n >\n <ErrorBoundary FallbackComponent={ErrorAlert} resetKeys={[definition.spec, queryResults]}>\n <PanelContent\n definition={definition}\n panelPluginKind={definition.spec.plugin.kind}\n spec={definition.spec.plugin.spec}\n contentDimensions={contentDimensions}\n queryResults={queryResults}\n />\n </ErrorBoundary>\n </CardContent>\n </Card>\n );\n});\n"],"names":["Card","CardContent","ErrorAlert","ErrorBoundary","combineSx","useChartsTheme","useId","useDataQueriesContext","usePluginRegistry","memo","useMemo","useState","useEffect","useResizeObserver","PanelContent","PanelHeader","Panel","props","definition","readHandlers","editHandlers","onMouseEnter","onMouseLeave","sx","panelOptions","panelGroupItemId","others","generatedPanelId","headerId","contentElement","setContentElement","width","height","ref","contentDimensions","undefined","chartsTheme","queryResults","getPlugin","panelPropsForActions","spec","plugin","map","query","data","pluginActions","setPluginActions","cancelled","loadPluginActions","panelPluginKind","kind","panelProps","actions","Array","isArray","length","headerActions","filter","action","location","index","ActionComponent","component","error","console","warn","item","Boolean","timeoutId","setTimeout","clearTimeout","handleMouseEnter","e","handleMouseLeave","display","flexFlow","variant","aria-labelledby","aria-describedby","data-testid","hideHeader","extra","panelDefinition","id","title","name","description","links","paddingX","container","padding","default","position","overflow","flexGrow","margin","FallbackComponent","resetKeys"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,IAAI,EAAEC,WAAW,QAAmB,gBAAgB;AAC7D,SAASC,UAAU,EAAEC,aAAa,EAAEC,SAAS,EAAEC,cAAc,EAAEC,KAAK,QAAQ,yBAAyB;AAErG,SAASC,qBAAqB,EAAEC,iBAAiB,QAAQ,4BAA4B;AACrF,SAAoBC,IAAI,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,SAAS,QAAQ,QAAQ;AACtE,OAAOC,uBAAuB,sBAAsB;AAEpD,SAASC,YAAY,QAAQ,iBAAiB;AAC9C,SAASC,WAAW,QAA0B,gBAAgB;AAkC9D;;;;;;;CAOC,GACD,OAAO,MAAMC,sBAAQP,KAAK,SAASO,MAAMC,KAAiB;IACxD,MAAM,EACJC,UAAU,EACVC,YAAY,EACZC,YAAY,EACZC,YAAY,EACZC,YAAY,EACZC,EAAE,EACFC,YAAY,EACZC,gBAAgB,EAChB,GAAGC,QACJ,GAAGT;IAEJ,yDAAyD;IACzD,MAAMU,mBAAmBrB,MAAM;IAC/B,MAAMsB,WAAW,GAAGD,iBAAiB,OAAO,CAAC;IAE7C,MAAM,CAACE,gBAAgBC,kBAAkB,GAAGnB,SAA6B;IAEzE,MAAM,EAAEoB,KAAK,EAAEC,MAAM,EAAE,GAAGnB,kBAAkB;QAAEoB,KAAKJ;IAAe;IAElE,MAAMK,oBAAoBxB,QAAQ;QAChC,IAAIqB,UAAUI,aAAaH,WAAWG,WAAW,OAAOA;QACxD,OAAO;YAAEJ;YAAOC;QAAO;IACzB,GAAG;QAACD;QAAOC;KAAO;IAElB,MAAMI,cAAc/B;IAEpB,MAAM,EAAEgC,YAAY,EAAE,GAAG9B;IACzB,MAAM,EAAE+B,SAAS,EAAE,GAAG9B;IAEtB,MAAM+B,uBAAuB7B,QAAQ;QACnC,OAAO;YACL8B,MAAMtB,WAAWsB,IAAI,CAACC,MAAM,CAACD,IAAI;YACjCH,cAAcA,aAAaK,GAAG,CAAC,CAACC,QAAW,CAAA;oBACzCzB,YAAYyB,MAAMzB,UAAU;oBAC5B0B,MAAMD,MAAMC,IAAI;gBAClB,CAAA;YACAV;YACAhB;QACF;IACF,GAAG;QAACA;QAAYgB;QAAmBG;KAAa;IAEhD,sCAAsC;IACtC,MAAM,CAACQ,eAAeC,iBAAiB,GAAGnC,SAAsB,EAAE;IAElEC,UAAU;QACR,IAAImC,YAAY;QAEhB,MAAMC,oBAAoB;YACxB,MAAMC,kBAAkB/B,WAAWsB,IAAI,CAACC,MAAM,CAACS,IAAI;YACnD,MAAMC,aAAaZ;YAEnB,IAAI,CAACU,mBAAmB,CAACE,YAAY;gBACnC,IAAI,CAACJ,WAAW;oBACdD,iBAAiB,EAAE;gBACrB;gBACA;YACF;YAEA,IAAI;gBACF,iDAAiD;gBACjD,IAAI,CAACR,aAAa,OAAOA,cAAc,YAAY;oBACjD,IAAI,CAACS,WAAW;wBACdD,iBAAiB,EAAE;oBACrB;oBACA;gBACF;gBAEA,MAAML,SAAS,MAAMH,UAAU,SAASW;gBAExC,IAAIF,WAAW;gBAEf,iDAAiD;gBACjD,IACE,CAACN,UACD,OAAOA,WAAW,YAClB,CAACA,OAAOW,OAAO,IACf,CAACC,MAAMC,OAAO,CAACb,OAAOW,OAAO,KAC7BX,OAAOW,OAAO,CAACG,MAAM,KAAK,GAC1B;oBACA,IAAI,CAACR,WAAW;wBACdD,iBAAiB,EAAE;oBACrB;oBACA;gBACF;gBAEA,2CAA2C;gBAC3C,MAAMU,gBAAgBf,OAAOW,OAAO,CACjCK,MAAM,CAAC,CAACC,SAAW,CAACA,OAAOC,QAAQ,IAAID,OAAOC,QAAQ,KAAK,UAC3DjB,GAAG,CAAC,CAACgB,QAAQE;oBACZ,MAAMC,kBAAkBH,OAAOI,SAAS;oBACxC,IAAI;wBACF,8DAA8D;wBAC9D,qBAAO,KAACD;4BAAgD,GAAIV,UAAU;2BAAzC,CAAC,cAAc,EAAES,OAAO;oBACvD,EAAE,OAAOG,OAAO;wBACdC,QAAQC,IAAI,CAAC,CAAC,+BAA+B,EAAEL,MAAM,CAAC,CAAC,EAAEG;wBACzD,OAAO;oBACT;gBACF,GACCN,MAAM,CAAC,CAACS,OAA4BC,QAAQD;gBAE/C,IAAI,CAACnB,WAAW;oBACdD,iBAAiBU;gBACnB;YACF,EAAE,OAAOO,OAAO;gBACd,IAAI,CAAChB,WAAW;oBACdiB,QAAQC,IAAI,CAAC,kCAAkCF;oBAC/CjB,iBAAiB,EAAE;gBACrB;YACF;QACF;QAEA,+DAA+D;QAC/D,MAAMsB,YAAYC,WAAW;YAC3BrB;QACF,GAAG;QAEH,OAAO;YACLD,YAAY;YACZuB,aAAaF;QACf;IACF,GAAG;QAAClD,WAAWsB,IAAI,CAACC,MAAM,CAACS,IAAI;QAAEX;QAAsBD;KAAU;IAEjE,MAAMiC,mBAA8C,CAACC;QACnDnD,eAAemD;IACjB;IAEA,MAAMC,mBAA8C,CAACD;QACnDlD,eAAekD;IACjB;IAEA,qBACE,MAACxE;QACC8D,WAAU;QACVvC,IAAInB,UACF;YACE2B,OAAO;YACPC,QAAQ;YACR0C,SAAS;YACTC,UAAU;YACV,UAAU;gBAAE,iBAAiB;YAAQ;QACvC,GACApD;QAEFqD,SAAQ;QACRvD,cAAckD;QACdjD,cAAcmD;QACdI,mBAAiBjD;QACjBkD,oBAAkBlD;QAClBmD,eAAY;QACX,GAAGrD,MAAM;;YAET,CAACF,cAAcwD,4BACd,KAACjE;gBACCkE,OAAOzD,cAAcyD,QAAQ;oBAAEC,iBAAiBhE;oBAAYO;gBAAiB;gBAC7E0D,IAAIvD;gBACJwD,OAAOlE,WAAWsB,IAAI,CAACkC,OAAO,CAACW,IAAI;gBACnCC,aAAapE,WAAWsB,IAAI,CAACkC,OAAO,CAACY,WAAW;gBAChDjD,cAAcA;gBACdlB,cAAcA;gBACdC,cAAcA;gBACdmE,OAAOrE,WAAWsB,IAAI,CAAC+C,KAAK;gBAC5B1C,eAAeA;gBACftB,IAAI;oBAAEiE,UAAU,GAAGpD,YAAYqD,SAAS,CAACC,OAAO,CAACC,OAAO,CAAC,EAAE,CAAC;gBAAC;;0BAGjE,KAAC1F;gBACC6D,WAAU;gBACVvC,IAAI;oBACFqE,UAAU;oBACVC,UAAU;oBACVC,UAAU;oBACVC,QAAQ;oBACRL,SAAS;oBACT,4CAA4C;oBAC5C,eAAe;wBACbA,SAAS;oBACX;gBACF;gBACAzD,KAAKH;0BAEL,cAAA,KAAC3B;oBAAc6F,mBAAmB9F;oBAAY+F,WAAW;wBAAC/E,WAAWsB,IAAI;wBAAEH;qBAAa;8BACtF,cAAA,KAACvB;wBACCI,YAAYA;wBACZ+B,iBAAiB/B,WAAWsB,IAAI,CAACC,MAAM,CAACS,IAAI;wBAC5CV,MAAMtB,WAAWsB,IAAI,CAACC,MAAM,CAACD,IAAI;wBACjCN,mBAAmBA;wBACnBG,cAAcA;;;;;;AAM1B,GAAG"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Panel/Panel.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Card, CardContent, CardProps } from '@mui/material';\nimport { ErrorAlert, ErrorBoundary, combineSx, useChartsTheme, useId } from '@perses-dev/components';\nimport { PanelDefinition } from '@perses-dev/core';\nimport { useDataQueriesContext, usePluginRegistry } from '@perses-dev/plugin-system';\nimport { ReactNode, memo, useMemo, useState, useEffect } from 'react';\nimport useResizeObserver from 'use-resize-observer';\nimport { PanelGroupItemId } from '../../context';\nimport { PanelContent } from './PanelContent';\nimport { PanelHeader, PanelHeaderProps } from './PanelHeader';\n\nexport interface PanelProps extends CardProps<'section'> {\n definition: PanelDefinition;\n readHandlers?: PanelHeaderProps['readHandlers'];\n editHandlers?: PanelHeaderProps['editHandlers'];\n panelOptions?: PanelOptions;\n panelGroupItemId?: PanelGroupItemId;\n viewQueriesHandler?: PanelHeaderProps['viewQueriesHandler'];\n}\n\nexport type PanelOptions = {\n /**\n * Allow you to hide the panel header if desired.\n * This can be useful in embedded mode for example.\n */\n hideHeader?: boolean;\n /**\n * Whether to show panel icons always, or only when hovering over the panel.\n * Default: if the dashboard is in editing mode or the panel is in fullscreen mode: 'always', otherwise 'hover'\n */\n showIcons?: 'always' | 'hover';\n /**\n * Content to render in right of the panel header. (top right of the panel)\n * It will only be rendered when the panel is in edit mode.\n */\n extra?: (props: PanelExtraProps) => ReactNode;\n};\n\nexport type PanelExtraProps = {\n /**\n * The PanelDefinition for the panel.\n */\n panelDefinition?: PanelDefinition;\n /**\n * The PanelGroupItemId for the panel.\n */\n panelGroupItemId?: PanelGroupItemId;\n};\n\n/**\n * Renders a PanelDefinition's content inside of a Card.\n *\n * Internal structure:\n * <Panel> // renders an entire panel, incl. header and action buttons\n * <PanelContent> // renders loading, error or panel based on the queries' status\n * <PanelPluginLoader> // loads a panel plugin from the plugin registry and renders the PanelComponent with data from props.queryResults\n */\nexport const Panel = memo(function Panel(props: PanelProps) {\n const {\n definition,\n readHandlers,\n editHandlers,\n onMouseEnter,\n onMouseLeave,\n sx,\n panelOptions,\n panelGroupItemId,\n viewQueriesHandler,\n ...others\n } = props;\n\n // Make sure we have an ID we can use for aria attributes\n const generatedPanelId = useId('Panel');\n const headerId = `${generatedPanelId}-header`;\n\n const [contentElement, setContentElement] = useState<HTMLElement | null>(null);\n\n const { width, height } = useResizeObserver({ ref: contentElement });\n\n const contentDimensions = useMemo(() => {\n if (width === undefined || height === undefined) return undefined;\n return { width, height };\n }, [width, height]);\n\n const chartsTheme = useChartsTheme();\n\n const { queryResults } = useDataQueriesContext();\n const { getPlugin } = usePluginRegistry();\n\n const panelPropsForActions = useMemo(() => {\n return {\n spec: definition.spec.plugin.spec,\n queryResults: queryResults.map((query) => ({\n definition: query.definition,\n data: query.data,\n })),\n contentDimensions,\n definition,\n };\n }, [definition, contentDimensions, queryResults]);\n\n // Load plugin actions from the plugin\n const [pluginActions, setPluginActions] = useState<ReactNode[]>([]);\n\n useEffect(() => {\n let cancelled = false;\n\n const loadPluginActions = async (): Promise<void> => {\n const panelPluginKind = definition.spec.plugin.kind;\n const panelProps = panelPropsForActions;\n\n if (!panelPluginKind || !panelProps) {\n if (!cancelled) {\n setPluginActions([]);\n }\n return;\n }\n\n try {\n // Add defensive check for getPlugin availability\n if (!getPlugin || typeof getPlugin !== 'function') {\n if (!cancelled) {\n setPluginActions([]);\n }\n return;\n }\n\n const plugin = await getPlugin('Panel', panelPluginKind);\n\n if (cancelled) return;\n\n // More defensive checking for plugin and actions\n if (\n !plugin ||\n typeof plugin !== 'object' ||\n !plugin.actions ||\n !Array.isArray(plugin.actions) ||\n plugin.actions.length === 0\n ) {\n if (!cancelled) {\n setPluginActions([]);\n }\n return;\n }\n\n // Render plugin actions in header location\n const headerActions = plugin.actions\n .filter((action) => !action.location || action.location === 'header')\n .map((action, index): ReactNode | null => {\n const ActionComponent = action.component;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return <ActionComponent key={`plugin-action-${index}`} {...(panelProps as any)} />;\n } catch (error) {\n console.warn(`Failed to render plugin action ${index}:`, error);\n return null;\n }\n })\n .filter((item): item is ReactNode => Boolean(item));\n\n if (!cancelled) {\n setPluginActions(headerActions);\n }\n } catch (error) {\n if (!cancelled) {\n console.warn('Failed to load plugin actions:', error);\n setPluginActions([]);\n }\n }\n };\n\n // Use setTimeout to defer the async operation to the next tick\n const timeoutId = setTimeout(() => {\n loadPluginActions();\n }, 0);\n\n return (): void => {\n cancelled = true;\n clearTimeout(timeoutId);\n };\n }, [definition.spec.plugin.kind, panelPropsForActions, getPlugin]);\n\n const handleMouseEnter: CardProps['onMouseEnter'] = (e) => {\n onMouseEnter?.(e);\n };\n\n const handleMouseLeave: CardProps['onMouseLeave'] = (e) => {\n onMouseLeave?.(e);\n };\n\n // default value for showIcons: if the dashboard is in editing mode or the panel is in fullscreen mode: 'always', otherwise 'hover'\n const showIcons = panelOptions?.showIcons ?? (editHandlers || readHandlers?.isPanelViewed ? 'always' : 'hover');\n\n return (\n <Card\n component=\"section\"\n sx={combineSx(\n {\n width: '100%',\n height: '100%',\n display: 'flex',\n flexFlow: 'column nowrap',\n ':hover': { '--panel-hover': 'block' },\n },\n sx\n )}\n variant=\"outlined\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n aria-labelledby={headerId}\n aria-describedby={headerId}\n data-testid=\"panel\"\n {...others}\n >\n {!panelOptions?.hideHeader && (\n <PanelHeader\n extra={panelOptions?.extra?.({ panelDefinition: definition, panelGroupItemId })}\n id={headerId}\n title={definition.spec.display.name}\n description={definition.spec.display.description}\n queryResults={queryResults}\n readHandlers={readHandlers}\n editHandlers={editHandlers}\n viewQueriesHandler={viewQueriesHandler}\n links={definition.spec.links}\n pluginActions={pluginActions}\n showIcons={showIcons}\n sx={{ paddingX: `${chartsTheme.container.padding.default}px` }}\n dimension={contentDimensions}\n />\n )}\n <CardContent\n component=\"figure\"\n sx={{\n position: 'relative',\n overflow: 'hidden',\n flexGrow: 1,\n margin: 0,\n padding: 0,\n // Override MUI default style for last-child\n ':last-child': {\n padding: 0,\n },\n }}\n ref={setContentElement}\n >\n <ErrorBoundary FallbackComponent={ErrorAlert} resetKeys={[definition.spec, queryResults]}>\n <PanelContent\n definition={definition}\n panelPluginKind={definition.spec.plugin.kind}\n spec={definition.spec.plugin.spec}\n contentDimensions={contentDimensions}\n queryResults={queryResults}\n />\n </ErrorBoundary>\n </CardContent>\n </Card>\n );\n});\n"],"names":["Card","CardContent","ErrorAlert","ErrorBoundary","combineSx","useChartsTheme","useId","useDataQueriesContext","usePluginRegistry","memo","useMemo","useState","useEffect","useResizeObserver","PanelContent","PanelHeader","Panel","props","definition","readHandlers","editHandlers","onMouseEnter","onMouseLeave","sx","panelOptions","panelGroupItemId","viewQueriesHandler","others","generatedPanelId","headerId","contentElement","setContentElement","width","height","ref","contentDimensions","undefined","chartsTheme","queryResults","getPlugin","panelPropsForActions","spec","plugin","map","query","data","pluginActions","setPluginActions","cancelled","loadPluginActions","panelPluginKind","kind","panelProps","actions","Array","isArray","length","headerActions","filter","action","location","index","ActionComponent","component","error","console","warn","item","Boolean","timeoutId","setTimeout","clearTimeout","handleMouseEnter","e","handleMouseLeave","showIcons","isPanelViewed","display","flexFlow","variant","aria-labelledby","aria-describedby","data-testid","hideHeader","extra","panelDefinition","id","title","name","description","links","paddingX","container","padding","default","dimension","position","overflow","flexGrow","margin","FallbackComponent","resetKeys"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { QueryData } from '@perses-dev/plugin-system';
|
|
3
3
|
import { Link } from '@perses-dev/core';
|
|
4
|
+
import { PanelOptions } from './Panel';
|
|
4
5
|
export interface PanelActionsProps {
|
|
5
6
|
title: string;
|
|
6
7
|
description?: string;
|
|
@@ -16,8 +17,12 @@ export interface PanelActionsProps {
|
|
|
16
17
|
isPanelViewed?: boolean;
|
|
17
18
|
onViewPanelClick: () => void;
|
|
18
19
|
};
|
|
20
|
+
viewQueriesHandler?: {
|
|
21
|
+
onClick: () => void;
|
|
22
|
+
};
|
|
19
23
|
queryResults: QueryData[];
|
|
20
24
|
pluginActions?: ReactNode[];
|
|
25
|
+
showIcons: PanelOptions['showIcons'];
|
|
21
26
|
}
|
|
22
27
|
export declare const PanelActions: React.FC<PanelActionsProps>;
|
|
23
28
|
//# sourceMappingURL=PanelActions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelActions.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelActions.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAqC,SAAS,EAAqB,MAAM,OAAO,CAAC;AAExF,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"PanelActions.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelActions.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAqC,SAAS,EAAqB,MAAM,OAAO,CAAC;AAExF,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAWtD,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAUxC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,YAAY,CAAC,EAAE;QACb,gBAAgB,EAAE,MAAM,IAAI,CAAC;QAC7B,qBAAqB,EAAE,MAAM,IAAI,CAAC;QAClC,kBAAkB,EAAE,MAAM,IAAI,CAAC;KAChC,CAAC;IACF,YAAY,CAAC,EAAE;QACb,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,gBAAgB,EAAE,MAAM,IAAI,CAAC;KAC9B,CAAC;IACF,kBAAkB,CAAC,EAAE;QACnB,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,CAAC;IACF,YAAY,EAAE,SAAS,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;IAC5B,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACtC;AASD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA6NpD,CAAC"}
|
|
@@ -14,6 +14,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
14
14
|
import { Stack, Box, Popover, CircularProgress, styled } from '@mui/material';
|
|
15
15
|
import { isValidElement, useMemo, useState } from 'react';
|
|
16
16
|
import { InfoTooltip } from '@perses-dev/components';
|
|
17
|
+
import DatabaseSearch from 'mdi-material-ui/DatabaseSearch';
|
|
17
18
|
import ArrowCollapseIcon from 'mdi-material-ui/ArrowCollapse';
|
|
18
19
|
import ArrowExpandIcon from 'mdi-material-ui/ArrowExpand';
|
|
19
20
|
import PencilIcon from 'mdi-material-ui/PencilOutline';
|
|
@@ -32,7 +33,7 @@ const ConditionalBox = styled(Box)({
|
|
|
32
33
|
flexGrow: 1,
|
|
33
34
|
justifyContent: 'flex-end'
|
|
34
35
|
});
|
|
35
|
-
export const PanelActions = ({ editHandlers, readHandlers, extra, title, description, descriptionTooltipId, links, queryResults, pluginActions = [] })=>{
|
|
36
|
+
export const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, extra, title, description, descriptionTooltipId, links, queryResults, pluginActions = [], showIcons })=>{
|
|
36
37
|
const descriptionAction = useMemo(()=>{
|
|
37
38
|
if (description && description.trim().length > 0) {
|
|
38
39
|
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
@@ -109,6 +110,23 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
109
110
|
readHandlers,
|
|
110
111
|
title
|
|
111
112
|
]);
|
|
113
|
+
const viewQueryAction = useMemo(()=>{
|
|
114
|
+
if (!viewQueriesHandler?.onClick) return null;
|
|
115
|
+
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
116
|
+
description: TOOLTIP_TEXT.queryView,
|
|
117
|
+
children: /*#__PURE__*/ _jsx(HeaderIconButton, {
|
|
118
|
+
"aria-label": ARIA_LABEL_TEXT.openQueryView(title),
|
|
119
|
+
size: "small",
|
|
120
|
+
onClick: viewQueriesHandler.onClick,
|
|
121
|
+
children: /*#__PURE__*/ _jsx(DatabaseSearch, {
|
|
122
|
+
fontSize: "inherit"
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
}, [
|
|
127
|
+
viewQueriesHandler,
|
|
128
|
+
title
|
|
129
|
+
]);
|
|
112
130
|
const editActions = useMemo(()=>{
|
|
113
131
|
if (editHandlers !== undefined) {
|
|
114
132
|
// If there are edit handlers, always just show the edit buttons
|
|
@@ -188,8 +206,8 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
188
206
|
flexGrow: 1
|
|
189
207
|
}
|
|
190
208
|
});
|
|
191
|
-
// if the panel is in non-editing, non-fullscreen mode
|
|
192
|
-
const OnHover = ({ children })=>
|
|
209
|
+
// By default, the panel header shows certain icons only on hover if the panel is in non-editing, non-fullscreen mode
|
|
210
|
+
const OnHover = ({ children })=>showIcons === 'hover' ? /*#__PURE__*/ _jsx(Box, {
|
|
193
211
|
sx: {
|
|
194
212
|
display: 'var(--panel-hover, none)'
|
|
195
213
|
},
|
|
@@ -220,12 +238,13 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
220
238
|
" ",
|
|
221
239
|
extraActions,
|
|
222
240
|
" ",
|
|
241
|
+
viewQueryAction,
|
|
223
242
|
readActions,
|
|
224
243
|
" ",
|
|
244
|
+
pluginActions,
|
|
225
245
|
editActions
|
|
226
246
|
]
|
|
227
247
|
}),
|
|
228
|
-
pluginActions,
|
|
229
248
|
moveAction
|
|
230
249
|
]
|
|
231
250
|
})
|
|
@@ -251,13 +270,16 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
251
270
|
/*#__PURE__*/ _jsxs(OnHover, {
|
|
252
271
|
children: [
|
|
253
272
|
extraActions,
|
|
254
|
-
" ",
|
|
255
273
|
readActions,
|
|
256
|
-
|
|
257
|
-
pluginActions,
|
|
258
|
-
/*#__PURE__*/ _jsx(OverflowMenu, {
|
|
274
|
+
/*#__PURE__*/ _jsxs(OverflowMenu, {
|
|
259
275
|
title: title,
|
|
260
|
-
children:
|
|
276
|
+
children: [
|
|
277
|
+
editActions,
|
|
278
|
+
" ",
|
|
279
|
+
viewQueryAction,
|
|
280
|
+
" ",
|
|
281
|
+
pluginActions
|
|
282
|
+
]
|
|
261
283
|
}),
|
|
262
284
|
moveAction
|
|
263
285
|
]
|
|
@@ -286,13 +308,14 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
286
308
|
/*#__PURE__*/ _jsxs(OnHover, {
|
|
287
309
|
children: [
|
|
288
310
|
extraActions,
|
|
289
|
-
|
|
311
|
+
viewQueryAction,
|
|
290
312
|
readActions,
|
|
291
313
|
" ",
|
|
292
|
-
pluginActions,
|
|
293
|
-
" ",
|
|
294
314
|
editActions,
|
|
295
|
-
|
|
315
|
+
pluginActions.length <= 1 ? pluginActions : /*#__PURE__*/ _jsx(OverflowMenu, {
|
|
316
|
+
title: title,
|
|
317
|
+
children: pluginActions
|
|
318
|
+
}),
|
|
296
319
|
moveAction
|
|
297
320
|
]
|
|
298
321
|
})
|
|
@@ -306,7 +329,7 @@ const OverflowMenu = ({ children, title })=>{
|
|
|
306
329
|
// do not show overflow menu if there is no content (for example, edit actions are hidden)
|
|
307
330
|
const hasContent = /*#__PURE__*/ isValidElement(children) || Array.isArray(children) && children.some(isValidElement);
|
|
308
331
|
if (!hasContent) {
|
|
309
|
-
return
|
|
332
|
+
return null;
|
|
310
333
|
}
|
|
311
334
|
const handleClick = (event)=>{
|
|
312
335
|
setAnchorPosition(event.currentTarget.getBoundingClientRect());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Panel/PanelActions.tsx"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Stack, Box, Popover, CircularProgress, styled, PopoverPosition } from '@mui/material';\nimport { isValidElement, PropsWithChildren, ReactNode, useMemo, useState } from 'react';\nimport { InfoTooltip } from '@perses-dev/components';\nimport { QueryData } from '@perses-dev/plugin-system';\nimport ArrowCollapseIcon from 'mdi-material-ui/ArrowCollapse';\nimport ArrowExpandIcon from 'mdi-material-ui/ArrowExpand';\nimport PencilIcon from 'mdi-material-ui/PencilOutline';\nimport DeleteIcon from 'mdi-material-ui/DeleteOutline';\nimport DragIcon from 'mdi-material-ui/DragVertical';\nimport ContentCopyIcon from 'mdi-material-ui/ContentCopy';\nimport MenuIcon from 'mdi-material-ui/Menu';\nimport AlertIcon from 'mdi-material-ui/Alert';\nimport InformationOutlineIcon from 'mdi-material-ui/InformationOutline';\nimport { Link } from '@perses-dev/core';\nimport {\n ARIA_LABEL_TEXT,\n HEADER_ACTIONS_CONTAINER_NAME,\n HEADER_MEDIUM_WIDTH,\n HEADER_SMALL_WIDTH,\n TOOLTIP_TEXT,\n} from '../../constants';\nimport { HeaderIconButton } from './HeaderIconButton';\nimport { PanelLinks } from './PanelLinks';\n\nexport interface PanelActionsProps {\n title: string;\n description?: string;\n descriptionTooltipId: string;\n links?: Link[];\n extra?: React.ReactNode;\n editHandlers?: {\n onEditPanelClick: () => void;\n onDuplicatePanelClick: () => void;\n onDeletePanelClick: () => void;\n };\n readHandlers?: {\n isPanelViewed?: boolean;\n onViewPanelClick: () => void;\n };\n queryResults: QueryData[];\n pluginActions?: ReactNode[];\n}\n\nconst ConditionalBox = styled(Box)({\n display: 'none',\n alignItems: 'center',\n flexGrow: 1,\n justifyContent: 'flex-end',\n});\n\nexport const PanelActions: React.FC<PanelActionsProps> = ({\n editHandlers,\n readHandlers,\n extra,\n title,\n description,\n descriptionTooltipId,\n links,\n queryResults,\n pluginActions = [],\n}) => {\n const descriptionAction = useMemo((): ReactNode | undefined => {\n if (description && description.trim().length > 0) {\n return (\n <InfoTooltip id={descriptionTooltipId} description={description} enterDelay={100}>\n <HeaderIconButton aria-label=\"panel description\" size=\"small\">\n <InformationOutlineIcon\n aria-describedby=\"info-tooltip\"\n aria-hidden={false}\n fontSize=\"inherit\"\n sx={{ color: (theme) => theme.palette.text.secondary }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [descriptionTooltipId, description]);\n\n const linksAction = links && links.length > 0 && <PanelLinks links={links} />;\n const extraActions = editHandlers === undefined && extra;\n\n const queryStateIndicator = useMemo((): ReactNode | undefined => {\n const hasData = queryResults.some((q) => q.data);\n const isFetching = queryResults.some((q) => q.isFetching);\n const queryErrors = queryResults.filter((q) => q.error);\n\n if (isFetching && hasData) {\n return <CircularProgress aria-label=\"loading\" size=\"1.125rem\" />;\n } else if (queryErrors.length > 0) {\n const errorTexts = queryErrors\n .map((q) => q.error)\n .map((e: any) => e?.message ?? e?.toString() ?? 'Unknown error') // eslint-disable-line @typescript-eslint/no-explicit-any\n .join('\\n');\n\n return (\n <InfoTooltip description={errorTexts}>\n <HeaderIconButton aria-label=\"panel errors\" size=\"small\">\n <AlertIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n }, [queryResults]);\n\n const readActions = useMemo((): ReactNode | undefined => {\n if (readHandlers !== undefined) {\n return (\n <InfoTooltip description={TOOLTIP_TEXT.viewPanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.viewPanel(title)}\n size=\"small\"\n onClick={readHandlers.onViewPanelClick}\n >\n {readHandlers.isPanelViewed ? (\n <ArrowCollapseIcon fontSize=\"inherit\" />\n ) : (\n <ArrowExpandIcon fontSize=\"inherit\" />\n )}\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [readHandlers, title]);\n\n const editActions = useMemo((): ReactNode | undefined => {\n if (editHandlers !== undefined) {\n // If there are edit handlers, always just show the edit buttons\n return (\n <>\n <InfoTooltip description={TOOLTIP_TEXT.editPanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.editPanel(title)}\n size=\"small\"\n onClick={editHandlers.onEditPanelClick}\n >\n <PencilIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n <InfoTooltip description={TOOLTIP_TEXT.duplicatePanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.duplicatePanel(title)}\n size=\"small\"\n onClick={editHandlers.onDuplicatePanelClick}\n >\n <ContentCopyIcon\n fontSize=\"inherit\"\n sx={{\n // Shrink this icon a little bit to look more consistent\n // with the other icons in the header.\n transform: 'scale(0.925)',\n }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n <InfoTooltip description={TOOLTIP_TEXT.deletePanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.deletePanel(title)}\n size=\"small\"\n onClick={editHandlers.onDeletePanelClick}\n >\n <DeleteIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n </>\n );\n }\n return undefined;\n }, [editHandlers, title]);\n\n const moveAction = useMemo((): ReactNode | undefined => {\n if (editActions && !readHandlers?.isPanelViewed) {\n return (\n <InfoTooltip description={TOOLTIP_TEXT.movePanel}>\n <HeaderIconButton aria-label={ARIA_LABEL_TEXT.movePanel(title)} size=\"small\">\n <DragIcon className=\"drag-handle\" sx={{ cursor: 'grab' }} fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [editActions, readHandlers, title]);\n\n const divider = <Box sx={{ flexGrow: 1 }}></Box>;\n\n // if the panel is in non-editing, non-fullscreen mode, show certain icons only on hover\n const OnHover = ({ children }: PropsWithChildren): ReactNode =>\n editHandlers === undefined && !readHandlers?.isPanelViewed ? (\n <Box sx={{ display: 'var(--panel-hover, none)' }}>{children}</Box>\n ) : (\n <>{children}</>\n );\n\n return (\n <>\n {/* small panel width: move all icons except move/grab to overflow menu */}\n <ConditionalBox\n sx={(theme) => ({\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).between(0, HEADER_SMALL_WIDTH)]: { display: 'flex' },\n })}\n >\n {divider}\n <OnHover>\n <OverflowMenu title={title}>\n {descriptionAction} {linksAction} {queryStateIndicator} {extraActions} {readActions} {editActions}\n </OverflowMenu>\n {pluginActions}\n {moveAction}\n </OnHover>\n </ConditionalBox>\n\n {/* medium panel width: move edit icons to overflow menu */}\n <ConditionalBox\n sx={(theme) => ({\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).between(HEADER_SMALL_WIDTH, HEADER_MEDIUM_WIDTH)]: {\n display: 'flex',\n },\n })}\n >\n <OnHover>\n {descriptionAction} {linksAction}\n </OnHover>\n {divider} {queryStateIndicator}\n <OnHover>\n {extraActions} {readActions} {pluginActions}\n <OverflowMenu title={title}>{editActions}</OverflowMenu>\n {moveAction}\n </OnHover>\n </ConditionalBox>\n\n {/* large panel width: show all icons in panel header */}\n <ConditionalBox\n sx={(theme) => ({\n // flip the logic here; if the browser (or jsdom) does not support container queries, always show all icons\n display: 'flex',\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).down(HEADER_MEDIUM_WIDTH)]: { display: 'none' },\n })}\n >\n <OnHover>\n {descriptionAction} {linksAction}\n </OnHover>\n {divider} {queryStateIndicator}\n <OnHover>\n {extraActions} {readActions} {pluginActions} {editActions} {moveAction}\n </OnHover>\n </ConditionalBox>\n </>\n );\n};\n\nconst OverflowMenu: React.FC<PropsWithChildren<{ title: string }>> = ({ children, title }) => {\n const [anchorPosition, setAnchorPosition] = useState<PopoverPosition>();\n\n // do not show overflow menu if there is no content (for example, edit actions are hidden)\n const hasContent = isValidElement(children) || (Array.isArray(children) && children.some(isValidElement));\n if (!hasContent) {\n return undefined;\n }\n\n const handleClick = (event: React.MouseEvent<HTMLElement>): void => {\n setAnchorPosition(event.currentTarget.getBoundingClientRect());\n };\n\n const handleClose = (): void => {\n setAnchorPosition(undefined);\n };\n\n const open = Boolean(anchorPosition);\n const id = open ? 'actions-menu' : undefined;\n\n return (\n <>\n <HeaderIconButton\n className=\"show-actions\"\n aria-describedby={id}\n onClick={handleClick}\n aria-label={ARIA_LABEL_TEXT.showPanelActions(title)}\n size=\"small\"\n >\n <MenuIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n <Popover\n id={id}\n open={open}\n anchorReference=\"anchorPosition\"\n anchorPosition={anchorPosition}\n onClose={handleClose}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n >\n <Stack direction=\"row\" alignItems=\"center\" sx={{ padding: 1 }} onClick={handleClose}>\n {children}\n </Stack>\n </Popover>\n </>\n );\n};\n"],"names":["Stack","Box","Popover","CircularProgress","styled","isValidElement","useMemo","useState","InfoTooltip","ArrowCollapseIcon","ArrowExpandIcon","PencilIcon","DeleteIcon","DragIcon","ContentCopyIcon","MenuIcon","AlertIcon","InformationOutlineIcon","ARIA_LABEL_TEXT","HEADER_ACTIONS_CONTAINER_NAME","HEADER_MEDIUM_WIDTH","HEADER_SMALL_WIDTH","TOOLTIP_TEXT","HeaderIconButton","PanelLinks","ConditionalBox","display","alignItems","flexGrow","justifyContent","PanelActions","editHandlers","readHandlers","extra","title","description","descriptionTooltipId","links","queryResults","pluginActions","descriptionAction","trim","length","id","enterDelay","aria-label","size","aria-describedby","aria-hidden","fontSize","sx","color","theme","palette","text","secondary","undefined","linksAction","extraActions","queryStateIndicator","hasData","some","q","data","isFetching","queryErrors","filter","error","errorTexts","map","e","message","toString","join","readActions","viewPanel","onClick","onViewPanelClick","isPanelViewed","editActions","editPanel","onEditPanelClick","duplicatePanel","onDuplicatePanelClick","transform","deletePanel","onDeletePanelClick","moveAction","movePanel","className","cursor","divider","OnHover","children","containerQueries","between","OverflowMenu","down","anchorPosition","setAnchorPosition","hasContent","Array","isArray","handleClick","event","currentTarget","getBoundingClientRect","handleClose","open","Boolean","showPanelActions","anchorReference","onClose","anchorOrigin","vertical","horizontal","direction","padding"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,KAAK,EAAEC,GAAG,EAAEC,OAAO,EAAEC,gBAAgB,EAAEC,MAAM,QAAyB,gBAAgB;AAC/F,SAASC,cAAc,EAAgCC,OAAO,EAAEC,QAAQ,QAAQ,QAAQ;AACxF,SAASC,WAAW,QAAQ,yBAAyB;AAErD,OAAOC,uBAAuB,gCAAgC;AAC9D,OAAOC,qBAAqB,8BAA8B;AAC1D,OAAOC,gBAAgB,gCAAgC;AACvD,OAAOC,gBAAgB,gCAAgC;AACvD,OAAOC,cAAc,+BAA+B;AACpD,OAAOC,qBAAqB,8BAA8B;AAC1D,OAAOC,cAAc,uBAAuB;AAC5C,OAAOC,eAAe,wBAAwB;AAC9C,OAAOC,4BAA4B,qCAAqC;AAExE,SACEC,eAAe,EACfC,6BAA6B,EAC7BC,mBAAmB,EACnBC,kBAAkB,EAClBC,YAAY,QACP,kBAAkB;AACzB,SAASC,gBAAgB,QAAQ,qBAAqB;AACtD,SAASC,UAAU,QAAQ,eAAe;AAqB1C,MAAMC,iBAAiBrB,OAAOH,KAAK;IACjCyB,SAAS;IACTC,YAAY;IACZC,UAAU;IACVC,gBAAgB;AAClB;AAEA,OAAO,MAAMC,eAA4C,CAAC,EACxDC,YAAY,EACZC,YAAY,EACZC,KAAK,EACLC,KAAK,EACLC,WAAW,EACXC,oBAAoB,EACpBC,KAAK,EACLC,YAAY,EACZC,gBAAgB,EAAE,EACnB;IACC,MAAMC,oBAAoBlC,QAAQ;QAChC,IAAI6B,eAAeA,YAAYM,IAAI,GAAGC,MAAM,GAAG,GAAG;YAChD,qBACE,KAAClC;gBAAYmC,IAAIP;gBAAsBD,aAAaA;gBAAaS,YAAY;0BAC3E,cAAA,KAACrB;oBAAiBsB,cAAW;oBAAoBC,MAAK;8BACpD,cAAA,KAAC7B;wBACC8B,oBAAiB;wBACjBC,eAAa;wBACbC,UAAS;wBACTC,IAAI;4BAAEC,OAAO,CAACC,QAAUA,MAAMC,OAAO,CAACC,IAAI,CAACC,SAAS;wBAAC;;;;QAK/D;QACA,OAAOC;IACT,GAAG;QAACpB;QAAsBD;KAAY;IAEtC,MAAMsB,cAAcpB,SAASA,MAAMK,MAAM,GAAG,mBAAK,KAAClB;QAAWa,OAAOA;;IACpE,MAAMqB,eAAe3B,iBAAiByB,aAAavB;IAEnD,MAAM0B,sBAAsBrD,QAAQ;QAClC,MAAMsD,UAAUtB,aAAauB,IAAI,CAAC,CAACC,IAAMA,EAAEC,IAAI;QAC/C,MAAMC,aAAa1B,aAAauB,IAAI,CAAC,CAACC,IAAMA,EAAEE,UAAU;QACxD,MAAMC,cAAc3B,aAAa4B,MAAM,CAAC,CAACJ,IAAMA,EAAEK,KAAK;QAEtD,IAAIH,cAAcJ,SAAS;YACzB,qBAAO,KAACzD;gBAAiB0C,cAAW;gBAAUC,MAAK;;QACrD,OAAO,IAAImB,YAAYvB,MAAM,GAAG,GAAG;YACjC,MAAM0B,aAAaH,YAChBI,GAAG,CAAC,CAACP,IAAMA,EAAEK,KAAK,EAClBE,GAAG,CAAC,CAACC,IAAWA,GAAGC,WAAWD,GAAGE,cAAc,iBAAiB,yDAAyD;aACzHC,IAAI,CAAC;YAER,qBACE,KAACjE;gBAAY2B,aAAaiC;0BACxB,cAAA,KAAC7C;oBAAiBsB,cAAW;oBAAeC,MAAK;8BAC/C,cAAA,KAAC9B;wBAAUiC,UAAS;;;;QAI5B;IACF,GAAG;QAACX;KAAa;IAEjB,MAAMoC,cAAcpE,QAAQ;QAC1B,IAAI0B,iBAAiBwB,WAAW;YAC9B,qBACE,KAAChD;gBAAY2B,aAAab,aAAaqD,SAAS;0BAC9C,cAAA,KAACpD;oBACCsB,cAAY3B,gBAAgByD,SAAS,CAACzC;oBACtCY,MAAK;oBACL8B,SAAS5C,aAAa6C,gBAAgB;8BAErC7C,aAAa8C,aAAa,iBACzB,KAACrE;wBAAkBwC,UAAS;uCAE5B,KAACvC;wBAAgBuC,UAAS;;;;QAKpC;QACA,OAAOO;IACT,GAAG;QAACxB;QAAcE;KAAM;IAExB,MAAM6C,cAAczE,QAAQ;QAC1B,IAAIyB,iBAAiByB,WAAW;YAC9B,gEAAgE;YAChE,qBACE;;kCACE,KAAChD;wBAAY2B,aAAab,aAAa0D,SAAS;kCAC9C,cAAA,KAACzD;4BACCsB,cAAY3B,gBAAgB8D,SAAS,CAAC9C;4BACtCY,MAAK;4BACL8B,SAAS7C,aAAakD,gBAAgB;sCAEtC,cAAA,KAACtE;gCAAWsC,UAAS;;;;kCAGzB,KAACzC;wBAAY2B,aAAab,aAAa4D,cAAc;kCACnD,cAAA,KAAC3D;4BACCsB,cAAY3B,gBAAgBgE,cAAc,CAAChD;4BAC3CY,MAAK;4BACL8B,SAAS7C,aAAaoD,qBAAqB;sCAE3C,cAAA,KAACrE;gCACCmC,UAAS;gCACTC,IAAI;oCACF,wDAAwD;oCACxD,sCAAsC;oCACtCkC,WAAW;gCACb;;;;kCAIN,KAAC5E;wBAAY2B,aAAab,aAAa+D,WAAW;kCAChD,cAAA,KAAC9D;4BACCsB,cAAY3B,gBAAgBmE,WAAW,CAACnD;4BACxCY,MAAK;4BACL8B,SAAS7C,aAAauD,kBAAkB;sCAExC,cAAA,KAAC1E;gCAAWqC,UAAS;;;;;;QAK/B;QACA,OAAOO;IACT,GAAG;QAACzB;QAAcG;KAAM;IAExB,MAAMqD,aAAajF,QAAQ;QACzB,IAAIyE,eAAe,CAAC/C,cAAc8C,eAAe;YAC/C,qBACE,KAACtE;gBAAY2B,aAAab,aAAakE,SAAS;0BAC9C,cAAA,KAACjE;oBAAiBsB,cAAY3B,gBAAgBsE,SAAS,CAACtD;oBAAQY,MAAK;8BACnE,cAAA,KAACjC;wBAAS4E,WAAU;wBAAcvC,IAAI;4BAAEwC,QAAQ;wBAAO;wBAAGzC,UAAS;;;;QAI3E;QACA,OAAOO;IACT,GAAG;QAACuB;QAAa/C;QAAcE;KAAM;IAErC,MAAMyD,wBAAU,KAAC1F;QAAIiD,IAAI;YAAEtB,UAAU;QAAE;;IAEvC,wFAAwF;IACxF,MAAMgE,UAAU,CAAC,EAAEC,QAAQ,EAAqB,GAC9C9D,iBAAiByB,aAAa,CAACxB,cAAc8C,8BAC3C,KAAC7E;YAAIiD,IAAI;gBAAExB,SAAS;YAA2B;sBAAImE;2BAEnD;sBAAGA;;IAGP,qBACE;;0BAEE,MAACpE;gBACCyB,IAAI,CAACE,QAAW,CAAA;wBACd,CAACA,MAAM0C,gBAAgB,CAAC3E,+BAA+B4E,OAAO,CAAC,GAAG1E,oBAAoB,EAAE;4BAAEK,SAAS;wBAAO;oBAC5G,CAAA;;oBAECiE;kCACD,MAACC;;0CACC,MAACI;gCAAa9D,OAAOA;;oCAClBM;oCAAkB;oCAAEiB;oCAAY;oCAAEE;oCAAoB;oCAAED;oCAAa;oCAAEgB;oCAAY;oCAAEK;;;4BAEvFxC;4BACAgD;;;;;0BAKL,MAAC9D;gBACCyB,IAAI,CAACE,QAAW,CAAA;wBACd,CAACA,MAAM0C,gBAAgB,CAAC3E,+BAA+B4E,OAAO,CAAC1E,oBAAoBD,qBAAqB,EAAE;4BACxGM,SAAS;wBACX;oBACF,CAAA;;kCAEA,MAACkE;;4BACEpD;4BAAkB;4BAAEiB;;;oBAEtBkC;oBAAQ;oBAAEhC;kCACX,MAACiC;;4BACElC;4BAAa;4BAAEgB;4BAAY;4BAAEnC;0CAC9B,KAACyD;gCAAa9D,OAAOA;0CAAQ6C;;4BAC5BQ;;;;;0BAKL,MAAC9D;gBACCyB,IAAI,CAACE,QAAW,CAAA;wBACd,2GAA2G;wBAC3G1B,SAAS;wBACT,CAAC0B,MAAM0C,gBAAgB,CAAC3E,+BAA+B8E,IAAI,CAAC7E,qBAAqB,EAAE;4BAAEM,SAAS;wBAAO;oBACvG,CAAA;;kCAEA,MAACkE;;4BACEpD;4BAAkB;4BAAEiB;;;oBAEtBkC;oBAAQ;oBAAEhC;kCACX,MAACiC;;4BACElC;4BAAa;4BAAEgB;4BAAY;4BAAEnC;4BAAc;4BAAEwC;4BAAY;4BAAEQ;;;;;;;AAKtE,EAAE;AAEF,MAAMS,eAA+D,CAAC,EAAEH,QAAQ,EAAE3D,KAAK,EAAE;IACvF,MAAM,CAACgE,gBAAgBC,kBAAkB,GAAG5F;IAE5C,0FAA0F;IAC1F,MAAM6F,2BAAa/F,eAAewF,aAAcQ,MAAMC,OAAO,CAACT,aAAaA,SAAShC,IAAI,CAACxD;IACzF,IAAI,CAAC+F,YAAY;QACf,OAAO5C;IACT;IAEA,MAAM+C,cAAc,CAACC;QACnBL,kBAAkBK,MAAMC,aAAa,CAACC,qBAAqB;IAC7D;IAEA,MAAMC,cAAc;QAClBR,kBAAkB3C;IACpB;IAEA,MAAMoD,OAAOC,QAAQX;IACrB,MAAMvD,KAAKiE,OAAO,iBAAiBpD;IAEnC,qBACE;;0BACE,KAACjC;gBACCkE,WAAU;gBACV1C,oBAAkBJ;gBAClBiC,SAAS2B;gBACT1D,cAAY3B,gBAAgB4F,gBAAgB,CAAC5E;gBAC7CY,MAAK;0BAEL,cAAA,KAAC/B;oBAASkC,UAAS;;;0BAErB,KAAC/C;gBACCyC,IAAIA;gBACJiE,MAAMA;gBACNG,iBAAgB;gBAChBb,gBAAgBA;gBAChBc,SAASL;gBACTM,cAAc;oBACZC,UAAU;oBACVC,YAAY;gBACd;0BAEA,cAAA,KAACnH;oBAAMoH,WAAU;oBAAMzF,YAAW;oBAASuB,IAAI;wBAAEmE,SAAS;oBAAE;oBAAGzC,SAAS+B;8BACrEd;;;;;AAKX"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Panel/PanelActions.tsx"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Stack, Box, Popover, CircularProgress, styled, PopoverPosition } from '@mui/material';\nimport { isValidElement, PropsWithChildren, ReactNode, useMemo, useState } from 'react';\nimport { InfoTooltip } from '@perses-dev/components';\nimport { QueryData } from '@perses-dev/plugin-system';\nimport DatabaseSearch from 'mdi-material-ui/DatabaseSearch';\nimport ArrowCollapseIcon from 'mdi-material-ui/ArrowCollapse';\nimport ArrowExpandIcon from 'mdi-material-ui/ArrowExpand';\nimport PencilIcon from 'mdi-material-ui/PencilOutline';\nimport DeleteIcon from 'mdi-material-ui/DeleteOutline';\nimport DragIcon from 'mdi-material-ui/DragVertical';\nimport ContentCopyIcon from 'mdi-material-ui/ContentCopy';\nimport MenuIcon from 'mdi-material-ui/Menu';\nimport AlertIcon from 'mdi-material-ui/Alert';\nimport InformationOutlineIcon from 'mdi-material-ui/InformationOutline';\nimport { Link } from '@perses-dev/core';\nimport {\n ARIA_LABEL_TEXT,\n HEADER_ACTIONS_CONTAINER_NAME,\n HEADER_MEDIUM_WIDTH,\n HEADER_SMALL_WIDTH,\n TOOLTIP_TEXT,\n} from '../../constants';\nimport { HeaderIconButton } from './HeaderIconButton';\nimport { PanelLinks } from './PanelLinks';\nimport { PanelOptions } from './Panel';\n\nexport interface PanelActionsProps {\n title: string;\n description?: string;\n descriptionTooltipId: string;\n links?: Link[];\n extra?: React.ReactNode;\n editHandlers?: {\n onEditPanelClick: () => void;\n onDuplicatePanelClick: () => void;\n onDeletePanelClick: () => void;\n };\n readHandlers?: {\n isPanelViewed?: boolean;\n onViewPanelClick: () => void;\n };\n viewQueriesHandler?: {\n onClick: () => void;\n };\n queryResults: QueryData[];\n pluginActions?: ReactNode[];\n showIcons: PanelOptions['showIcons'];\n}\n\nconst ConditionalBox = styled(Box)({\n display: 'none',\n alignItems: 'center',\n flexGrow: 1,\n justifyContent: 'flex-end',\n});\n\nexport const PanelActions: React.FC<PanelActionsProps> = ({\n editHandlers,\n readHandlers,\n viewQueriesHandler,\n extra,\n title,\n description,\n descriptionTooltipId,\n links,\n queryResults,\n pluginActions = [],\n showIcons,\n}) => {\n const descriptionAction = useMemo((): ReactNode | undefined => {\n if (description && description.trim().length > 0) {\n return (\n <InfoTooltip id={descriptionTooltipId} description={description} enterDelay={100}>\n <HeaderIconButton aria-label=\"panel description\" size=\"small\">\n <InformationOutlineIcon\n aria-describedby=\"info-tooltip\"\n aria-hidden={false}\n fontSize=\"inherit\"\n sx={{ color: (theme) => theme.palette.text.secondary }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [descriptionTooltipId, description]);\n\n const linksAction = links && links.length > 0 && <PanelLinks links={links} />;\n const extraActions = editHandlers === undefined && extra;\n\n const queryStateIndicator = useMemo((): ReactNode | undefined => {\n const hasData = queryResults.some((q) => q.data);\n const isFetching = queryResults.some((q) => q.isFetching);\n const queryErrors = queryResults.filter((q) => q.error);\n\n if (isFetching && hasData) {\n return <CircularProgress aria-label=\"loading\" size=\"1.125rem\" />;\n } else if (queryErrors.length > 0) {\n const errorTexts = queryErrors\n .map((q) => q.error)\n .map((e: any) => e?.message ?? e?.toString() ?? 'Unknown error') // eslint-disable-line @typescript-eslint/no-explicit-any\n .join('\\n');\n\n return (\n <InfoTooltip description={errorTexts}>\n <HeaderIconButton aria-label=\"panel errors\" size=\"small\">\n <AlertIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n }, [queryResults]);\n\n const readActions = useMemo((): ReactNode | undefined => {\n if (readHandlers !== undefined) {\n return (\n <InfoTooltip description={TOOLTIP_TEXT.viewPanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.viewPanel(title)}\n size=\"small\"\n onClick={readHandlers.onViewPanelClick}\n >\n {readHandlers.isPanelViewed ? (\n <ArrowCollapseIcon fontSize=\"inherit\" />\n ) : (\n <ArrowExpandIcon fontSize=\"inherit\" />\n )}\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [readHandlers, title]);\n\n const viewQueryAction = useMemo(() => {\n if (!viewQueriesHandler?.onClick) return null;\n return (\n <InfoTooltip description={TOOLTIP_TEXT.queryView}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.openQueryView(title)}\n size=\"small\"\n onClick={viewQueriesHandler.onClick}\n >\n <DatabaseSearch fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }, [viewQueriesHandler, title]);\n\n const editActions = useMemo((): ReactNode | undefined => {\n if (editHandlers !== undefined) {\n // If there are edit handlers, always just show the edit buttons\n return (\n <>\n <InfoTooltip description={TOOLTIP_TEXT.editPanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.editPanel(title)}\n size=\"small\"\n onClick={editHandlers.onEditPanelClick}\n >\n <PencilIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n <InfoTooltip description={TOOLTIP_TEXT.duplicatePanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.duplicatePanel(title)}\n size=\"small\"\n onClick={editHandlers.onDuplicatePanelClick}\n >\n <ContentCopyIcon\n fontSize=\"inherit\"\n sx={{\n // Shrink this icon a little bit to look more consistent\n // with the other icons in the header.\n transform: 'scale(0.925)',\n }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n <InfoTooltip description={TOOLTIP_TEXT.deletePanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.deletePanel(title)}\n size=\"small\"\n onClick={editHandlers.onDeletePanelClick}\n >\n <DeleteIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n </>\n );\n }\n return undefined;\n }, [editHandlers, title]);\n\n const moveAction = useMemo((): ReactNode | undefined => {\n if (editActions && !readHandlers?.isPanelViewed) {\n return (\n <InfoTooltip description={TOOLTIP_TEXT.movePanel}>\n <HeaderIconButton aria-label={ARIA_LABEL_TEXT.movePanel(title)} size=\"small\">\n <DragIcon className=\"drag-handle\" sx={{ cursor: 'grab' }} fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [editActions, readHandlers, title]);\n\n const divider = <Box sx={{ flexGrow: 1 }}></Box>;\n\n // By default, the panel header shows certain icons only on hover if the panel is in non-editing, non-fullscreen mode\n const OnHover = ({ children }: PropsWithChildren): ReactNode =>\n showIcons === 'hover' ? <Box sx={{ display: 'var(--panel-hover, none)' }}>{children}</Box> : <>{children}</>;\n\n return (\n <>\n {/* small panel width: move all icons except move/grab to overflow menu */}\n <ConditionalBox\n sx={(theme) => ({\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).between(0, HEADER_SMALL_WIDTH)]: { display: 'flex' },\n })}\n >\n {divider}\n <OnHover>\n <OverflowMenu title={title}>\n {descriptionAction} {linksAction} {queryStateIndicator} {extraActions} {viewQueryAction}\n {readActions} {pluginActions}\n {editActions}\n </OverflowMenu>\n {moveAction}\n </OnHover>\n </ConditionalBox>\n\n {/* medium panel width: move edit icons to overflow menu */}\n <ConditionalBox\n sx={(theme) => ({\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).between(HEADER_SMALL_WIDTH, HEADER_MEDIUM_WIDTH)]: {\n display: 'flex',\n },\n })}\n >\n <OnHover>\n {descriptionAction} {linksAction}\n </OnHover>\n {divider} {queryStateIndicator}\n <OnHover>\n {extraActions}\n {readActions}\n <OverflowMenu title={title}>\n {editActions} {viewQueryAction} {pluginActions}\n </OverflowMenu>\n {moveAction}\n </OnHover>\n </ConditionalBox>\n\n {/* large panel width: show all icons in panel header */}\n <ConditionalBox\n sx={(theme) => ({\n // flip the logic here; if the browser (or jsdom) does not support container queries, always show all icons\n display: 'flex',\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).down(HEADER_MEDIUM_WIDTH)]: { display: 'none' },\n })}\n >\n <OnHover>\n {descriptionAction} {linksAction}\n </OnHover>\n {divider} {queryStateIndicator}\n <OnHover>\n {extraActions}\n {viewQueryAction}\n {readActions} {editActions}\n {/* Show plugin actions inside a menu if it gets crowded */}\n {pluginActions.length <= 1 ? pluginActions : <OverflowMenu title={title}>{pluginActions}</OverflowMenu>}\n {moveAction}\n </OnHover>\n </ConditionalBox>\n </>\n );\n};\n\nconst OverflowMenu: React.FC<PropsWithChildren<{ title: string }>> = ({ children, title }) => {\n const [anchorPosition, setAnchorPosition] = useState<PopoverPosition>();\n\n // do not show overflow menu if there is no content (for example, edit actions are hidden)\n const hasContent = isValidElement(children) || (Array.isArray(children) && children.some(isValidElement));\n if (!hasContent) {\n return null;\n }\n\n const handleClick = (event: React.MouseEvent<HTMLElement>): void => {\n setAnchorPosition(event.currentTarget.getBoundingClientRect());\n };\n\n const handleClose = (): void => {\n setAnchorPosition(undefined);\n };\n\n const open = Boolean(anchorPosition);\n const id = open ? 'actions-menu' : undefined;\n\n return (\n <>\n <HeaderIconButton\n className=\"show-actions\"\n aria-describedby={id}\n onClick={handleClick}\n aria-label={ARIA_LABEL_TEXT.showPanelActions(title)}\n size=\"small\"\n >\n <MenuIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n <Popover\n id={id}\n open={open}\n anchorReference=\"anchorPosition\"\n anchorPosition={anchorPosition}\n onClose={handleClose}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n >\n <Stack direction=\"row\" alignItems=\"center\" sx={{ padding: 1 }} onClick={handleClose}>\n {children}\n </Stack>\n </Popover>\n </>\n );\n};\n"],"names":["Stack","Box","Popover","CircularProgress","styled","isValidElement","useMemo","useState","InfoTooltip","DatabaseSearch","ArrowCollapseIcon","ArrowExpandIcon","PencilIcon","DeleteIcon","DragIcon","ContentCopyIcon","MenuIcon","AlertIcon","InformationOutlineIcon","ARIA_LABEL_TEXT","HEADER_ACTIONS_CONTAINER_NAME","HEADER_MEDIUM_WIDTH","HEADER_SMALL_WIDTH","TOOLTIP_TEXT","HeaderIconButton","PanelLinks","ConditionalBox","display","alignItems","flexGrow","justifyContent","PanelActions","editHandlers","readHandlers","viewQueriesHandler","extra","title","description","descriptionTooltipId","links","queryResults","pluginActions","showIcons","descriptionAction","trim","length","id","enterDelay","aria-label","size","aria-describedby","aria-hidden","fontSize","sx","color","theme","palette","text","secondary","undefined","linksAction","extraActions","queryStateIndicator","hasData","some","q","data","isFetching","queryErrors","filter","error","errorTexts","map","e","message","toString","join","readActions","viewPanel","onClick","onViewPanelClick","isPanelViewed","viewQueryAction","queryView","openQueryView","editActions","editPanel","onEditPanelClick","duplicatePanel","onDuplicatePanelClick","transform","deletePanel","onDeletePanelClick","moveAction","movePanel","className","cursor","divider","OnHover","children","containerQueries","between","OverflowMenu","down","anchorPosition","setAnchorPosition","hasContent","Array","isArray","handleClick","event","currentTarget","getBoundingClientRect","handleClose","open","Boolean","showPanelActions","anchorReference","onClose","anchorOrigin","vertical","horizontal","direction","padding"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { Link } from '@perses-dev/core';
|
|
|
3
3
|
import { QueryData } from '@perses-dev/plugin-system';
|
|
4
4
|
import { ReactElement, ReactNode } from 'react';
|
|
5
5
|
import { PanelActionsProps } from './PanelActions';
|
|
6
|
+
import { PanelOptions } from './Panel';
|
|
6
7
|
type OmittedProps = 'children' | 'action' | 'title' | 'disableTypography';
|
|
7
8
|
export interface PanelHeaderProps extends Omit<CardHeaderProps, OmittedProps> {
|
|
8
9
|
id: string;
|
|
@@ -11,10 +12,15 @@ export interface PanelHeaderProps extends Omit<CardHeaderProps, OmittedProps> {
|
|
|
11
12
|
links?: Link[];
|
|
12
13
|
extra?: ReactNode;
|
|
13
14
|
queryResults: QueryData[];
|
|
15
|
+
viewQueriesHandler?: PanelActionsProps['viewQueriesHandler'];
|
|
14
16
|
readHandlers?: PanelActionsProps['readHandlers'];
|
|
15
17
|
editHandlers?: PanelActionsProps['editHandlers'];
|
|
16
18
|
pluginActions?: ReactNode[];
|
|
19
|
+
showIcons: PanelOptions['showIcons'];
|
|
20
|
+
dimension?: {
|
|
21
|
+
width: number;
|
|
22
|
+
};
|
|
17
23
|
}
|
|
18
|
-
export declare function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, pluginActions, ...rest }: PanelHeaderProps): ReactElement;
|
|
24
|
+
export declare function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, pluginActions, showIcons, viewQueriesHandler, dimension, ...rest }: PanelHeaderProps): ReactElement;
|
|
19
25
|
export {};
|
|
20
26
|
//# sourceMappingURL=PanelHeader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelHeader.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelHeader.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAc,eAAe,
|
|
1
|
+
{"version":3,"file":"PanelHeader.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelHeader.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAc,eAAe,EAA8B,MAAM,eAAe,CAAC;AAExF,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,SAAS,EAA+B,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,SAAS,EAA+B,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAgB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,KAAK,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,mBAAmB,CAAC;AAE1E,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC;IAC3E,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,SAAS,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;IAC7D,YAAY,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACjD,YAAY,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACjD,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;IAC5B,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/B;AAED,wBAAgB,WAAW,CAAC,EAC1B,EAAE,EACF,KAAK,EAAE,QAAQ,EACf,WAAW,EAAE,cAAc,EAC3B,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,EAAE,EACF,KAAK,EACL,aAAa,EACb,SAAS,EACT,kBAAkB,EAClB,SAAS,EACT,GAAG,IAAI,EACR,EAAE,gBAAgB,GAAG,YAAY,CAyEjC"}
|