@parca/profile 0.16.109 → 0.16.111

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/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.16.111](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.109...@parca/profile@0.16.111) (2023-02-09)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.16.110](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.109...@parca/profile@0.16.110) (2023-02-08)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## 0.16.109 (2023-02-08)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -59,10 +59,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
59
59
  // See the License for the specific language governing permissions and
60
60
  // limitations under the License.
61
61
  import { useState, useEffect, useRef } from 'react';
62
+ import cx from 'classnames';
62
63
  import graphviz from 'graphviz-wasm';
63
64
  import * as d3 from 'd3';
64
65
  import { Stage, Layer, Rect, Arrow, Text, Label } from 'react-konva';
65
- import { Button } from '@parca/components';
66
+ import { Button, useURLState } from '@parca/components';
66
67
  import { jsonToDot, getCurvePoints } from './utils';
67
68
  import { isSearchMatch, selectQueryParam } from '@parca/functions';
68
69
  import Tooltip from '../GraphTooltip';
@@ -109,6 +110,8 @@ var Callgraph = function (_a) {
109
110
  var rawNodes = graph.nodes, total = graph.cumulative;
110
111
  var currentSearchString = (_b = selectQueryParam('search_string')) !== null && _b !== void 0 ? _b : '';
111
112
  var isSearchEmpty = currentSearchString === undefined || currentSearchString === '';
113
+ var rawDashboardItems = useURLState({ param: 'dashboard_items' })[0];
114
+ var dashboardItems = rawDashboardItems;
112
115
  useEffect(function () {
113
116
  var getDataWithPositions = function () { return __awaiter(void 0, void 0, void 0, function () {
114
117
  var dataAsDot, jsonGraph;
@@ -218,6 +221,6 @@ var Callgraph = function (_a) {
218
221
  ? true
219
222
  : isSearchMatch(currentSearchString, node.functionName);
220
223
  return (_jsx(Node, { node: node, hoveredNode: hoveredNode, setHoveredNode: setHoveredNode, isCurrentSearchMatch: isCurrentSearchMatch }, "node-".concat(node._gvid)));
221
- })] })) })), _jsx(Tooltip, { hoveringNode: rawNodes.find(function (n) { return n.id === (hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.data.id); }), unit: sampleUnit, total: +total, isFixed: false, x: (_c = hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.mouseX) !== null && _c !== void 0 ? _c : 0, y: (_d = hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.mouseY) !== null && _d !== void 0 ? _d : 0, contextElement: containerRef.current }), stage.scale.x !== 1 && (_jsx(Button, __assign({ className: "w-auto !absolute top-0 left-0", variant: "neutral", onClick: resetZoom }, { children: "Reset Zoom" })))] })) })));
224
+ })] })) })), _jsx(Tooltip, { hoveringNode: rawNodes.find(function (n) { return n.id === (hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.data.id); }), unit: sampleUnit, total: +total, isFixed: false, x: (_c = hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.mouseX) !== null && _c !== void 0 ? _c : 0, y: (_d = hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.mouseY) !== null && _d !== void 0 ? _d : 0, contextElement: containerRef.current }), stage.scale.x !== 1 && (_jsx("div", __assign({ className: cx(dashboardItems.length > 1 ? 'left-[25px]' : 'left-0', 'w-auto absolute top-[-46px]') }, { children: _jsx(Button, __assign({ variant: "neutral", onClick: resetZoom }, { children: "Reset Zoom" })) })))] })) })));
222
225
  };
223
226
  export default Callgraph;
@@ -33,6 +33,7 @@ import { IcicleNode, RowHeight } from './IcicleGraphNodes';
33
33
  import useColoredGraph from './useColoredGraph';
34
34
  import { selectQueryParam } from '@parca/functions';
35
35
  import ColorStackLegend from './ColorStackLegend';
36
+ import useUserPreference, { USER_PREFERENCES } from '@parca/functions/useUserPreference';
36
37
  export var IcicleGraph = memo(function IcicleGraph(_a) {
37
38
  var _b;
38
39
  var graph = _a.graph, width = _a.width, setCurPath = _a.setCurPath, curPath = _a.curPath, sampleUnit = _a.sampleUnit, navigateTo = _a.navigateTo, _c = _a.isTrimmed, isTrimmed = _c === void 0 ? false : _c;
@@ -48,6 +49,7 @@ export var IcicleGraph = memo(function IcicleGraph(_a) {
48
49
  var coloredGraph = useColoredGraph(graph);
49
50
  var currentSearchString = (_b = selectQueryParam('search_string')) !== null && _b !== void 0 ? _b : '';
50
51
  var compareMode = selectQueryParam('compare_a') === 'true' && selectQueryParam('compare_b') === 'true';
52
+ var colorProfileName = useUserPreference(USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key)[0];
51
53
  useEffect(function () {
52
54
  if (ref.current != null) {
53
55
  setHeight(ref === null || ref === void 0 ? void 0 : ref.current.getBoundingClientRect().height);
@@ -69,10 +71,16 @@ export var IcicleGraph = memo(function IcicleGraph(_a) {
69
71
  var rel = pointer(e);
70
72
  throttledSetPos([rel[0], rel[1]]);
71
73
  };
72
- return (_jsxs("div", __assign({ onMouseLeave: function () { return setHoveringNode(undefined); } }, { children: [_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode }), _jsx(GraphTooltip, { unit: sampleUnit, total: total, x: pos[0], y: pos[1], hoveringNode: hoveringNode, contextElement: svg.current, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function }), _jsx("div", __assign({ className: cx(dashboardItems.length > 1
73
- ? "".concat(isTrimmed ? 'top-[-54px]' : 'top-[-70px]', " left-[25px]")
74
- : isTrimmed
75
- ? 'top-[-54px]'
76
- : 'top-[-69px]', 'flex justify-start absolute ') }, { children: _jsx(Button, __assign({ color: "neutral", onClick: function () { return setCurPath([]); }, disabled: curPath.length === 0, className: "w-auto", variant: "neutral" }, { children: "Reset View" })) })), _jsx("svg", __assign({ className: "font-robotoMono", width: width, height: height, onMouseMove: onMouseMove, preserveAspectRatio: "xMinYMid", ref: svg }, { children: _jsx("g", __assign({ ref: ref }, { children: _jsx("g", __assign({ transform: 'translate(0, 0)' }, { children: _jsx(IcicleNode, { x: 0, y: 0, totalWidth: width, height: RowHeight, setCurPath: setCurPath, setHoveringNode: setHoveringNode, curPath: curPath, data: coloredGraph.root, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function, total: total, xScale: xScale, path: [], level: 0, isRoot: true, searchString: currentSearchString, compareMode: compareMode }) })) })) }))] })));
74
+ var isColorStackLegendVisible = colorProfileName !== 'default';
75
+ return (_jsxs("div", __assign({ onMouseLeave: function () { return setHoveringNode(undefined); } }, { children: [_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode }), _jsx(GraphTooltip, { unit: sampleUnit, total: total, x: pos[0], y: pos[1], hoveringNode: hoveringNode, contextElement: svg.current, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function }), _jsx("div", __assign({ className: cx('flex justify-start absolute', {
76
+ 'top-[-48px]': dashboardItems.length <= 1 && !isTrimmed && !isColorStackLegendVisible,
77
+ 'top-[-69px]': dashboardItems.length <= 1 && !isTrimmed,
78
+ 'top-[-54px]': dashboardItems.length <= 1 && isTrimmed && isColorStackLegendVisible,
79
+ 'top-[-54px] ': dashboardItems.length <= 1 && isTrimmed && !isColorStackLegendVisible,
80
+ 'top-[-54px] left-[25px]': dashboardItems.length > 1 && isTrimmed && isColorStackLegendVisible,
81
+ 'top-[-54px] left-[25px] ': dashboardItems.length > 1 && isTrimmed && !isColorStackLegendVisible,
82
+ 'top-[-70px] left-[25px]': dashboardItems.length > 1 && !isTrimmed && isColorStackLegendVisible,
83
+ 'top-[-46px] left-[25px]': dashboardItems.length > 1 && !isTrimmed && !isColorStackLegendVisible,
84
+ }) }, { children: _jsx(Button, __assign({ color: "neutral", onClick: function () { return setCurPath([]); }, disabled: curPath.length === 0, className: "w-auto", variant: "neutral" }, { children: "Reset View" })) })), _jsx("svg", __assign({ className: "font-robotoMono", width: width, height: height, onMouseMove: onMouseMove, preserveAspectRatio: "xMinYMid", ref: svg }, { children: _jsx("g", __assign({ ref: ref }, { children: _jsx("g", __assign({ transform: 'translate(0, 0)' }, { children: _jsx(IcicleNode, { x: 0, y: 0, totalWidth: width, height: RowHeight, setCurPath: setCurPath, setHoveringNode: setHoveringNode, curPath: curPath, data: coloredGraph.root, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function, total: total, xScale: xScale, path: [], level: 0, isRoot: true, searchString: currentSearchString, compareMode: compareMode }) })) })) }))] })));
77
85
  });
78
86
  export default IcicleGraph;
@@ -9,7 +9,7 @@ var __assign = (this && this.__assign) || function () {
9
9
  };
10
10
  return __assign.apply(this, arguments);
11
11
  };
12
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
12
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  // Copyright 2022 The Parca Authors
14
14
  // Licensed under the Apache License, Version 2.0 (the "License");
15
15
  // you may not use this file except in compliance with the License.
@@ -23,8 +23,8 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
23
23
  // See the License for the specific language governing permissions and
24
24
  // limitations under the License.
25
25
  import { useCallback, useMemo } from 'react';
26
- import { getLastItem, valueFormatter, isSearchMatch, parseParams, selectQueryParam, } from '@parca/functions';
27
- import { Table } from '@parca/components';
26
+ import { getLastItem, valueFormatter, isSearchMatch, parseParams } from '@parca/functions';
27
+ import { Button, Table, useURLState } from '@parca/components';
28
28
  import { createColumnHelper } from '@tanstack/react-table';
29
29
  import { hexifyAddress } from '../utils';
30
30
  import '../TopTable.styles.css';
@@ -52,8 +52,11 @@ export var TopTable = function (_a) {
52
52
  var _b;
53
53
  var top = _a.data, unit = _a.sampleUnit, navigateTo = _a.navigateTo, loading = _a.loading;
54
54
  var router = parseParams(window.location.search);
55
- var currentSearchString = selectQueryParam('search_string');
56
- var compareMode = Boolean(selectQueryParam('compare_a')) && Boolean(selectQueryParam('compare_b'));
55
+ var rawDashboardItems = useURLState({ param: 'dashboard_items' })[0];
56
+ var currentSearchString = useURLState({ param: 'search_string' })[0];
57
+ var rawcompareMode = useURLState({ param: 'compare_a' })[0];
58
+ var compareMode = rawcompareMode === undefined ? false : rawcompareMode === 'true';
59
+ var dashboardItems = rawDashboardItems;
57
60
  var columns = useMemo(function () {
58
61
  var cols = [
59
62
  columnHelper.accessor('meta', {
@@ -107,13 +110,17 @@ export var TopTable = function (_a) {
107
110
  }
108
111
  }, [navigateTo, router]);
109
112
  var onRowClick = useCallback(function (row) {
113
+ // If there is only one dashboard item, we don't want to select a span
114
+ if (dashboardItems.length <= 1) {
115
+ return;
116
+ }
110
117
  var meta = row.meta;
111
118
  if (meta === undefined) {
112
119
  return;
113
120
  }
114
121
  var name = RowLabel(meta);
115
122
  selectSpan(name);
116
- }, [selectSpan]);
123
+ }, [selectSpan, dashboardItems.length]);
117
124
  var shouldHighlightRow = useCallback(function (row) {
118
125
  var meta = row.meta;
119
126
  if (meta === undefined)
@@ -124,12 +131,17 @@ export var TopTable = function (_a) {
124
131
  var enableHighlighting = useMemo(function () {
125
132
  return currentSearchString != null && (currentSearchString === null || currentSearchString === void 0 ? void 0 : currentSearchString.length) > 0;
126
133
  }, [currentSearchString]);
134
+ var clearSelection = useCallback(function () {
135
+ if (navigateTo != null) {
136
+ navigateTo('/', __assign(__assign({}, router), { search_string: '' }), { replace: true });
137
+ }
138
+ }, [navigateTo, router]);
127
139
  var initialSorting = useMemo(function () {
128
140
  return [{ id: compareMode ? 'diff' : 'cumulative', desc: true }];
129
141
  }, [compareMode]);
130
142
  var total = top != null ? top.list.length : 0;
131
143
  if (total === 0 && !loading)
132
144
  return _jsx(_Fragment, { children: "Profile has no samples" });
133
- return (_jsx(_Fragment, { children: _jsx("div", __assign({ className: "w-full font-robotoMono h-[80vh] overflow-scroll" }, { children: _jsx(Table, { data: (_b = top === null || top === void 0 ? void 0 : top.list) !== null && _b !== void 0 ? _b : [], columns: columns, initialSorting: initialSorting, onRowClick: onRowClick, enableHighlighting: enableHighlighting, shouldHighlightRow: shouldHighlightRow }) })) }));
145
+ return (_jsxs("div", __assign({ className: "relative" }, { children: [dashboardItems.length > 1 && (_jsx("div", __assign({ className: "left-[25px] top-[-45px] absolute" }, { children: _jsx(Button, __assign({ color: "neutral", onClick: clearSelection, className: "w-auto", variant: "neutral", disabled: currentSearchString === undefined || currentSearchString.length === 0 }, { children: "Clear selection" })) }))), _jsx("div", __assign({ className: "w-full font-robotoMono h-[80vh] overflow-scroll" }, { children: _jsx(Table, { data: (_b = top === null || top === void 0 ? void 0 : top.list) !== null && _b !== void 0 ? _b : [], columns: columns, initialSorting: initialSorting, onRowClick: onRowClick, enableHighlighting: enableHighlighting, shouldHighlightRow: shouldHighlightRow, usePointerCursor: dashboardItems.length > 1 }) }))] })));
134
146
  };
135
147
  export default TopTable;
package/dist/styles.css CHANGED
@@ -1 +1 @@
1
- /*! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.invisible{visibility:hidden}.\!absolute{position:absolute!important}.absolute{position:absolute}.relative{position:relative}.top-0{top:0}.left-0{left:0}.right-0{right:0}.top-\[-54px\]{top:-54px}.top-\[-70px\]{top:-70px}.left-\[25px\]{left:25px}.top-\[-69px\]{top:-69px}.z-50{z-index:50}.z-10{z-index:10}.m-auto{margin:auto}.m-0{margin:0}.m-2{margin:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-20{margin-bottom:5rem;margin-top:5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.mr-3{margin-right:.75rem}.ml-2{margin-left:.5rem}.mr-6{margin-right:1.5rem}.mt-2{margin-top:.5rem}.mt-1{margin-top:.25rem}.ml-auto{margin-left:auto}.mb-2{margin-bottom:.5rem}.mr-1{margin-right:.25rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.table{display:table}.grid{display:grid}.h-36{height:9rem}.h-1{height:.25rem}.h-\[80vh\]{height:80vh}.h-4{height:1rem}.max-h-\[400px\]{max-height:400px}.w-auto{width:auto}.w-1\/5{width:20%}.w-4\/5{width:80%}.w-full{width:100%}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-40{width:10rem}.w-2\/5{width:40%}.w-1\/2{width:50%}.w-8{width:2rem}.w-4{width:1rem}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.min-w-\[300px\]{min-width:300px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.translate-y-1{--tw-translate-y:0.25rem}.translate-y-0,.translate-y-1{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y:0px}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-1{gap:.25rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.25rem*var(--tw-space-x-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded-lg{border-radius:.5rem}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-l{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.rounded-r{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.border{border-width:1px}.border-r-0{border-right-width:0}.border-l-0{border-left-width:0}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.p-3{padding:.75rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-1{padding:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-20{padding-bottom:5rem;padding-top:5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pt-2{padding-top:.5rem}.pb-4{padding-bottom:1rem}.pr-2{padding-right:.5rem}.pl-2{padding-left:.5rem}.pb-2{padding-bottom:.5rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-90{opacity:.9}.opacity-100{opacity:1}.opacity-0{opacity:0}.opacity-50{opacity:.5}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.blur{--tw-blur:blur(8px)}.blur,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-150{transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-indigo-800:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(55 48 163/var(--tw-ring-opacity))}[class~=theme-dark] .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}[class~=theme-dark] .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}[class~=theme-dark] .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}
1
+ /*! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.invisible{visibility:hidden}.absolute{position:absolute}.relative{position:relative}.left-\[25px\]{left:25px}.left-0{left:0}.top-\[-46px\]{top:-46px}.right-0{right:0}.top-\[-45px\]{top:-45px}.top-\[-48px\]{top:-48px}.top-\[-69px\]{top:-69px}.top-\[-54px\]{top:-54px}.top-\[-70px\]{top:-70px}.z-50{z-index:50}.z-10{z-index:10}.m-auto{margin:auto}.m-0{margin:0}.m-2{margin:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-20{margin-bottom:5rem;margin-top:5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.mr-3{margin-right:.75rem}.ml-2{margin-left:.5rem}.mr-6{margin-right:1.5rem}.mt-2{margin-top:.5rem}.mt-1{margin-top:.25rem}.ml-auto{margin-left:auto}.mb-2{margin-bottom:.5rem}.mr-1{margin-right:.25rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.table{display:table}.grid{display:grid}.h-36{height:9rem}.h-1{height:.25rem}.h-\[80vh\]{height:80vh}.h-4{height:1rem}.max-h-\[400px\]{max-height:400px}.w-auto{width:auto}.w-1\/5{width:20%}.w-4\/5{width:80%}.w-full{width:100%}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-40{width:10rem}.w-2\/5{width:40%}.w-1\/2{width:50%}.w-8{width:2rem}.w-4{width:1rem}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.min-w-\[300px\]{min-width:300px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.translate-y-1{--tw-translate-y:0.25rem}.translate-y-0,.translate-y-1{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y:0px}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-1{gap:.25rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.25rem*var(--tw-space-x-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded-lg{border-radius:.5rem}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-l{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.rounded-r{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.border{border-width:1px}.border-r-0{border-right-width:0}.border-l-0{border-left-width:0}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.p-3{padding:.75rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-1{padding:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-20{padding-bottom:5rem;padding-top:5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pt-2{padding-top:.5rem}.pb-4{padding-bottom:1rem}.pr-2{padding-right:.5rem}.pl-2{padding-left:.5rem}.pb-2{padding-bottom:.5rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-90{opacity:.9}.opacity-100{opacity:1}.opacity-0{opacity:0}.opacity-50{opacity:.5}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.blur{--tw-blur:blur(8px)}.blur,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-150{transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-indigo-800:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(55 48 163/var(--tw-ring-opacity))}[class~=theme-dark] .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}[class~=theme-dark] .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}[class~=theme-dark] .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.16.109",
3
+ "version": "0.16.111",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@parca/client": "^0.16.62",
7
- "@parca/components": "^0.16.91",
7
+ "@parca/components": "^0.16.93",
8
8
  "@parca/dynamicsize": "^0.16.52",
9
9
  "@parca/functions": "^0.16.60",
10
10
  "@parca/parser": "^0.16.53",
@@ -45,5 +45,5 @@
45
45
  "access": "public",
46
46
  "registry": "https://registry.npmjs.org/"
47
47
  },
48
- "gitHead": "7e9b162434159a5e614c8d7c12e360ff3069da39"
48
+ "gitHead": "5a51bfaf98ebb147ff2cfd3a90457ec4f05a9c8c"
49
49
  }
@@ -12,11 +12,12 @@
12
12
  // limitations under the License.
13
13
 
14
14
  import {useState, useEffect, useRef} from 'react';
15
+ import cx from 'classnames';
15
16
  import graphviz from 'graphviz-wasm';
16
17
  import * as d3 from 'd3';
17
18
  import {Stage, Layer, Rect, Arrow, Text, Label} from 'react-konva';
18
19
  import type {KonvaEventObject} from 'konva/lib/Node';
19
- import {Button} from '@parca/components';
20
+ import {Button, useURLState} from '@parca/components';
20
21
  import {CallgraphNode, CallgraphEdge, Callgraph as CallgraphType} from '@parca/client';
21
22
  import {jsonToDot, getCurvePoints} from './utils';
22
23
  import type {HoveringNode} from '../GraphTooltip';
@@ -181,6 +182,9 @@ const Callgraph = ({graph, sampleUnit, width, colorRange}: Props): JSX.Element =
181
182
  const {nodes: rawNodes, cumulative: total} = graph;
182
183
  const currentSearchString = (selectQueryParam('search_string') as string) ?? '';
183
184
  const isSearchEmpty = currentSearchString === undefined || currentSearchString === '';
185
+ const [rawDashboardItems] = useURLState({param: 'dashboard_items'});
186
+
187
+ const dashboardItems = rawDashboardItems as string[];
184
188
 
185
189
  useEffect(() => {
186
190
  const getDataWithPositions = async (): Promise<void> => {
@@ -345,9 +349,16 @@ const Callgraph = ({graph, sampleUnit, width, colorRange}: Props): JSX.Element =
345
349
  contextElement={containerRef.current}
346
350
  />
347
351
  {stage.scale.x !== 1 && (
348
- <Button className="w-auto !absolute top-0 left-0" variant="neutral" onClick={resetZoom}>
349
- Reset Zoom
350
- </Button>
352
+ <div
353
+ className={cx(
354
+ dashboardItems.length > 1 ? 'left-[25px]' : 'left-0',
355
+ 'w-auto absolute top-[-46px]'
356
+ )}
357
+ >
358
+ <Button variant="neutral" onClick={resetZoom}>
359
+ Reset Zoom
360
+ </Button>
361
+ </div>
351
362
  )}
352
363
  </div>
353
364
  </div>
@@ -27,6 +27,7 @@ import useColoredGraph from './useColoredGraph';
27
27
  import {selectQueryParam} from '@parca/functions';
28
28
  import type {NavigateFunction} from '@parca/functions';
29
29
  import ColorStackLegend from './ColorStackLegend';
30
+ import useUserPreference, {USER_PREFERENCES} from '@parca/functions/useUserPreference';
30
31
 
31
32
  interface IcicleGraphProps {
32
33
  graph: Flamegraph;
@@ -64,6 +65,10 @@ export const IcicleGraph = memo(function IcicleGraph({
64
65
  const compareMode: boolean =
65
66
  selectQueryParam('compare_a') === 'true' && selectQueryParam('compare_b') === 'true';
66
67
 
68
+ const [colorProfileName] = useUserPreference<string>(
69
+ USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key
70
+ );
71
+
67
72
  useEffect(() => {
68
73
  if (ref.current != null) {
69
74
  setHeight(ref?.current.getBoundingClientRect().height);
@@ -89,6 +94,7 @@ export const IcicleGraph = memo(function IcicleGraph({
89
94
 
90
95
  throttledSetPos([rel[0], rel[1]]);
91
96
  };
97
+ const isColorStackLegendVisible = colorProfileName !== 'default';
92
98
 
93
99
  return (
94
100
  <div onMouseLeave={() => setHoveringNode(undefined)}>
@@ -106,14 +112,20 @@ export const IcicleGraph = memo(function IcicleGraph({
106
112
  functions={coloredGraph.function}
107
113
  />
108
114
  <div
109
- className={cx(
110
- dashboardItems.length > 1
111
- ? `${isTrimmed ? 'top-[-54px]' : 'top-[-70px]'} left-[25px]`
112
- : isTrimmed
113
- ? 'top-[-54px]'
114
- : 'top-[-69px]',
115
- 'flex justify-start absolute '
116
- )}
115
+ className={cx('flex justify-start absolute', {
116
+ 'top-[-48px]': dashboardItems.length <= 1 && !isTrimmed && !isColorStackLegendVisible,
117
+ 'top-[-69px]': dashboardItems.length <= 1 && !isTrimmed,
118
+ 'top-[-54px]': dashboardItems.length <= 1 && isTrimmed && isColorStackLegendVisible,
119
+ 'top-[-54px] ': dashboardItems.length <= 1 && isTrimmed && !isColorStackLegendVisible,
120
+ 'top-[-54px] left-[25px]':
121
+ dashboardItems.length > 1 && isTrimmed && isColorStackLegendVisible,
122
+ 'top-[-54px] left-[25px] ':
123
+ dashboardItems.length > 1 && isTrimmed && !isColorStackLegendVisible,
124
+ 'top-[-70px] left-[25px]':
125
+ dashboardItems.length > 1 && !isTrimmed && isColorStackLegendVisible,
126
+ 'top-[-46px] left-[25px]':
127
+ dashboardItems.length > 1 && !isTrimmed && !isColorStackLegendVisible,
128
+ })}
117
129
  >
118
130
  <Button
119
131
  color="neutral"
@@ -13,16 +13,10 @@
13
13
 
14
14
  import {useCallback, useMemo} from 'react';
15
15
 
16
- import {
17
- getLastItem,
18
- valueFormatter,
19
- isSearchMatch,
20
- parseParams,
21
- selectQueryParam,
22
- } from '@parca/functions';
16
+ import {getLastItem, valueFormatter, isSearchMatch, parseParams} from '@parca/functions';
23
17
  import type {NavigateFunction} from '@parca/functions';
24
18
  import {TopNode, TopNodeMeta, Top} from '@parca/client';
25
- import {Table} from '@parca/components';
19
+ import {Button, Table, useURLState} from '@parca/components';
26
20
  import {createColumnHelper} from '@tanstack/react-table';
27
21
  import type {ColumnDef} from '@tanstack/react-table';
28
22
 
@@ -70,9 +64,13 @@ export const TopTable = ({
70
64
  loading,
71
65
  }: TopTableProps): JSX.Element => {
72
66
  const router = parseParams(window.location.search);
73
- const currentSearchString = selectQueryParam('search_string') as string;
74
- const compareMode =
75
- Boolean(selectQueryParam('compare_a')) && Boolean(selectQueryParam('compare_b'));
67
+ const [rawDashboardItems] = useURLState({param: 'dashboard_items'});
68
+ const [currentSearchString] = useURLState({param: 'search_string'});
69
+ const [rawcompareMode] = useURLState({param: 'compare_a'});
70
+
71
+ const compareMode: boolean = rawcompareMode === undefined ? false : rawcompareMode === 'true';
72
+
73
+ const dashboardItems = rawDashboardItems as string[];
76
74
 
77
75
  const columns = useMemo(() => {
78
76
  const cols: Array<ColumnDef<TopNode, any>> = [
@@ -142,6 +140,11 @@ export const TopTable = ({
142
140
 
143
141
  const onRowClick = useCallback(
144
142
  (row: TopNode) => {
143
+ // If there is only one dashboard item, we don't want to select a span
144
+ if (dashboardItems.length <= 1) {
145
+ return;
146
+ }
147
+
145
148
  const meta = row.meta;
146
149
  if (meta === undefined) {
147
150
  return;
@@ -149,7 +152,7 @@ export const TopTable = ({
149
152
  const name = RowLabel(meta);
150
153
  selectSpan(name);
151
154
  },
152
- [selectSpan]
155
+ [selectSpan, dashboardItems.length]
153
156
  );
154
157
 
155
158
  const shouldHighlightRow = useCallback(
@@ -157,7 +160,7 @@ export const TopTable = ({
157
160
  const meta = row.meta;
158
161
  if (meta === undefined) return false;
159
162
  const name = RowLabel(meta);
160
- return isSearchMatch(currentSearchString, name);
163
+ return isSearchMatch(currentSearchString as string, name);
161
164
  },
162
165
  [currentSearchString]
163
166
  );
@@ -166,6 +169,19 @@ export const TopTable = ({
166
169
  return currentSearchString != null && currentSearchString?.length > 0;
167
170
  }, [currentSearchString]);
168
171
 
172
+ const clearSelection = useCallback((): void => {
173
+ if (navigateTo != null) {
174
+ navigateTo(
175
+ '/',
176
+ {
177
+ ...router,
178
+ ...{search_string: ''},
179
+ },
180
+ {replace: true}
181
+ );
182
+ }
183
+ }, [navigateTo, router]);
184
+
169
185
  const initialSorting = useMemo(() => {
170
186
  return [{id: compareMode ? 'diff' : 'cumulative', desc: true}];
171
187
  }, [compareMode]);
@@ -175,7 +191,22 @@ export const TopTable = ({
175
191
  if (total === 0 && !loading) return <>Profile has no samples</>;
176
192
 
177
193
  return (
178
- <>
194
+ <div className="relative">
195
+ {/* Clearing the selection is only useful when two visualizations types are selected. So we'll only show it in that case */}
196
+ {dashboardItems.length > 1 && (
197
+ <div className="left-[25px] top-[-45px] absolute">
198
+ <Button
199
+ color="neutral"
200
+ onClick={clearSelection}
201
+ className="w-auto"
202
+ variant="neutral"
203
+ disabled={currentSearchString === undefined || currentSearchString.length === 0}
204
+ >
205
+ Clear selection
206
+ </Button>
207
+ </div>
208
+ )}
209
+
179
210
  <div className="w-full font-robotoMono h-[80vh] overflow-scroll">
180
211
  <Table
181
212
  data={top?.list ?? []}
@@ -184,9 +215,10 @@ export const TopTable = ({
184
215
  onRowClick={onRowClick}
185
216
  enableHighlighting={enableHighlighting}
186
217
  shouldHighlightRow={shouldHighlightRow}
218
+ usePointerCursor={dashboardItems.length > 1}
187
219
  />
188
220
  </div>
189
- </>
221
+ </div>
190
222
  );
191
223
  };
192
224