From 9f091b686143a08dba5315c7a702e224152a064d Mon Sep 17 00:00:00 2001 From: James Kerr Date: Tue, 9 Jan 2024 12:55:20 -0800 Subject: [PATCH] Zui Polish 2 (#2895) Dark Mode Translucent Mac Window New Pin Design New Toolbar Design New Detail Pane Design New History Pane Design New Save Query Workflow --- apps/zui/build/preload.js | 8 +- apps/zui/package.json | 1 - apps/zui/pages/detail.tsx | 2 +- apps/zui/project.json | 2 +- apps/zui/public/custom-icons.svg | 15 + apps/zui/public/icons.svg | 13450 ++++++++++++++++ apps/zui/public/icons/file-border.tsx | 23 - apps/zui/public/icons/subspace-border.svg | 10 - apps/zui/public/icons/subspace.svg | 6 - apps/zui/public/main.css | 3944 ----- apps/zui/public/pool-wall-background.svg | 5638 ------- apps/zui/src/app/commands/editor.ts | 117 - apps/zui/src/app/commands/pins.ts | 125 - apps/zui/src/app/commands/queries.ts | 2 +- apps/zui/src/app/commands/run-query.ts | 6 +- .../zui/src/app/commands/show-history-pane.ts | 5 - apps/zui/src/app/commands/values.ts | 30 - apps/zui/src/app/core/Data.tsx | 27 +- apps/zui/src/app/core/icon-temp.tsx | 43 - apps/zui/src/app/core/icons/braces.tsx | 11 - apps/zui/src/app/core/icons/branch.tsx | 25 - apps/zui/src/app/core/icons/carrot down.tsx | 18 - apps/zui/src/app/core/icons/chart.tsx | 11 - apps/zui/src/app/core/icons/check.tsx | 12 - apps/zui/src/app/core/icons/chevron-down.tsx | 11 - apps/zui/src/app/core/icons/chevron-left.tsx | 18 - apps/zui/src/app/core/icons/chevron-right.tsx | 17 - apps/zui/src/app/core/icons/chevron-up.tsx | 19 - apps/zui/src/app/core/icons/close.tsx | 25 - .../app/core/icons/collapse-horizontal.tsx | 12 - apps/zui/src/app/core/icons/collapse.tsx | 18 - apps/zui/src/app/core/icons/columns.tsx | 16 - apps/zui/src/app/core/icons/detach.tsx | 11 - apps/zui/src/app/core/icons/doc-plain.tsx | 28 - .../app/core/icons/double-chevron-right.tsx | 11 - apps/zui/src/app/core/icons/duplicate.tsx | 28 - .../src/app/core/icons/expand-horizontal.tsx | 12 - apps/zui/src/app/core/icons/expand.tsx | 17 - apps/zui/src/app/core/icons/export.tsx | 18 - apps/zui/src/app/core/icons/file-border.tsx | 22 - apps/zui/src/app/core/icons/file-filled.tsx | 14 - apps/zui/src/app/core/icons/folder.tsx | 23 - apps/zui/src/app/core/icons/grid.tsx | 11 - apps/zui/src/app/core/icons/hide.tsx | 8 - apps/zui/src/app/core/icons/history.tsx | 17 - apps/zui/src/app/core/icons/index.ts | 95 - apps/zui/src/app/core/icons/lamda.tsx | 17 - apps/zui/src/app/core/icons/left-arrow.tsx | 12 - apps/zui/src/app/core/icons/list.tsx | 11 - apps/zui/src/app/core/icons/lock.tsx | 27 - apps/zui/src/app/core/icons/pin.tsx | 20 - apps/zui/src/app/core/icons/plus.tsx | 24 - apps/zui/src/app/core/icons/pool.tsx | 14 - apps/zui/src/app/core/icons/query.tsx | 20 - apps/zui/src/app/core/icons/reload.tsx | 11 - apps/zui/src/app/core/icons/right-arrow.tsx | 12 - .../app/core/icons/right-sidebar-toggle.tsx | 15 - apps/zui/src/app/core/icons/run.tsx | 24 - apps/zui/src/app/core/icons/sharkfin.tsx | 21 - apps/zui/src/app/core/icons/show.tsx | 9 - .../zui/src/app/core/icons/sidebar-toggle.tsx | 11 - apps/zui/src/app/core/icons/snippet.tsx | 19 - apps/zui/src/app/core/icons/sort-asc.tsx | 33 - apps/zui/src/app/core/icons/sort-desc.tsx | 33 - apps/zui/src/app/core/icons/tag.tsx | 26 - .../src/app/core/icons/three-dots-stacked.tsx | 11 - apps/zui/src/app/core/icons/three-dots.tsx | 10 - apps/zui/src/app/core/icons/update.tsx | 11 - apps/zui/src/app/core/icons/view.tsx | 14 - apps/zui/src/app/core/icons/warning.tsx | 8 - apps/zui/src/app/core/icons/zui.tsx | 17 - apps/zui/src/app/core/models/active-query.ts | 2 +- apps/zui/src/app/detail/Fields.tsx | 44 +- apps/zui/src/app/detail/Panel.tsx | 15 +- apps/zui/src/app/detail/PanelHeading.tsx | 6 +- apps/zui/src/app/detail/Shared.tsx | 2 +- .../app/features/inspector/list.styled.tsx | 56 - .../inspector/templates/container.tsx | 6 +- .../app/features/inspector/templates/item.tsx | 5 +- .../app/features/inspector/templates/key.tsx | 7 +- .../src/app/features/right-pane/common.tsx | 3 - .../right-pane/history/history-item.tsx | 29 +- .../features/right-pane/history/section.tsx | 3 +- .../right-pane/history/use-entry-menu.ts | 2 +- .../zui/src/app/features/right-pane/index.tsx | 19 +- .../app/features/right-pane/version-item.tsx | 5 +- .../features/right-pane/versions-section.tsx | 3 +- apps/zui/src/app/features/sidebar/content.tsx | 2 +- apps/zui/src/app/features/sidebar/index.tsx | 4 +- apps/zui/src/app/features/sidebar/item.tsx | 30 +- .../src/app/features/sidebar/lake-picker.tsx | 11 +- .../src/app/features/sidebar/plus-button.tsx | 10 +- .../features/sidebar/pools-section/empty.tsx | 2 +- .../features/sidebar/pools-section/index.tsx | 2 +- .../sidebar/pools-section/pool-item.tsx | 9 +- .../sidebar/pools-section/pools-tree.tsx | 3 +- .../sidebar/queries-section/empty.tsx | 2 +- .../sidebar/queries-section/index.tsx | 8 +- .../sidebar/queries-section/queries-tree.tsx | 22 +- .../sidebar/queries-section/query-item.tsx | 5 +- .../src/app/features/sidebar/search-bar.tsx | 8 +- .../sidebar/sidebar-toggle-button.tsx | 9 +- .../src/app/menus/column-list-item-menu.ts | 38 +- .../zui/src/app/menus/columns-toolbar-menu.ts | 33 +- apps/zui/src/app/menus/header-context-menu.ts | 13 +- apps/zui/src/app/menus/new-pin-menu.ts | 22 - apps/zui/src/app/menus/open-query-menu.ts | 2 +- apps/zui/src/app/menus/pool-context-menu.ts | 5 +- apps/zui/src/app/menus/pool-toolbar-menu.ts | 49 +- apps/zui/src/app/menus/query-context-menu.ts | 9 +- .../src/app/menus/query-tree-context-menu.ts | 1 - apps/zui/src/app/menus/saved-query-menu.ts | 127 +- apps/zui/src/app/menus/value-context-menu.ts | 36 +- .../zui/src/app/query-home/editor-resizer.tsx | 21 - apps/zui/src/app/query-home/flows/new-tab.ts | 6 - .../src/app/query-home/flows/submit-search.ts | 41 - apps/zui/src/app/query-home/index.tsx | 83 - .../src/app/query-home/query-home.module.css | 31 - .../src/app/query-home/results/data-hook.ts | 14 - .../app/query-home/results/results.styled.tsx | 90 - .../src/app/query-home/search-area/index.tsx | 58 - .../query-home/search-area/pins/base-pin.tsx | 207 - .../search-area/pins/from-pin/from-pin.tsx | 33 - .../search-area/pins/from-pin/show-menu.ts | 34 - .../pins/generic-pin/generic-pin.tsx | 18 - .../search-area/pins/new-pin-button.tsx | 33 - .../search-area/pins/pin-context-menu.ts | 74 - .../app/query-home/search-area/pins/pins.tsx | 42 - .../search-area/pins/placeholder-pin.tsx | 32 - .../pins/time-range-pin/time-range-pin.tsx | 32 - .../query-home/search-area/popup-position.ts | 5 - .../src/app/query-home/title-bar/button.tsx | 74 - .../src/app/query-home/title-bar/context.tsx | 26 - .../query-home/title-bar/detatch-button.tsx | 22 - .../query-home/title-bar/heading-button.tsx | 27 - .../app/query-home/title-bar/heading-form.tsx | 50 - .../app/query-home/title-bar/heading-menu.tsx | 21 - .../query-home/title-bar/heading-saved.tsx | 81 - .../src/app/query-home/title-bar/heading.tsx | 14 - .../app/query-home/title-bar/icon-button.tsx | 42 - .../app/query-home/title-bar/nav-actions.tsx | 47 - .../app/query-home/title-bar/orange-tag.tsx | 16 - .../app/query-home/title-bar/plus-one.test.ts | 17 - .../query-home/title-bar/query-actions.tsx | 84 - .../app/query-home/title-bar/title-bar.tsx | 28 - .../query-home/title-bar/use-heading-form.ts | 63 - .../app/query-home/toolbar/actions/button.tsx | 119 - .../query-home/toolbar/results-toolbar.tsx | 16 - .../toolbar/results-view-switch.tsx | 48 - apps/zui/src/app/router/routes.ts | 4 +- .../src/app/routes/app-wrapper/app-grid.tsx | 18 +- .../src/app/routes/app-wrapper/app-modals.tsx | 2 +- .../app/routes/app-wrapper/app-wrapper.tsx | 4 +- .../app-wrapper/data-dropzone.module.css | 2 +- .../src/app/routes/app-wrapper/main-area.tsx | 19 +- apps/zui/src/components/button-menu.tsx | 17 +- apps/zui/src/components/debut.tsx | 1 + apps/zui/src/components/dialog/index.tsx | 3 +- apps/zui/src/components/drag-anchor.tsx | 6 +- apps/zui/src/components/file-input.tsx | 2 +- apps/zui/src/components/forms.module.css | 5 +- apps/zui/src/components/icon-button.tsx | 36 +- apps/zui/src/components/icon/icon-names.ts | 63 + apps/zui/src/components/icon/icon.module.css | 4 + apps/zui/src/components/icon/index.tsx | 35 + .../src/components/icon/ming-cute-names.ts | 1336 ++ apps/zui/src/components/input-button.tsx | 4 +- apps/zui/src/components/list-item.tsx | 12 +- apps/zui/src/components/modals.module.css | 15 +- apps/zui/src/components/more-items-button.tsx | 10 +- apps/zui/src/components/section-tabs.tsx | 2 +- .../src/components/toolbar-tabs.module.css | 14 +- apps/zui/src/components/toolbar-tabs.tsx | 19 +- apps/zui/src/components/toolbar.tsx | 3 +- apps/zui/src/components/tooltip.module.css | 17 + apps/zui/src/components/tooltip.tsx | 55 + .../search-area => components}/zed-editor.tsx | 6 +- .../components/zed-table/cell-component.tsx | 1 + apps/zui/src/components/zed-table/cell.ts | 6 +- apps/zui/src/components/zed-table/column.ts | 4 +- apps/zui/src/components/zed-table/config.ts | 1 - .../src/components/zed-table/header-cell.tsx | 8 +- apps/zui/src/components/zed-table/types.ts | 1 - apps/zui/src/core/command.ts | 53 - apps/zui/src/core/handlers.ts | 4 + apps/zui/src/core/menu/built-menu.ts | 43 - apps/zui/src/core/menu/create-menu.ts | 35 +- apps/zui/src/core/menu/global-menus.ts | 4 - apps/zui/src/core/menu/handle-click.ts | 15 + apps/zui/src/core/menu/index.ts | 5 +- apps/zui/src/core/menu/menu-manager.ts | 32 - apps/zui/src/core/menu/menu-node.ts | 43 - apps/zui/src/core/menu/menu.ts | 14 - apps/zui/src/core/menu/show-context-menu.ts | 27 +- apps/zui/src/core/menu/to-electron.ts | 18 + apps/zui/src/core/menu/types.ts | 25 +- apps/zui/src/core/menu/use-menu-extension.ts | 49 + apps/zui/src/core/menu/use-menu-instance.ts | 62 - apps/zui/src/css/_about-window.scss | 2 +- apps/zui/src/css/_buttons.scss | 12 +- apps/zui/src/css/_chart-elements.scss | 3 - apps/zui/src/css/_chart.scss | 14 +- apps/zui/src/css/_circle-chevron.scss | 71 - apps/zui/src/css/_click-feedback.scss | 21 - apps/zui/src/css/_column-chooser.scss | 81 - apps/zui/src/css/_column-description.scss | 52 - apps/zui/src/css/_conn-versation.scss | 9 +- apps/zui/src/css/_download-progress.scss | 34 - apps/zui/src/css/_editor.scss | 5 + apps/zui/src/css/_error-boundary.scss | 1 - apps/zui/src/css/_filter-node.scss | 44 - apps/zui/src/css/_filter-tree.scss | 95 - apps/zui/src/css/_global.scss | 36 +- apps/zui/src/css/_header-cell.scss | 75 - apps/zui/src/css/_histogram-tooltip.scss | 13 +- apps/zui/src/css/_history-pane.scss | 4 - apps/zui/src/css/_icons.scss | 5 - apps/zui/src/css/_info-notice.scss | 69 - apps/zui/src/css/_inline-table-loading.scss | 3 +- apps/zui/src/css/_inline-table.scss | 6 +- apps/zui/src/css/_input-suggestions.scss | 40 - apps/zui/src/css/_list-item.scss | 6 +- apps/zui/src/css/_log-cell.scss | 48 - apps/zui/src/css/_log-detail-window.scss | 4 +- apps/zui/src/css/_log-detail.scss | 3 +- apps/zui/src/css/_log-viewer.scss | 82 - apps/zui/src/css/_mac-spinner.scss | 2 +- apps/zui/src/css/_notice-banner.scss | 3 +- apps/zui/src/css/_packet-post-progress.scss | 61 - apps/zui/src/css/_pane.scss | 2 +- apps/zui/src/css/_pop-menu.scss | 104 - apps/zui/src/css/_progress-indicator.scss | 13 +- apps/zui/src/css/_saved-pools-list.scss | 107 - apps/zui/src/css/_search-results.scss | 8 - apps/zui/src/css/_settings-modal.scss | 70 - apps/zui/src/css/_tab.scss | 47 +- apps/zui/src/css/_table.scss | 3 +- apps/zui/src/css/_time-span-pickers.scss | 122 - apps/zui/src/css/_toaster.scss | 2 +- apps/zui/src/css/_toolbar-button.scss | 77 - apps/zui/src/css/_tooltip-animation.scss | 22 + apps/zui/src/css/_tooltip.scss | 34 - apps/zui/src/css/_zed-table.scss | 11 +- apps/zui/src/css/_zed-view.scss | 4 +- apps/zui/src/css/forms/_file-input.scss | 20 - apps/zui/src/css/forms/_global.scss | 3 - apps/zui/src/css/forms/_main.scss | 5 - apps/zui/src/css/forms/_mixins.scss | 12 - apps/zui/src/css/forms/_select-input.scss | 10 - apps/zui/src/css/forms/_text-input.scss | 11 - apps/zui/src/css/main.scss | 29 +- apps/zui/src/css/settings/_colors.scss | 204 +- apps/zui/src/css/shared/_type-colors.scss | 11 +- apps/zui/src/css/shared/_typography.scss | 11 - apps/zui/src/domain/commands.ts | 1 - apps/zui/src/domain/commands/messages.ts | 5 + apps/zui/src/domain/commands/operations.ts | 15 + apps/zui/src/domain/commands/plugin-api.ts | 25 + apps/zui/src/domain/editor/handlers.ts | 127 + apps/zui/src/domain/editor/messages.ts | 15 + apps/zui/src/domain/handlers.ts | 3 +- apps/zui/src/domain/menus.ts | 1 - apps/zui/src/domain/menus/handlers.ts | 9 - apps/zui/src/domain/menus/messages.ts | 11 +- apps/zui/src/domain/menus/operations.ts | 12 + apps/zui/src/domain/menus/plugin-api.ts | 14 + apps/zui/src/domain/messages.ts | 11 +- apps/zui/src/domain/operations.ts | 2 + apps/zui/src/domain/panes/commands.ts | 7 - apps/zui/src/domain/plugin-api.ts | 4 + apps/zui/src/domain/results/commands.ts | 21 - apps/zui/src/domain/results/handlers.ts | 95 +- apps/zui/src/domain/results/toolbar-menu.ts | 39 - apps/zui/src/domain/session/commands.ts | 10 - apps/zui/src/domain/session/handlers.ts | 10 - apps/zui/src/domain/session/handlers/index.ts | 4 + .../src/domain/session/handlers/navigation.ts | 63 + apps/zui/src/domain/session/handlers/pins.ts | 165 + .../src/domain/session/handlers/queries.ts | 50 + .../domain/session/handlers/submit-search.ts | 42 + .../domain/session/menus/choose-pool-menu.ts | 17 + .../src/domain/session/menus/edit-pin.menu.ts | 44 + .../src/domain/session/menus/toolbar-menu.ts | 58 + apps/zui/src/domain/session/messages.ts | 24 +- apps/zui/src/domain/window/handlers.ts | 22 + apps/zui/src/electron/html-dialog/dialog.html | 19 - .../src/electron/html-dialog/dialog.style.tsx | 37 - apps/zui/src/electron/html-dialog/dialog.tsx | 52 - apps/zui/src/electron/html-dialog/index.ts | 50 - .../src/electron/ops/get-menu-template-op.ts | 10 - .../electron/ops/import-queries-op.test.ts | 13 +- apps/zui/src/electron/ops/index.ts | 2 - .../zui/src/electron/ops/invoke-command-op.ts | 11 - .../run-main/run-protocol-handlers.ts | 3 +- apps/zui/src/electron/windows-pre-25.ts | 8 +- .../src/electron/windows/search/app-menu.ts | 4 +- .../electron/windows/search/search-window.ts | 2 + apps/zui/src/initializers/commands.ts | 7 - apps/zui/src/initializers/index.ts | 2 - apps/zui/src/initializers/menus.ts | 7 - apps/zui/src/js/api/layout-api.ts | 20 - apps/zui/src/js/api/zui-api.ts | 16 +- apps/zui/src/js/components/AboutWindow.tsx | 4 +- apps/zui/src/js/components/CircleChevron.tsx | 35 - apps/zui/src/js/components/CloseButton.tsx | 4 +- apps/zui/src/js/components/Content.tsx | 2 +- apps/zui/src/js/components/FilterNode.tsx | 48 - .../zui/src/js/components/HTMLContextMenu.tsx | 3 +- apps/zui/src/js/components/InfoNotice.tsx | 15 - .../js/components/LakeModals/StatusLight.tsx | 29 - .../LogDetails/ColumnDescription.tsx | 33 - apps/zui/src/js/components/Login.tsx | 13 +- apps/zui/src/js/components/MenuBarButton.tsx | 40 - .../src/js/components/ModalBox/Buttons.tsx | 64 - .../src/js/components/ModalBox/ModalBox.tsx | 41 - .../js/components/ModalBox/ModalContents.tsx | 46 - apps/zui/src/js/components/ModalBox/types.ts | 27 - .../components/ModalBox/useModalController.ts | 53 - apps/zui/src/js/components/Notice.tsx | 108 - apps/zui/src/js/components/StartupError.tsx | 89 - .../src/js/components/TabBar/SearchTab.tsx | 14 +- apps/zui/src/js/components/TabBar/TabBar.tsx | 12 +- .../TabBar}/use-query-id-name-map.ts | 0 .../js/components/TabBar/useTabController.ts | 3 +- apps/zui/src/js/components/Tooltip.tsx | 22 - .../src/js/components/common/EmptySection.tsx | 4 +- .../components/status-bar/query-progress.tsx | 2 +- apps/zui/src/js/flows/searchBar/actions.ts | 2 +- apps/zui/src/js/icons/ThreeDotsIcon.tsx | 7 - .../js/initializers/init-resize-listener.ts | 21 + apps/zui/src/js/initializers/initDOM.ts | 3 + .../src/js/initializers/initIpcListeners.ts | 4 +- .../src/js/initializers/initNewSearchTab.ts | 4 +- apps/zui/src/js/initializers/initialize.ts | 9 +- apps/zui/src/js/lib/System.ts | 10 - apps/zui/src/js/state/Current/selectors.ts | 3 +- apps/zui/src/js/state/Layout/reducer.ts | 9 +- apps/zui/src/js/state/Layout/types.ts | 2 +- apps/zui/src/js/state/Pools/selectors.ts | 4 +- .../QueryVersions/flows/save-query-version.ts | 20 - .../src/js/state/ResultsToolbar/selectors.ts | 3 - apps/zui/src/js/state/ResultsToolbar/slice.ts | 23 - .../{ResultsToolbar => Selection}/index.ts | 5 +- apps/zui/src/js/state/Selection/reducer.ts | 29 + apps/zui/src/js/state/Selection/selectors.ts | 6 + apps/zui/src/js/state/Tab/reducer.ts | 4 +- apps/zui/src/js/state/Table/index.ts | 9 +- apps/zui/src/js/state/Table/reducer.ts | 100 +- apps/zui/src/js/state/Table/selectors.ts | 145 + apps/zui/src/js/state/Table/types.ts | 21 + .../src/plugins/brimcap/packets/download.ts | 4 +- .../src/plugins/brimcap/packets/menu-item.ts | 14 +- .../plugins/brimcap/suricata/correlations.ts | 1 - apps/zui/src/ppl/css/_load-files-input.scss | 188 - apps/zui/src/ppl/detail/EventLimit.tsx | 4 +- apps/zui/src/ppl/detail/EventTimeline.tsx | 20 +- apps/zui/src/ppl/detail/RelatedAlerts.tsx | 2 +- apps/zui/src/ppl/detail/RelatedConns.tsx | 2 +- apps/zui/src/ppl/detail/UidPanel.tsx | 2 +- apps/zui/src/ppl/detail/ZeekTag.tsx | 4 +- apps/zui/src/ppl/import/DataFileIcon.tsx | 26 - apps/zui/src/ppl/import/LoadFilesInput.tsx | 62 - apps/zui/src/ppl/zeek/zeek-plugin.tsx | 2 +- apps/zui/src/test/system/teardown.ts | 3 +- apps/zui/src/util/find-ancestor.ts | 8 + apps/zui/src/util/fixed-positioner.ts | 160 +- apps/zui/src/util/hooks/use-color-scheme.ts | 18 + apps/zui/src/util/hooks/use-fixed-position.ts | 24 +- apps/zui/src/util/objectify.ts | 5 + .../query-home/title-bar => util}/plus-one.ts | 0 apps/zui/src/util/tree.ts | 28 + apps/zui/src/views/application/index.tsx | 4 +- .../zui/src/views/application/use-app-menu.ts | 5 +- .../src/views/application/use-shortcuts.ts | 3 +- .../views/columns-pane/columns-toolbar.tsx | 17 +- .../src/views/columns-pane/columns-tree.tsx | 26 +- apps/zui/src/views/columns-pane/index.tsx | 1 - apps/zui/src/views/histogram-pane/chart.tsx | 4 +- .../histogram-pane/histogram-pane.module.css | 21 +- .../views/histogram-pane/settings-button.tsx | 2 +- apps/zui/src/views/load-pane/form.module.css | 27 +- apps/zui/src/views/load-pane/form.tsx | 6 +- apps/zui/src/views/load-pane/index.module.css | 4 +- .../src/views/load-pane/results.module.css | 21 +- apps/zui/src/views/load-pane/results.tsx | 8 +- .../zui/src/views/load-pane/shaper.module.css | 4 +- apps/zui/src/views/load-pane/shaper.tsx | 5 +- .../src/views/pool-page/details.module.css | 2 +- apps/zui/src/views/pool-page/index.module.css | 2 +- apps/zui/src/views/pool-page/index.tsx | 4 +- apps/zui/src/views/pool-page/job.module.css | 21 +- apps/zui/src/views/pool-page/job.tsx | 4 +- .../views/pool-page/recent-loads.module.css | 6 +- .../views/preferences-modal/index.module.css | 67 - .../results-pane}/alert-view.ts | 0 .../results-pane}/bare-string-view.ts | 0 .../errors/missing-pool-error.tsx | 12 +- .../results-pane/errors/network-error.tsx | 6 +- apps/zui/src/views/results-pane/inspector.tsx | 12 +- .../results-pane}/path-view.ts | 0 .../results-pane/results-pane.module.css | 9 + .../views/results-pane/table-controller.tsx | 56 +- .../views/results-pane/table-inspector.tsx | 4 +- apps/zui/src/views/results-pane/table.tsx | 104 +- .../views/session-page/detail-bar.module.css | 0 .../zui/src/views/session-page/detail-bar.tsx | 3 + .../src/views/session-page/editor-resizer.tsx | 35 + .../src/views/session-page/editor.module.css | 4 + apps/zui/src/views/session-page/editor.tsx | 46 + .../src/views/session-page/footer.module.css | 28 + apps/zui/src/views/session-page/footer.tsx | 125 + .../src/views/session-page/grid.module.css | 5 + apps/zui/src/views/session-page/grid.tsx | 20 + .../src/views/session-page/index.module.css | 0 apps/zui/src/views/session-page/index.tsx | 18 + .../session-page}/loader.ts | 2 +- .../src/views/session-page/pins.module.css | 50 + apps/zui/src/views/session-page/pins.tsx | 53 + .../src/views/session-page/pins/base-pin.tsx | 145 + .../session-page}/pins/dialog.tsx | 13 +- .../session-page}/pins/form-helpers.tsx | 2 +- .../session-page/pins/generic-pin-form.tsx} | 6 +- .../pins}/get-time-preview.test.ts | 0 .../session-page/pins}/get-time-string.ts | 0 .../pins/time-range-pin-form.tsx} | 8 +- .../session-page}/pins/use-pin-dnd.ts | 0 .../src/views/session-page/results.module.css | 5 + apps/zui/src/views/session-page/results.tsx | 12 + .../session-page}/route.tsx | 8 +- .../src/views/session-page/toolbar.module.css | 94 + apps/zui/src/views/session-page/toolbar.tsx | 120 + .../src/views/session-page/use-title-form.ts | 31 + apps/zui/src/views/welcome-page/index.tsx | 22 +- .../zui-kit/core/table-view/table-view-api.ts | 5 +- apps/zui/src/zui-kit/core/table-view/types.ts | 2 +- apps/zui/src/zui-kit/core/value-view/types.ts | 2 +- apps/zui/src/zui-kit/react/list-view.tsx | 2 +- apps/zui/src/zui-kit/react/table-view.tsx | 2 +- apps/zui/src/zui/commands.ts | 1 - apps/zui/src/zui/index.ts | 2 - apps/zui/src/zui/menus.ts | 1 - nx.json | 37 +- package.json | 4 +- packages/zed-js/project.json | 4 +- packages/zed-wasm/.env.build-go | 2 +- packages/zed-wasm/project.json | 4 +- packages/zui-player/helpers/test-app.ts | 14 +- packages/zui-player/tests/export.spec.ts | 6 +- packages/zui-player/tests/packets.spec.ts | 18 + packages/zui-player/tests/queries.spec.ts | 48 +- .../tests/right-click-menus.spec.ts | 92 + packages/zui-player/tests/table.spec.ts | 6 + yarn.lock | 270 +- 453 files changed, 18590 insertions(+), 16914 deletions(-) create mode 100644 apps/zui/public/custom-icons.svg create mode 100644 apps/zui/public/icons.svg delete mode 100644 apps/zui/public/icons/file-border.tsx delete mode 100644 apps/zui/public/icons/subspace-border.svg delete mode 100644 apps/zui/public/icons/subspace.svg delete mode 100644 apps/zui/public/main.css delete mode 100644 apps/zui/public/pool-wall-background.svg delete mode 100644 apps/zui/src/app/commands/editor.ts delete mode 100644 apps/zui/src/app/commands/pins.ts delete mode 100644 apps/zui/src/app/commands/show-history-pane.ts delete mode 100644 apps/zui/src/app/commands/values.ts delete mode 100644 apps/zui/src/app/core/icon-temp.tsx delete mode 100644 apps/zui/src/app/core/icons/braces.tsx delete mode 100644 apps/zui/src/app/core/icons/branch.tsx delete mode 100644 apps/zui/src/app/core/icons/carrot down.tsx delete mode 100644 apps/zui/src/app/core/icons/chart.tsx delete mode 100644 apps/zui/src/app/core/icons/check.tsx delete mode 100644 apps/zui/src/app/core/icons/chevron-down.tsx delete mode 100644 apps/zui/src/app/core/icons/chevron-left.tsx delete mode 100644 apps/zui/src/app/core/icons/chevron-right.tsx delete mode 100644 apps/zui/src/app/core/icons/chevron-up.tsx delete mode 100644 apps/zui/src/app/core/icons/close.tsx delete mode 100644 apps/zui/src/app/core/icons/collapse-horizontal.tsx delete mode 100644 apps/zui/src/app/core/icons/collapse.tsx delete mode 100644 apps/zui/src/app/core/icons/columns.tsx delete mode 100644 apps/zui/src/app/core/icons/detach.tsx delete mode 100644 apps/zui/src/app/core/icons/doc-plain.tsx delete mode 100644 apps/zui/src/app/core/icons/double-chevron-right.tsx delete mode 100644 apps/zui/src/app/core/icons/duplicate.tsx delete mode 100644 apps/zui/src/app/core/icons/expand-horizontal.tsx delete mode 100644 apps/zui/src/app/core/icons/expand.tsx delete mode 100644 apps/zui/src/app/core/icons/export.tsx delete mode 100644 apps/zui/src/app/core/icons/file-border.tsx delete mode 100644 apps/zui/src/app/core/icons/file-filled.tsx delete mode 100644 apps/zui/src/app/core/icons/folder.tsx delete mode 100644 apps/zui/src/app/core/icons/grid.tsx delete mode 100644 apps/zui/src/app/core/icons/hide.tsx delete mode 100644 apps/zui/src/app/core/icons/history.tsx delete mode 100644 apps/zui/src/app/core/icons/index.ts delete mode 100644 apps/zui/src/app/core/icons/lamda.tsx delete mode 100644 apps/zui/src/app/core/icons/left-arrow.tsx delete mode 100644 apps/zui/src/app/core/icons/list.tsx delete mode 100644 apps/zui/src/app/core/icons/lock.tsx delete mode 100644 apps/zui/src/app/core/icons/pin.tsx delete mode 100644 apps/zui/src/app/core/icons/plus.tsx delete mode 100644 apps/zui/src/app/core/icons/pool.tsx delete mode 100644 apps/zui/src/app/core/icons/query.tsx delete mode 100644 apps/zui/src/app/core/icons/reload.tsx delete mode 100644 apps/zui/src/app/core/icons/right-arrow.tsx delete mode 100644 apps/zui/src/app/core/icons/right-sidebar-toggle.tsx delete mode 100644 apps/zui/src/app/core/icons/run.tsx delete mode 100644 apps/zui/src/app/core/icons/sharkfin.tsx delete mode 100644 apps/zui/src/app/core/icons/show.tsx delete mode 100644 apps/zui/src/app/core/icons/sidebar-toggle.tsx delete mode 100644 apps/zui/src/app/core/icons/snippet.tsx delete mode 100644 apps/zui/src/app/core/icons/sort-asc.tsx delete mode 100644 apps/zui/src/app/core/icons/sort-desc.tsx delete mode 100644 apps/zui/src/app/core/icons/tag.tsx delete mode 100644 apps/zui/src/app/core/icons/three-dots-stacked.tsx delete mode 100644 apps/zui/src/app/core/icons/three-dots.tsx delete mode 100644 apps/zui/src/app/core/icons/update.tsx delete mode 100644 apps/zui/src/app/core/icons/view.tsx delete mode 100644 apps/zui/src/app/core/icons/warning.tsx delete mode 100644 apps/zui/src/app/core/icons/zui.tsx delete mode 100644 apps/zui/src/app/features/inspector/list.styled.tsx delete mode 100644 apps/zui/src/app/menus/new-pin-menu.ts delete mode 100644 apps/zui/src/app/query-home/editor-resizer.tsx delete mode 100644 apps/zui/src/app/query-home/flows/new-tab.ts delete mode 100644 apps/zui/src/app/query-home/flows/submit-search.ts delete mode 100644 apps/zui/src/app/query-home/index.tsx delete mode 100644 apps/zui/src/app/query-home/query-home.module.css delete mode 100644 apps/zui/src/app/query-home/results/data-hook.ts delete mode 100644 apps/zui/src/app/query-home/results/results.styled.tsx delete mode 100644 apps/zui/src/app/query-home/search-area/index.tsx delete mode 100644 apps/zui/src/app/query-home/search-area/pins/base-pin.tsx delete mode 100644 apps/zui/src/app/query-home/search-area/pins/from-pin/from-pin.tsx delete mode 100644 apps/zui/src/app/query-home/search-area/pins/from-pin/show-menu.ts delete mode 100644 apps/zui/src/app/query-home/search-area/pins/generic-pin/generic-pin.tsx delete mode 100644 apps/zui/src/app/query-home/search-area/pins/new-pin-button.tsx delete mode 100644 apps/zui/src/app/query-home/search-area/pins/pin-context-menu.ts delete mode 100644 apps/zui/src/app/query-home/search-area/pins/pins.tsx delete mode 100644 apps/zui/src/app/query-home/search-area/pins/placeholder-pin.tsx delete mode 100644 apps/zui/src/app/query-home/search-area/pins/time-range-pin/time-range-pin.tsx delete mode 100644 apps/zui/src/app/query-home/search-area/popup-position.ts delete mode 100644 apps/zui/src/app/query-home/title-bar/button.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/context.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/detatch-button.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/heading-button.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/heading-form.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/heading-menu.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/heading-saved.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/heading.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/icon-button.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/nav-actions.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/orange-tag.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/plus-one.test.ts delete mode 100644 apps/zui/src/app/query-home/title-bar/query-actions.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/title-bar.tsx delete mode 100644 apps/zui/src/app/query-home/title-bar/use-heading-form.ts delete mode 100644 apps/zui/src/app/query-home/toolbar/actions/button.tsx delete mode 100644 apps/zui/src/app/query-home/toolbar/results-toolbar.tsx delete mode 100644 apps/zui/src/app/query-home/toolbar/results-view-switch.tsx create mode 100644 apps/zui/src/components/icon/icon-names.ts create mode 100644 apps/zui/src/components/icon/icon.module.css create mode 100644 apps/zui/src/components/icon/index.tsx create mode 100644 apps/zui/src/components/icon/ming-cute-names.ts create mode 100644 apps/zui/src/components/tooltip.module.css create mode 100644 apps/zui/src/components/tooltip.tsx rename apps/zui/src/{app/query-home/search-area => components}/zed-editor.tsx (88%) delete mode 100644 apps/zui/src/core/command.ts delete mode 100644 apps/zui/src/core/menu/built-menu.ts delete mode 100644 apps/zui/src/core/menu/global-menus.ts create mode 100644 apps/zui/src/core/menu/handle-click.ts delete mode 100644 apps/zui/src/core/menu/menu-manager.ts delete mode 100644 apps/zui/src/core/menu/menu-node.ts delete mode 100644 apps/zui/src/core/menu/menu.ts create mode 100644 apps/zui/src/core/menu/to-electron.ts create mode 100644 apps/zui/src/core/menu/use-menu-extension.ts delete mode 100644 apps/zui/src/core/menu/use-menu-instance.ts delete mode 100644 apps/zui/src/css/_chart-elements.scss delete mode 100644 apps/zui/src/css/_circle-chevron.scss delete mode 100644 apps/zui/src/css/_click-feedback.scss delete mode 100644 apps/zui/src/css/_column-chooser.scss delete mode 100644 apps/zui/src/css/_column-description.scss delete mode 100644 apps/zui/src/css/_download-progress.scss create mode 100644 apps/zui/src/css/_editor.scss delete mode 100644 apps/zui/src/css/_filter-node.scss delete mode 100644 apps/zui/src/css/_filter-tree.scss delete mode 100644 apps/zui/src/css/_header-cell.scss delete mode 100644 apps/zui/src/css/_history-pane.scss delete mode 100644 apps/zui/src/css/_icons.scss delete mode 100644 apps/zui/src/css/_info-notice.scss delete mode 100644 apps/zui/src/css/_input-suggestions.scss delete mode 100644 apps/zui/src/css/_log-cell.scss delete mode 100644 apps/zui/src/css/_log-viewer.scss delete mode 100644 apps/zui/src/css/_packet-post-progress.scss delete mode 100644 apps/zui/src/css/_pop-menu.scss delete mode 100644 apps/zui/src/css/_saved-pools-list.scss delete mode 100644 apps/zui/src/css/_search-results.scss delete mode 100644 apps/zui/src/css/_settings-modal.scss delete mode 100644 apps/zui/src/css/_time-span-pickers.scss delete mode 100644 apps/zui/src/css/_toolbar-button.scss create mode 100644 apps/zui/src/css/_tooltip-animation.scss delete mode 100644 apps/zui/src/css/_tooltip.scss delete mode 100644 apps/zui/src/css/forms/_file-input.scss delete mode 100644 apps/zui/src/css/forms/_global.scss delete mode 100644 apps/zui/src/css/forms/_main.scss delete mode 100644 apps/zui/src/css/forms/_mixins.scss delete mode 100644 apps/zui/src/css/forms/_select-input.scss delete mode 100644 apps/zui/src/css/forms/_text-input.scss delete mode 100644 apps/zui/src/domain/commands.ts create mode 100644 apps/zui/src/domain/commands/messages.ts create mode 100644 apps/zui/src/domain/commands/operations.ts create mode 100644 apps/zui/src/domain/commands/plugin-api.ts create mode 100644 apps/zui/src/domain/editor/handlers.ts create mode 100644 apps/zui/src/domain/editor/messages.ts delete mode 100644 apps/zui/src/domain/menus.ts delete mode 100644 apps/zui/src/domain/menus/handlers.ts create mode 100644 apps/zui/src/domain/menus/operations.ts create mode 100644 apps/zui/src/domain/menus/plugin-api.ts delete mode 100644 apps/zui/src/domain/panes/commands.ts delete mode 100644 apps/zui/src/domain/results/commands.ts delete mode 100644 apps/zui/src/domain/results/toolbar-menu.ts delete mode 100644 apps/zui/src/domain/session/commands.ts delete mode 100644 apps/zui/src/domain/session/handlers.ts create mode 100644 apps/zui/src/domain/session/handlers/index.ts create mode 100644 apps/zui/src/domain/session/handlers/navigation.ts create mode 100644 apps/zui/src/domain/session/handlers/pins.ts create mode 100644 apps/zui/src/domain/session/handlers/queries.ts create mode 100644 apps/zui/src/domain/session/handlers/submit-search.ts create mode 100644 apps/zui/src/domain/session/menus/choose-pool-menu.ts create mode 100644 apps/zui/src/domain/session/menus/edit-pin.menu.ts create mode 100644 apps/zui/src/domain/session/menus/toolbar-menu.ts delete mode 100644 apps/zui/src/electron/html-dialog/dialog.html delete mode 100644 apps/zui/src/electron/html-dialog/dialog.style.tsx delete mode 100644 apps/zui/src/electron/html-dialog/dialog.tsx delete mode 100644 apps/zui/src/electron/html-dialog/index.ts delete mode 100644 apps/zui/src/electron/ops/get-menu-template-op.ts delete mode 100644 apps/zui/src/electron/ops/invoke-command-op.ts delete mode 100644 apps/zui/src/initializers/commands.ts delete mode 100644 apps/zui/src/initializers/menus.ts delete mode 100644 apps/zui/src/js/api/layout-api.ts delete mode 100644 apps/zui/src/js/components/CircleChevron.tsx delete mode 100644 apps/zui/src/js/components/FilterNode.tsx delete mode 100644 apps/zui/src/js/components/InfoNotice.tsx delete mode 100644 apps/zui/src/js/components/LakeModals/StatusLight.tsx delete mode 100644 apps/zui/src/js/components/LogDetails/ColumnDescription.tsx delete mode 100644 apps/zui/src/js/components/MenuBarButton.tsx delete mode 100644 apps/zui/src/js/components/ModalBox/Buttons.tsx delete mode 100644 apps/zui/src/js/components/ModalBox/ModalBox.tsx delete mode 100644 apps/zui/src/js/components/ModalBox/ModalContents.tsx delete mode 100644 apps/zui/src/js/components/ModalBox/types.ts delete mode 100644 apps/zui/src/js/components/ModalBox/useModalController.ts delete mode 100644 apps/zui/src/js/components/Notice.tsx delete mode 100644 apps/zui/src/js/components/StartupError.tsx rename apps/zui/src/{app/query-home/hooks => js/components/TabBar}/use-query-id-name-map.ts (100%) delete mode 100644 apps/zui/src/js/components/Tooltip.tsx delete mode 100644 apps/zui/src/js/icons/ThreeDotsIcon.tsx create mode 100644 apps/zui/src/js/initializers/init-resize-listener.ts delete mode 100644 apps/zui/src/js/state/QueryVersions/flows/save-query-version.ts delete mode 100644 apps/zui/src/js/state/ResultsToolbar/selectors.ts delete mode 100644 apps/zui/src/js/state/ResultsToolbar/slice.ts rename apps/zui/src/js/state/{ResultsToolbar => Selection}/index.ts (53%) create mode 100644 apps/zui/src/js/state/Selection/reducer.ts create mode 100644 apps/zui/src/js/state/Selection/selectors.ts create mode 100644 apps/zui/src/js/state/Table/selectors.ts create mode 100644 apps/zui/src/js/state/Table/types.ts delete mode 100644 apps/zui/src/ppl/css/_load-files-input.scss delete mode 100644 apps/zui/src/ppl/import/DataFileIcon.tsx delete mode 100644 apps/zui/src/ppl/import/LoadFilesInput.tsx create mode 100644 apps/zui/src/util/find-ancestor.ts create mode 100644 apps/zui/src/util/hooks/use-color-scheme.ts create mode 100644 apps/zui/src/util/objectify.ts rename apps/zui/src/{app/query-home/title-bar => util}/plus-one.ts (100%) create mode 100644 apps/zui/src/util/tree.ts rename apps/zui/src/{app/query-home/results => views/results-pane}/alert-view.ts (100%) rename apps/zui/src/{app/query-home/results => views/results-pane}/bare-string-view.ts (100%) rename apps/zui/src/{app/query-home/results => views/results-pane}/path-view.ts (100%) create mode 100644 apps/zui/src/views/session-page/detail-bar.module.css create mode 100644 apps/zui/src/views/session-page/detail-bar.tsx create mode 100644 apps/zui/src/views/session-page/editor-resizer.tsx create mode 100644 apps/zui/src/views/session-page/editor.module.css create mode 100644 apps/zui/src/views/session-page/editor.tsx create mode 100644 apps/zui/src/views/session-page/footer.module.css create mode 100644 apps/zui/src/views/session-page/footer.tsx create mode 100644 apps/zui/src/views/session-page/grid.module.css create mode 100644 apps/zui/src/views/session-page/grid.tsx create mode 100644 apps/zui/src/views/session-page/index.module.css create mode 100644 apps/zui/src/views/session-page/index.tsx rename apps/zui/src/{app/query-home => views/session-page}/loader.ts (97%) create mode 100644 apps/zui/src/views/session-page/pins.module.css create mode 100644 apps/zui/src/views/session-page/pins.tsx create mode 100644 apps/zui/src/views/session-page/pins/base-pin.tsx rename apps/zui/src/{app/query-home/search-area => views/session-page}/pins/dialog.tsx (94%) rename apps/zui/src/{app/query-home/search-area => views/session-page}/pins/form-helpers.tsx (98%) rename apps/zui/src/{app/query-home/search-area/pins/generic-pin/form.tsx => views/session-page/pins/generic-pin-form.tsx} (89%) rename apps/zui/src/{app/query-home/search-area/pins/time-range-pin => views/session-page/pins}/get-time-preview.test.ts (100%) rename apps/zui/src/{app/query-home/search-area/pins/time-range-pin => views/session-page/pins}/get-time-string.ts (100%) rename apps/zui/src/{app/query-home/search-area/pins/time-range-pin/form.tsx => views/session-page/pins/time-range-pin-form.tsx} (93%) rename apps/zui/src/{app/query-home/search-area => views/session-page}/pins/use-pin-dnd.ts (100%) create mode 100644 apps/zui/src/views/session-page/results.module.css create mode 100644 apps/zui/src/views/session-page/results.tsx rename apps/zui/src/{app/query-home => views/session-page}/route.tsx (80%) create mode 100644 apps/zui/src/views/session-page/toolbar.module.css create mode 100644 apps/zui/src/views/session-page/toolbar.tsx create mode 100644 apps/zui/src/views/session-page/use-title-form.ts delete mode 100644 apps/zui/src/zui/commands.ts delete mode 100644 apps/zui/src/zui/menus.ts create mode 100644 packages/zui-player/tests/packets.spec.ts create mode 100644 packages/zui-player/tests/right-click-menus.spec.ts diff --git a/apps/zui/build/preload.js b/apps/zui/build/preload.js index e7972c94f9..0e9db7e3d7 100644 --- a/apps/zui/build/preload.js +++ b/apps/zui/build/preload.js @@ -1,8 +1,12 @@ const {contextBridge, ipcRenderer} = require("electron") const preloadApi = () => ({ - on: ipcRenderer.on.bind(ipcRenderer), - off: ipcRenderer.off.bind(ipcRenderer), + on: (channel, handler) => { + ipcRenderer.on(channel, handler) + return () => { + ipcRenderer.off(channel, handler) + } + }, once: ipcRenderer.once.bind(ipcRenderer), invoke: ipcRenderer.invoke.bind(ipcRenderer), }) diff --git a/apps/zui/package.json b/apps/zui/package.json index 81794682ab..2884b3ed91 100644 --- a/apps/zui/package.json +++ b/apps/zui/package.json @@ -139,7 +139,6 @@ "react-redux": "^8.0.5", "react-router": "5.3.1", "react-spring": "^8.0.27", - "react-tooltip": "^4.2.7", "react-transition-group": "^4.4.5", "react-window": "^1.8.7", "regenerator-runtime": "^0.13.6", diff --git a/apps/zui/pages/detail.tsx b/apps/zui/pages/detail.tsx index 323c8bd170..8e50e80c1b 100644 --- a/apps/zui/pages/detail.tsx +++ b/apps/zui/pages/detail.tsx @@ -4,7 +4,7 @@ import {AppProvider} from "src/app/core/context" import AppWindowRouter from "src/app/router/app-window-router" import LogDetailsWindow from "src/js/components/LogDetailsWindow" import {Modals} from "src/js/components/Modals" -import Tooltip from "src/js/components/Tooltip" +import {Tooltip} from "src/components/tooltip" import initialize from "src/js/initializers/initialize" import TabHistories from "src/js/state/TabHistories" import Tabs from "src/js/state/Tabs" diff --git a/apps/zui/project.json b/apps/zui/project.json index 0fd3d43d8e..e4b7db75f8 100644 --- a/apps/zui/project.json +++ b/apps/zui/project.json @@ -4,7 +4,7 @@ "sourceRoot": "apps/zui", "projectType": "app", "targets": { - "watch-tsc": { + "tsc-watch": { "command": "tsc -p apps/zui/tsconfig.json --watch" }, "lint": { diff --git a/apps/zui/public/custom-icons.svg b/apps/zui/public/custom-icons.svg new file mode 100644 index 0000000000..576a2cf05c --- /dev/null +++ b/apps/zui/public/custom-icons.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/apps/zui/public/icons.svg b/apps/zui/public/icons.svg new file mode 100644 index 0000000000..205f3ed189 --- /dev/null +++ b/apps/zui/public/icons.svg @@ -0,0 +1,13450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/zui/public/icons/file-border.tsx b/apps/zui/public/icons/file-border.tsx deleted file mode 100644 index 4b54872a5f..0000000000 --- a/apps/zui/public/icons/file-border.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from "react" - -export default function FileBorder(props: any) { - return ( - - - - - ) -} diff --git a/apps/zui/public/icons/subspace-border.svg b/apps/zui/public/icons/subspace-border.svg deleted file mode 100644 index 72ebbf49c3..0000000000 --- a/apps/zui/public/icons/subspace-border.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/apps/zui/public/icons/subspace.svg b/apps/zui/public/icons/subspace.svg deleted file mode 100644 index fe50168c66..0000000000 --- a/apps/zui/public/icons/subspace.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/apps/zui/public/main.css b/apps/zui/public/main.css deleted file mode 100644 index 2806f457ba..0000000000 --- a/apps/zui/public/main.css +++ /dev/null @@ -1,3944 +0,0 @@ -/* This file is for your main application css. */ -/* Settings */ -@font-face { - font-family: "Recursive"; - src: url(/fonts/recursive.woff2) format("woff2-variations"); - font-style: oblique 0deg 15deg; - font-weight: 300 1000; - font-display: block; -} -:root { - --mono-font: "Recursive"; - --body-font: "system-ui"; - /* Recursive settings */ - --mono: "MONO" 1; - /* Monospace: Sans (natural-width) or Mono (fixed-width) */ - --casl: "CASL" 0; - /* Casual: Linear to Casual */ - --slnt: "slnt" 0; - /* Slant: 0 to -15 degrees, auto cursive at -14 */ - --CRSV: "CRSV" 0.5; - /* Cursive: always roman, auto substitution, or always cursive */ - font-variation-settings: var(--mono), var(--casl), var(--wght), var(--slnt), - var(--CRSV); -} - -:root { - --red: #cd1313; - --green: #399c81; - --green-bright: #4ef567; - --orange: #ff7f00; - --yellow: #ffc933; - --azure: #2f629c; - --cello: hsl(212, 100%, 14%); - --cello-transparent: hsla(212, 100%, 14%, 0.92); - --havelock: #4b91e2; - --hawkes-blue: rgba(206, 228, 253, 0.5); - --pecan: #9c692f; - --snow: #fcfcfd; - --coconut: #f7f7f8; - --ivory: #f3f3f4; - --cloudy: #e2e6e9; - --lead: #abadaf; - --slate: #717375; - --wet-cement: #4c5661; - --aqua: #0f1e2e; - --aqua-transparent: rgba(15, 30, 46, 0.2); - --alert-3: #fbc00e; - --alert-2: #f4912f; - --alert-1: #d0250b; - --hover-light-bg: rgba(0, 0, 0, 0.06); - --table-stripe-bg: rgba(0, 0, 0, 0.02); - --input-background: hsl(240, 15%, 92%); - --sidebar-background: hsl(212, 8%, 85%); - --sidebar-item-hover: hsl(212, 15%, 85%); - --sidebar-item-active: hsl(212, 15%, 83%); - --tab-background: hsl(212, 4%, 88%); - --tab-background-hover: hsl(212, 15%, 96%); - --primary-color-lighter: hsl(212, 72%, 75%); - --primary-color-light: hsl(212, 72%, 69%); - --primary-color: hsl(212, 72%, 59%); - --primary-color-dark: hsl(212, 72%, 53%); - --primary-color-darker: hsl(212, 72%, 48%); - --foreground-color: var(--aqua); - --button-background: hsl(212, 5%, 92%); - --button-background-hover: hsl(212, 5%, 90%); - --button-background-active: hsl(212, 5%, 87%); - --editor-background: white; - --border-color: hsl(216, 10%, 87%); - --border-color-dark: hsl(216, 10%, 80%); - --chrome-color: hsl(212, 10%, 97%); -} - -/* Shared */ -:root { - --shadow-color: 0deg 0% 68%; - --shadow-elevation-low: 0.4px 0.5px 1px hsl(var(--shadow-color) / 0), - 0.7px 1px 1.8px hsl(var(--shadow-color) / 0.19), - 1.3px 1.9px 3.5px hsl(var(--shadow-color) / 0.38); - --shadow-elevation-medium: 0.4px 0.5px 1px hsl(var(--shadow-color) / 0), - 1.4px 2px 3.7px hsl(var(--shadow-color) / 0.1), - 2.3px 3.4px 6.2px hsl(var(--shadow-color) / 0.19), - 3.9px 5.7px 10.4px hsl(var(--shadow-color) / 0.29), - 6.7px 9.7px 17.7px hsl(var(--shadow-color) / 0.38); - --shadow-elevation-high: 0.4px 0.5px 1px hsl(var(--shadow-color) / 0), - 2.6px 3.8px 6.9px hsl(var(--shadow-color) / 0.04), - 4.6px 6.6px 12.1px hsl(var(--shadow-color) / 0.09), - 6.5px 9.4px 17.1px hsl(var(--shadow-color) / 0.13), - 8.6px 12.4px 22.6px hsl(var(--shadow-color) / 0.18), - 11.1px 16px 29.2px hsl(var(--shadow-color) / 0.22), - 14.3px 20.7px 37.7px hsl(var(--shadow-color) / 0.27), - 18.4px 26.6px 48.5px hsl(var(--shadow-color) / 0.31), - 23.7px 34.3px 62.5px hsl(var(--shadow-color) / 0.35), - 30.4px 44px 80.2px hsl(var(--shadow-color) / 0.4); -} - -:root { - --zed-null: var(--lead); - --zed-time: hsl(275, 55%, 50%); - --zed-symbol: hsl(212, 95%, 55%); - --zed-type: hsla(212, 70%, 50%); - --interval: #544aa6; - --bool: #3eaef4; - --zed-string: hsl(130, 54%, 38%); - --zed-key: hsl(212, 20%, 40%); - --zed-number: #e65835; - --zed-syntax: hsl(212, 17%, 55%); - --zed-note: hsl(212, 17%, 80%); - --zed-container: var(--foreground-color); -} - -.zed-syntax { - color: var(--zed-syntax); -} - -.zed-key { - color: var(--zed-key); -} - -.zed-ip, -.zed-net { - color: var(--zed-symbol); -} - -.zed-duration { - color: var(--zed-symbol); -} - -.zed-uint8, -.zed-uint16, -.zed-uint32, -.zed-uint64, -.zed-int8, -.zed-int16, -.zed-int32, -.zed-int64, -.zed-float64, -.zed-float32, -.zed-float16 { - color: var(--zed-number); -} - -.zed-bool { - color: var(--zed-symbol); -} - -.zed-time { - color: var(--zed-time); -} - -.zed-null { - color: var(--zed-null); -} - -.zed-string { - color: var(--zed-string); -} - -.zed-error { - color: hsl(6deg, 97%, 40%); -} - -.zed-type { - color: var(--zed-symbol); -} - -.zed-annotation { - color: var(--zed-type); - font-weight: bold; -} - -.zed-note { - color: var(--zed-note); - font-style: italic; -} - -.zed-container { - color: var(--zed-container); -} - -.paragraph { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; - margin: 0; -} - -.mono, -.table td { - font-family: var(--mono-font); - font-weight: normal; - font-size: 12px; - line-height: 16px; - margin: 0; -} - -.code { - display: inline-block; - font-family: var(--mono-font); - font-size: 12px; - line-height: 14px; - padding: 3px 6px; - margin: 0; -} -.code.full { - width: 100%; -} -.code.light { - background-color: rgba(0, 0, 0, 0.04); - box-shadow: inset 0px 0px 2px 0 rgba(0, 0, 0, 0.1); - padding: 12px 24px; -} - -.fieldset { - font-size: 12px; - font-weight: 700; - line-height: 15px; - margin: 0; - font-family: system-ui, sans-serif; -} - -.subscript { - font-family: system-ui, sans-serif; - font-size: 9px; - font-weight: normal; - line-height: 11px; - margin: 0; -} - -.stats { - font-family: var(--mono-font); - font-size: 12px; - font-weight: normal; - line-height: 12px; -} - -.label, -.inline-table th { - font-family: system-ui, sans-serif; - font-size: 0.625rem; - line-height: 15px; - font-weight: normal; - margin: 0; -} - -.link { - font-family: system-ui, sans-serif; - font-weight: normal; - font-size: 14px; - line-height: 20px; - margin: 0; - text-decoration: underline; - cursor: pointer; - color: var(--havelock); -} - -.bold { - font-weight: bold; -} - -.underline { - text-decoration: underline; -} - -.link-button { - font-size: 11px; - text-transform: uppercase; - padding: 4.584px 7.417px; - border-radius: 3px; - cursor: pointer; - display: inline-block; - transform: translateY(0px); - user-select: none; - text-align: center; -} -.link-button:hover { - transition: background-color 100ms; - background: rgba(255, 255, 255, 0.1); -} -.link-button:active { - background: rgba(255, 255, 255, 0.2); - transform: translateY(2px); -} - -/* Forms */ -::placeholder { - color: var(--lead); -} - -.text-input { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; - box-shadow: inset 0 0 0 0.5px var(--lead), inset 0 0 0 1px white; - width: 100%; - color: var(--aqua); - background: var(--ivory); - padding: 3px 8px; - border-radius: 4px; - border: none; -} -.text-input:focus, -.text-input:active { - z-index: 1; - box-shadow: 0 0 0 2px var(--havelock); - outline: none !important; -} - -.select-input { - height: 24px; - width: 100%; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; - box-shadow: inset 0 0 0 0.5px var(--lead), inset 0 0 0 1px white; - color: var(--aqua); - background: var(--ivory); - border: none; -} -.select-input:focus, -.select-input:active { - z-index: 1; - box-shadow: 0 0 0 2px var(--havelock); - outline: none !important; -} - -.file-input { - box-shadow: inset 0 0 0 0.5px var(--lead), inset 0 0 0 1px white; - display: flex; - align-items: stretch; - border-radius: 4px; -} -.file-input button { - background: linear-gradient(#ffffff, 0.5px, #fefefe 2px, #f6f6f6); - margin: 1px 0 1px 1px; - border-radius: 4px 0 0 4px; - border: none; -} -.file-input button:active:not(:disabled) { - background: linear-gradient(#fefefe, 0.5px, #f3f3f3 2px); -} -.file-input button:focus { - z-index: 1; -} -.file-input .text-input { - border-radius: 0 4px 4px 0; -} - -/* Specific */ -*, -*::before, -*::after { - box-sizing: border-box; -} - -* { - margin: 0; -} - -html, -body { - height: 100%; - width: 100%; -} - -body { - line-height: 1.5; - -webkit-font-smoothing: antialiased; - font-family: var(--body-font); - color: var(--foreground-color); - background-color: var(--background-color); - font-size: 14px; -} - -input, -button, -textarea, -select { - font: inherit; -} - -p, -h1, -h2, -h3, -h4, -h5, -h6 { - overflow-wrap: break-word; -} - -pre, -code { - border-radius: 3px; - font-family: var(--mono-font); -} - -pre { - overflow-x: scroll; -} - -code { - padding: 2px 3px; -} - -body.no-select { - user-select: none; -} - -body.col-resize { - cursor: col-resize; -} - -.panel-button { - display: flex; - align-items: center; - justify-content: center; - padding: 6px; - height: 28px; - width: 28px; - background: none; - border: none; - border-radius: 3px; -} -.panel-button svg { - fill: var(--slate); - height: 100%; - width: 100%; -} -.panel-button:hover { - transition: background-color 100ms; - background: rgba(0, 0, 0, 0.05); -} -.panel-button:active { - background-color: rgba(0, 0, 0, 0.1); - transform: translateY(2px); -} -.panel-button:disabled svg { - fill: var(--cloudy); -} -.panel-button:disabled:hover { - background: none; -} -.panel-button:disabled:active { - box-shadow: none; - transform: none; -} -.panel-button.text { - width: auto; -} - -.close-button { - width: 30px; - height: 30px; - padding: 0; - border: none; - display: flex; - align-items: center; - justify-content: center; - outline: none; - background: none; - position: relative; -} -.close-button svg { - height: 10px; - width: 10px; - stroke: none; - fill: var(--slate); - transition: fill 50ms; -} -.close-button:hover svg { - fill: var(--aqua); -} -.close-button:active svg { - fill: var(--slate); -} - -svg.icon { - width: 1rem; - height: 1rem; - fill: var(--slate); -} - -.text-content { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; -} -.text-content > * { - margin: 0; - margin-bottom: 20px; -} -.text-content pre { - padding: 12px 24px; - overflow: hidden; - font-size: 11px; -} - -#app-root, -#__next { - height: 100%; - width: 100%; -} - -body > div { - position: fixed; -} - -#measure-layer { - top: 0; - z-index: -1; -} - -.modal-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0); - display: flex; - justify-content: center; - align-items: flex-start; - overflow-x: hidden; - overflow-y: auto; - padding: 2rem; - padding-top: 4rem; - z-index: 2; -} - -.modal-contents { - -webkit-app-region: no-drag; - background: white; - box-shadow: 12px 12px 48px rgba(0, 0, 0, 0.45); - padding: 20px 20px 0 20px; - border-radius: 5px; - position: relative; - width: 680px; - max-width: 100%; - max-height: 100%; - display: flex; - flex-direction: column; - -webkit-backface-visibility: hidden; - -webkit-transform: translateZ(0) scale(1, 1); - transform: translateZ(0); -} -.modal-contents .modal-header { - margin-bottom: 20px; - flex: 0 0 auto; - min-height: 0; - user-select: none; -} -.modal-contents .modal-body { - display: flex; - min-height: 0; - flex-direction: column; -} -.modal-contents .close-button { - position: absolute; - top: 0; - right: 0; -} -.modal-contents .button-row { - flex: 0 0; -} - -.conn-versation { - margin-bottom: 12px; - display: flex; - justify-content: space-between; - user-select: none; -} -.conn-versation td, -.conn-versation th { - white-space: nowrap; - user-select: all; -} -.conn-versation .host { - border: 1px solid var(--cloudy); - border-radius: 3px; -} -.conn-versation .fieldset { - text-align: center; - padding: 6px 3px; -} -.conn-versation .ip, -.conn-versation .port { - margin: 0; - color: white; - background: var(--havelock); - font-size: 12px; - text-align: center; - line-height: 20px; - font-family: var(--mono-font); - user-select: all; -} -.conn-versation .ip.small { - font-size: 8px; -} -.conn-versation .port { - background: #65bef6; -} -.conn-versation .responder .ip { - background: var(--green); -} -.conn-versation .responder .port { - background: #5ec4a8; -} -.conn-versation .history { - align-self: center; - flex: 1; - padding: 12px; -} -.conn-versation .history-packet { - display: flex; - align-items: center; - line-height: 18px; -} -.conn-versation .history-packet span { - font-weight: bold; - font-family: var(--mono-font); - text-transform: uppercase; - font-size: 12px; - padding: 1px 6px; -} -.conn-versation .history-packet hr { - flex: 1; - border: none; - border-bottom: 1px solid var(--yellow); - margin: 0; -} -.conn-versation .history-packet .triangle { - fill: var(--yellow); - stroke: var(--yellow); - width: 10px; -} -.conn-versation .history-packet.arrow-right { - padding-right: 6px; -} -.conn-versation .history-packet.arrow-left { - padding-left: 6px; -} -.conn-versation .history-packet.arrow-left .triangle { - order: 1; - transform: rotate(180deg); -} -.conn-versation .history-packet.arrow-left hr { - order: 2; -} -.conn-versation .history-packet.arrow-left span { - order: 3; -} - -.chart { - height: 100px; - position: relative; -} -.chart .selection { - fill: var(--havelock); - stroke: var(--havelock); - stroke-dasharray: 3px; -} -.chart .loading-message, -.chart .no-chart-data { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; - margin: 0; - position: absolute; - user-select: none; - pointer-events: none; - z-index: 0; - left: 50%; - top: 47%; - transform: translate(-50%, -50%); - color: var(--lead); -} -.chart .loading-message .burst, -.chart .no-chart-data .burst { - background-color: var(--lead); -} -.chart .no-chart-data { - opacity: 0; -} -.chart .no-chart-data.visible { - opacity: 1; -} -.chart .tooltip { - opacity: 0; - position: absolute; - height: 30px; - white-space: nowrap; - display: flex; - align-items: center; - font-size: 12px; - padding: 0 10px; - background: white; - box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.3); - pointer-events: none; - transition: all 100ms; - font-family: var(--mono-font); -} -.chart .tooltip span.path { - display: inline-block; - text-align: center; - color: white; - padding: 0 6px; - border-radius: 3px; - font-weight: bold; -} - -.chart svg { - display: block; -} -.chart svg .tick line { - stroke: var(--cloudy); -} -.chart svg .tick text { - pointer-events: none; - user-select: none; -} -.chart svg .x-axis-drag { - cursor: ew-resize; -} -.chart svg .domain { - stroke: var(--cloudy); -} -.chart svg text { - font-family: var(--mono-font); - fill: var(--lead); - font-size: 9px; -} - -.chart-tooltip { - font-family: var(--mono-font); - opacity: 0; -} - -.y-axis-single-tick text { - transform: translate(-2px, -6px); -} - -.filter-node { - display: inline-flex; - align-items: center; - background: var(--green); - border-radius: 3px; - margin-bottom: 3px; - position: relative; - box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.5); - border: 1px solid transparent; - transition: all 50ms; -} -.filter-node p { - font-family: var(--mono-font); - color: white; - font-size: 9px; - line-height: 13px; - padding: 0 4px; - border-radius: 3px; - margin: 0; -} -.filter-node .remove-button { - display: none; -} -.filter-node:hover .remove-button { - display: flex; -} -.filter-node:hover .remove-button .circle { - fill: var(--wet-cement); - opacity: 0.5; -} -.filter-node:hover .remove-button:hover .circle { - opacity: 0.8; -} -.filter-node:hover .remove-button:active .circle { - opacity: 1; -} -.filter-node.focused { - border: 1px solid var(--yellow); - background: #5ec4a8; -} - -.filter-tree { - height: 100%; - color: white; - margin-top: 10px; - user-select: none; -} -.filter-tree .filter-tree-parent { - display: flex; - align-items: center; - margin: 0; - height: 24px; -} - -.filter-tree-parent:hover { - background: var(--hover-light-bg); -} - -.filter-tree-node { - position: relative; - margin-left: 19.416px; - padding: 2px 0; -} -.filter-tree-node .filter-tree-parent::before { - content: ""; - width: 1px; - height: 27px; - position: absolute; - background: var(--cloudy); - top: -3px; - left: 0; -} -.filter-tree-node:last-of-type > .filter-tree-parent::before { - height: 17px; -} -.filter-tree-node .filter-tree-children::before { - content: ""; - width: 1px; - height: 100%; - position: absolute; - background: var(--cloudy); - top: 0; - left: 0; -} -.filter-tree-node:last-of-type > .filter-tree-children::before { - display: none; -} -.filter-tree-node .filter-node { - background: transparent; - position: relative; - margin: 0 0 0 6px; - box-shadow: none; - height: 16px; -} -.filter-tree-node .filter-node p { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; - line-height: 16px; - color: var(--aqua); - padding: 2px; - margin: 0 2px; - overflow-x: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.filter-tree-node .filter-node:before { - content: ""; - position: absolute; - background: var(--cloudy); - width: 6px; - height: 1px; - right: calc(100% + 1px); -} -.filter-tree-node.pinned > .filter-tree-parent > .filter-node { - background: var(--green); -} -.filter-tree-node.pinned > .filter-tree-parent > .filter-node p { - color: white; -} -.filter-tree-node.active > .filter-tree-parent > .filter-node { - background: var(--slate); -} -.filter-tree-node.active > .filter-tree-parent > .filter-node p { - color: white; -} - -.left-arrow { - border-left: 2px solid white; - border-bottom: 2px solid white; - display: inline-block; - border-radius: 0 0 0 1px; - padding: 2px; - margin: 0 12px; - transform: rotate(45deg); -} - -.up-arrow { - border-left: 2px solid white; - border-bottom: 2px solid white; - display: inline-block; - border-radius: 0 0 0 1px; - padding: 2px; - margin: 0 12px; - transform: rotate(135deg); -} - -.right-arrow { - border-left: 2px solid white; - border-bottom: 2px solid white; - display: inline-block; - border-radius: 0 0 0 1px; - padding: 2px; - margin: 0 12px; - transform: rotate(225deg); -} - -.down-arrow { - border-left: 2px solid white; - border-bottom: 2px solid white; - display: inline-block; - border-radius: 0 0 0 1px; - padding: 2px; - margin: 0 12px; - transform: rotate(315deg); -} - -.viewer { - overflow: visible; - height: 0; - width: 0; -} -.viewer *::selection { - background: transparent; -} -.using-keyboard .viewer:focus { - outline: none; -} - -.viewer .view { - overflow: scroll; - display: flex; -} - -.viewer .list { - position: relative; -} - -.viewer .chunk { - position: absolute; -} - -.viewer .log-row { - white-space: nowrap; - contain: layout style; - display: flex; - font-family: var(--mono-font); - font-size: 12px; - white-space: nowrap; - min-height: 25px; - line-height: 25px; - align-items: center; - opacity: 1; - padding-left: 16px; -} -.viewer .log-row.even { - background: var(--table-stripe-bg); -} -.viewer .log-row:hover { - background: var(--hover-light-bg); -} -.viewer .log-row.highlight { - background: var(--havelock); -} -.viewer .log-row.highlight span { - color: white; -} - -.viewer .end-message { - text-align: center; - font-size: 12px; - color: var(--lead); - line-height: 100px; -} - -.viewer .count, -.viewer .duration, -.viewer .uint8, -.viewer .uint16, -.viewer .uint32, -.viewer .uint64, -.viewer .int8, -.viewer .int16, -.viewer .int32, -.viewer .int64 { - text-align: right; -} -.viewer .path-tag { - display: inline-block; - border-radius: 3px; - padding: 0 6px; - line-height: 17px; - font-weight: normal; - color: white; - text-align: center; -} - -.log-detail { - padding: 12px; -} -.log-detail section { - margin-bottom: 24px; -} - -.empty-message-wrapper { - height: 100%; - display: flex; - align-items: center; - justify-content: center; -} -.empty-message-wrapper .empty-message { - text-align: center; - color: var(--slate); - font-size: 12px; -} - -.control-bar { - position: relative; - z-index: 1; - margin-bottom: 8px; - padding-top: 12px; - padding-left: 6px; - padding-right: 6px; -} -.control-bar .row-1 { - margin-left: 12px; - margin-right: 16px; - margin-bottom: 8px; -} -.control-bar .row-2 { - display: flex; - -webkit-app-region: no-drag; -} -.control-bar .search-bar { - flex: 1; -} - -.pins { - user-select: none; - margin-top: 12px; - display: inline-flex; - align-items: center; - min-height: 20px; - flex-wrap: wrap; - flex-basis: 100%; -} -.pins .filter-node { - margin-right: 12px; - min-height: 17px; -} - -@keyframes fadein { - from { - opacity: 0; - } - to { - opacity: 1; - } -} -.pane-left { - min-width: 150px; - flex-shrink: 0; -} - -.pane-right { - min-width: 240px; - flex-shrink: 0; -} - -.settings-modal { - min-width: 500px; -} -.settings-modal .settings-form { - border-radius: 3px; -} -.settings-modal .settings-form a { - text-decoration: underline; - cursor: pointer; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; -} -.settings-modal .settings-form input, -.settings-modal .settings-form select { - width: 240px; -} -.settings-modal .settings-form .setting-panel { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 12px; - height: 48px; - border-bottom: 1px solid var(--ivory); - position: relative; -} -.settings-modal .settings-form .setting-panel:last-child { - border: none; -} -.settings-modal .errors h4 { - margin-bottom: 0.25rem; -} -.settings-modal .errors ul { - margin-top: 1rem; - line-height: 1.5; -} -.settings-modal .errors a { - color: var(--red); - cursor: pointer; - text-decoration: underline; -} -.settings-modal .errors p { - margin: 0; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; -} -.settings-modal .feedback { - position: absolute; - right: 12px; - top: 1px; - margin: 0; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; - line-height: 14px; - background: var(--havelock); - color: white; - padding: 0 6px; - border-radius: 4px; - animation: fadein 300ms; - z-index: 1; -} - -.pool-modal .pool-modal-contents { - margin-bottom: 20px; -} - -.pane { - position: relative; - display: flex; - flex-direction: column; -} - -.pane-header { - user-select: none; - position: relative; - flex-shrink: 0; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 12px; -} -.pane-header svg { - fill: var(--slate); -} -.pane-header .center { - position: absolute; - left: 50%; - transform: translateX(-50%); -} -.pane-header .right { - display: flex; -} - -.pane-title { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; - text-align: center; - margin: 0; -} - -.pane-body { - height: 100%; - overflow-x: hidden; - overflow-y: auto; -} - -.pane-left { - border-right: 1px solid var(--border-color); -} - -.pane-right { - border-left: 1px solid var(--border-color); -} - -.history-pane { - background: var(--snow); - overflow-x: unset; -} - -.download-progress { - position: relative; - background: var(--cello); -} -.download-progress.complete .progress-value { - background-color: var(--green); -} -.download-progress .progress-bar { - width: 100%; - height: 5px; -} -.download-progress .progress-value { - background-color: var(--yellow); - height: 100%; - border-radius: 0 8px 8px 0; - width: 0%; - transition: width 200ms linear; -} -.download-progress .message-wrapper { - display: flex; - justify-content: space-between; - align-items: center; -} -.download-progress .message { - font-size: 12px; - padding: 12px; - white-space: nowrap; - color: white; -} - -.error-boundary { - overflow: auto; - height: 100%; - background-color: var(--ivory); - background: linear-gradient(to bottom right, #f8eee3, #fae1e0); - padding: 24px; - line-height: 1.5; -} -.error-boundary h1 { - padding-top: 31.415px; - display: flex; - align-items: center; - color: var(--red); -} -.error-boundary h1 svg { - fill: var(--red); - margin: 0; - height: 45px; - width: 45px; - margin-right: 31.415px; -} -.error-boundary pre, -.error-boundary li, -.error-boundary code, -.error-boundary a { - overflow: auto; - font-size: 11px; -} - -.tool-tip { - position: fixed; - background: var(--cello-transparent); - font-family: var(--mono-font); - color: white; - font-size: 12px; - line-height: 18px; - padding: 0 3px; - border-radius: 3px; - z-index: 1; - pointer-events: none; - user-select: none; - box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.3); -} -.tool-tip .secondary { - font-size: 10px; - opacity: 0.7; -} - -.__react_component_tooltip.tooltip { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; - transition: opacity 150ms; - padding: 3px 8px; -} - -.zui-tooltip-show-hover { - pointer-events: auto !important; -} -.zui-tooltip-show-hover:hover { - visibility: visible !important; - opacity: 1 !important; -} - -.log-cell { - padding: 0 4px; - position: relative; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - height: 25px; - display: flex; - align-items: flex-start; -} -.log-cell.hover, -.log-cell.active { - position: relative; -} - -.cell-value-item { - position: relative; - padding: 0 1px; - border: 1px solid transparent; - height: 25px; -} -.cell-value-item.selected { - background: rgba(255, 255, 255, 0.25); -} -.cell-value-item:hover { - z-index: 1; - border: 1px dashed var(--lead); -} - -.cell-value-item:last-child { - width: 100%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.compound-field-extra { - height: 25px; - border: 1px solid transparent; - color: var(--lead); -} -.compound-field-extra.separator { - margin-right: 6px; -} - -.no-results { - text-align: center; - width: 100%; - margin-top: 100px; - color: var(--lead); - display: inline-block; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; -} - -.column-chooser-menu { - background-color: white; - min-width: 280px; - position: absolute; - top: 48px; - right: 12px; - bottom: 48px; - border-radius: 4px; - display: flex; - flex-direction: column; -} -.column-chooser-menu .fieldset { - margin: 24px auto; - text-align: center; - font-family: system-ui; - font-weight: 500; - font-size: 13px; - text-transform: uppercase; - letter-spacing: 1px; -} -.column-chooser-menu hr { - border: none; - min-height: 1px; - width: calc(100% - 48px); - margin: 0 auto; - background-color: #dfe0e6; -} -.column-chooser-menu .subscript { - color: #c5c7d1; -} -.column-chooser-menu .close-button { - position: absolute; - right: 6px; - top: 6px; -} -.column-chooser-menu .count { - top: 18px; - left: 24px; - width: 24px; - height: 24px; - background-color: var(--havelock); - color: white; - border-radius: 50%; - position: absolute; - display: flex; - justify-content: center; - align-items: center; - cursor: default; -} -.column-chooser-menu .count .label, -.column-chooser-menu .count .inline-table th, -.inline-table .column-chooser-menu .count th { - cursor: default; -} -.column-chooser-menu .count:hover { - text-decoration: line-through; -} -.column-chooser-menu ul { - list-style-type: none; - margin: 0; - padding: 0; - overflow-y: scroll; - padding-top: 18px; - padding-bottom: 12px; - height: 100%; -} -.column-chooser-menu .search-input { - width: 100%; - align-content: center; - margin-bottom: 12px; -} - -.slide-in-right-appear { - transform: translate(100%); -} - -.slide-in-right-appear-active { - transition: transform 150ms; - transform: translate(0, 0); -} - -.histogram-tooltip-wrapper { - position: absolute; - z-index: 1; - top: 0px; - pointer-events: none; - transition: opacity 200ms 50ms, right 75ms, left 75ms; - opacity: 1; - font-family: var(--mono-font); -} - -.histogram-tooltip { - pointer-events: none; - color: white; - background: var(--cello-transparent); - font-size: 11px; - border-radius: 8px; -} -.histogram-tooltip table { - width: 100%; - padding: 10px; -} -.histogram-tooltip .count { - text-align: right; -} -.histogram-tooltip .ts { - white-space: nowrap; - height: 22px; - line-height: 22px; - background: var(--cello); - border-radius: 8px 8px 0 0; - padding: 0 10px; - text-align: center; -} -.histogram-tooltip .total-row { - border-top: 1px solid white; - text-align: right; - font-weight: bold; -} -.histogram-tooltip .path-tag { - border-radius: 3px; - padding: 0 6px; -} - -.hover-line { - fill: var(--slate); -} - -.whois-modal .text-content { - display: flex; - flex-direction: column; - min-height: 0; -} -.whois-modal .text-content > * { - flex-shrink: 0; -} -.whois-modal .text-content pre.output { - min-height: 0; - flex: 1; - overflow: auto; -} - -.portal-overlay { - position: fixed; - left: 0; - right: 0; - top: 0; - bottom: 0; - z-index: 1; -} - -.portal-item { - position: absolute; -} - -.dim-portal-overlay-appear { - background-color: rgba(0, 0, 0, 0); -} - -.dim-portal-overlay-appear-active, -.dim-portal-overlay-enter-done { - transition: background-color 200ms; - background-color: rgba(0, 0, 0, 0.35); -} - -.portal-item-appear { - transform: translate(0, -24px); - opacity: 0; -} - -.portal-item-appear-active, -.portal-item-enter-done { - transition: transform 150ms, opacity 150ms; - transform: translate(0, 0); - opacity: 1; -} - -.message-box { - color: white; - padding: 12px 24px 24px 24px; - overflow: hidden; - position: relative; - border-radius: 3px; - width: 400px; - background-color: rgba(84, 88, 102, 0.97); - box-shadow: 0 1px 10px 0px rgba(0, 0, 0, 0.5); -} -.message-box::after { - width: 120px; - height: 120px; - content: ""; - background-color: #d93347; - position: absolute; - top: -80px; - left: -80px; - border-radius: 50%; -} -.message-box .header { - margin-left: 24px; - margin-bottom: 24px; -} -.message-box .code { - margin-top: 12px; - background-color: rgba(0, 0, 0, 0.2); - white-space: normal; -} -.message-box .close-button { - position: absolute; - right: 12px; - top: 8px; -} - -.notice-banner { - background: linear-gradient( - to top, - #ffe999, - hsl(47deg, 100%, 70%) 2%, - hsl(47deg, 100%, 50%) 98%, - #ffe999 - ); - box-shadow: 0 1px 3px -1px rgba(0, 0, 0, 0.4); - border-radius: 3px; - padding: 12px 19.416px; - font-size: 14px; - font-weight: 500; - margin: 0; -} -.notice-banner p { - margin: 0; -} -.notice-banner a { - padding-left: 12px; - text-decoration: underline; - cursor: pointer; - user-select: none; - font-weight: 400; -} -.notice-banner a:hover { - color: var(--slate); -} -.notice-banner a:active { - color: inherit; -} -.notice-banner .error-details { - margin-top: 12px; -} -.notice-banner .error-details p { - font-size: 12px; - font-weight: 400; - line-height: 17px; -} -.notice-banner.fixed { - position: absolute; - z-index: 5; - top: 22px; - left: 50%; - max-width: 90%; -} - -.circle-chevron { - background: none; - border: none; - margin: 0; - padding: 0; - outline: none; -} -.circle-chevron .circle { - box-shadow: 0 0 3px rgba(0, 0, 0, 0.5); - height: 36px; - width: 36px; - border-radius: 50%; - display: flex; - align-items: center; - transition: transform 150ms, box-shadow 150ms, background-color 150ms; -} -.circle-chevron svg { - width: 11px; - margin-left: 11px; - transition: transform 150ms; -} -.circle-chevron:hover .circle { - transform: scale(1.05); - box-shadow: 0 1px 10px 0px rgba(0, 0, 0, 0.5); -} -.circle-chevron:active .circle { - transform: scale(1); - box-shadow: 0 0 3px rgba(0, 0, 0, 0.5); -} -.circle-chevron:active svg { - transform: translateX(-2px); -} -.circle-chevron .circle { - background-color: white; -} -.circle-chevron .circle:hover { - background-color: #f7f7f7; -} -.circle-chevron .circle:active { - background-color: white; -} -.circle-chevron svg { - fill: var(--slate); -} -.circle-chevron.left { - transform: rotateY(0); -} -.circle-chevron.right { - transform: rotateY(180deg); -} -.circle-chevron.expand svg { - margin-left: 8px; -} - -.left-pane-expand-button { - z-index: 2; - position: fixed; - top: calc(50% - 18px); - left: -13px; -} - -.right-pane-expand-button { - z-index: 2; - position: fixed; - top: calc(50% - 18px); - right: -13px; -} - -.right-pane-collapser, -.left-pane-collapser { - z-index: 2; - position: absolute; - top: calc(50% - 18px); - opacity: 0; - transition: opacity 150ms 500ms; -} -.right-pane-collapser.show, -.left-pane-collapser.show { - transition: opacity 150ms; - opacity: 1; -} - -.right-pane-collapser { - left: -18px; -} - -.left-pane-collapser { - right: -18px; -} - -.slide-in-from-left-enter { - transform: translateX(-100%); -} - -.slide-in-from-left-enter-active { - transition: transform 150ms; - transform: translateX(0); -} - -.slide-in-from-left-exit { - transform: translateX(0); -} - -.slide-in-from-left-exit-active { - transition: transform 150ms; - transform: translateX(-100%); -} - -.slide-in-from-right-enter { - transform: translateX(100%); -} - -.slide-in-from-right-enter-active { - transition: transform 150ms; - transform: translateX(0); -} - -.slide-in-from-right-exit { - transform: translateX(0); -} - -.slide-in-from-right-exit-active { - transition: transform 150ms; - transform: translateX(100%); -} - -@keyframes flash-element { - from { - background: inherit; - transform: inherit; - } - 10% { - background: yellow; - transform: scale(1.3); - } - to { - background: inherit; - transform: inherit; - } -} -.flash-element { - animation: flash-element 500ms ease-out; -} - -.loading-message { - opacity: 0; - display: flex; - align-items: center; - justify-content: center; - transition: opacity 250ms; -} -.loading-message .fieldset { - margin-left: 12px; -} -.loading-message.visible { - transition: opacity 250ms; - opacity: 1; -} - -.loading-burst.visible { - opacity: 1; - transition: none; -} - -.loading-burst { - opacity: 0; - transition: opacity 500ms; - margin-left: 10px; - height: 12px; - width: 12px; - position: relative; -} -.loading-burst .burst { - border-radius: 50%; - position: absolute; - width: 100%; - height: 100%; - opacity: 0; -} -.loading-burst .burst-1 { - background: var(--green); - animation: burst 1s infinite; -} -.loading-burst .burst-2 { - background: var(--green); - animation: burst 1s 200ms infinite; -} - -@keyframes burst { - 0% { - opacity: 1; - transform: scale(0); - } - 50% { - opacity: 0.5; - transform: scale(1); - } - 100% { - opacity: 0; - transform: scale(2); - } -} -.curl-modal .text-content { - display: flex; - flex-direction: column; - min-height: 0; -} -.curl-modal .text-content pre { - flex: 1; - overflow: auto; - user-select: all; -} - -.zq-modal { - min-height: 0; -} - -.inline-table table { - border-collapse: collapse; - width: 100%; -} -.inline-table td:first-child { - border-radius: 3px 0 0 3px; -} -.inline-table td:last-child { - border-radius: 0 3px 3px 0; -} -.inline-table tbody tr:nth-child(odd) { - background: var(--table-stripe-bg); -} -.inline-table tbody tr:hover { - background: var(--hover-light-bg); -} -.inline-table th, -.inline-table td { - padding: 3px 6px; -} -.inline-table th.count, -.inline-table td.count { - text-align: right; -} -.inline-table th { - text-align: left; - font-size: 9px; - font-weight: bold; - color: var(--slate); -} - -.hash-correlation .two-column { - display: flex; - justify-content: space-between; - align-items: flex-start; -} -.hash-correlation .two-column > * { - flex-basis: 45%; -} -.hash-correlation .table { - margin-bottom: 12px; -} - -.inline-table-loading tr { - height: 20px; -} -.inline-table-loading tr:hover { - background: initial !important; -} -.inline-table-loading tbody td { - border-radius: 3px !important; -} -.inline-table-loading tbody tr:nth-child(1) { - animation: squeeze 3000ms 100ms ease-in-out infinite; -} -.inline-table-loading tbody tr:nth-child(3) { - animation: squeeze 3000ms 300ms ease-in-out infinite; -} -.inline-table-loading tbody tr:nth-child(5) { - animation: squeeze 3000ms 500ms ease-in-out infinite; -} - -@keyframes squeeze { - from { - transform: scaleX(1); - } - 50% { - transform: scaleX(1); - background-color: var(--table-stripe-bg); - } - 60% { - transform: scaleX(0.85); - background-color: var(--hover-light-bg); - } - 70% { - transform: scaleX(1); - } -} -.table { - border-collapse: collapse; - width: 100%; - font-family: var(--mono-font); -} -.table tbody tr:nth-child(odd) { - background: var(--table-stripe-bg); -} -.table tbody tr:hover { - background: var(--hover-light-bg); -} -.table th, -.table td { - padding: 3px 6px; -} -.table th { - text-align: left; - font-size: 9px; - font-weight: bold; -} -.table.light tbody tr:nth-child(odd) { - background: rgba(255, 255, 255, 0.02); -} -.table.light tbody tr:hover { - background: rgba(255, 255, 255, 0.06); -} - -.vertical-table th, -.vertical-table td { - word-break: break-word; -} -.vertical-table th { - white-space: nowrap; - border-radius: 3px 0 0 3px; -} -.vertical-table td { - border-radius: 0 3px 3px 0; -} - -.horizontal-table td { - word-break: break-all; -} -.horizontal-table .count { - text-align: right; - word-break: keep-all; -} - -.span-duration { - display: flex; - align-items: center; - justify-content: center; - font-family: var(--mono-font); - user-select: none; - width: 55px; -} -.span-duration span { - font-size: 10px; - padding: 0 3px; - white-space: nowrap; - line-height: 13px; -} -.span-duration hr { - margin: 0; - flex: 1; - border: none; - border-top: 1px solid #dcdcdc; -} -.span-duration.error span { - background: linear-gradient( - to top, - #ffe999, - hsl(47deg, 100%, 70%) 2%, - hsl(47deg, 100%, 50%) 98%, - #ffe999 - ); - box-shadow: 0 1px 3px -1px rgba(0, 0, 0, 0.4); - border-radius: 3px; - padding: 0 8px; - animation: nope-shake 200ms; - animation-delay: 50ms; - animation-iteration-count: 2; - animation-timing-function: linear; -} -.span-duration.error hr { - opacity: 0; -} - -@keyframes nope-shake { - from { - transform: translateX(0); - } - 25% { - transform: translateX(3px); - } - 50% { - transform: translateX(0); - } - 75% { - transform: translateX(-3px); - } - to { - transform: translateX(0); - } -} -.expand-button { - transform: rotate(-90deg); -} -.expand-button.open { - transform: rotate(0deg); - opacity: 1; -} -.expand-button svg { - margin-top: 2px; - width: 11px; - height: 11px; -} - -.pop-menu-overlay { - position: fixed; - background: transparent; - left: 0; - right: 0; - top: 0; - bottom: 0; - z-index: 2; -} - -.pop-menu-wrapper { - filter: drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5)); - z-index: 1; - margin: 0; - text-align: left; - background-color: white; - position: relative; - border-radius: 5px; - display: inline-block; - pointer-events: all; -} -.pop-menu-wrapper ul { - padding: 8px 0; - margin: 0; -} -.pop-menu-wrapper li { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; - padding: 4.584px 36px; - list-style-type: none; - display: block; - white-space: nowrap; - margin: 0; - user-select: none; -} -.pop-menu-wrapper li:hover { - background-color: var(--havelock); - color: white; -} -.pop-menu-wrapper .disabled { - cursor: auto; - color: var(--lead); -} -.pop-menu-wrapper .disabled:hover { - background-color: inherit; - color: var(--lead); -} -.pop-menu-wrapper hr { - border: none; - border-top: 1px solid var(--cloudy); - margin: 8px 0; -} -.pop-menu-wrapper .pop-menu-pointer { - margin: 0; - padding: 0; - fill: white; - position: absolute; - height: 16px; -} - -.test-anchor { - position: fixed; - background-color: var(--havelock); - height: 100px; - width: 100px; - border-radius: 50%; -} - -.a { - top: 10px; - left: 10px; -} - -.b { - top: 10px; - right: 10px; -} - -.c { - bottom: 10px; - right: 10px; -} - -.d { - bottom: 10px; - left: 10px; -} - -.e { - top: 30%; - left: 50%; -} - -.f { - top: 60%; - left: 50%; -} - -.button-row { - display: flex; - justify-content: flex-end; - margin-bottom: 20px; -} -.button-row > * { - margin-left: 5px; -} - -.debug-modal .text-content { - display: flex; - flex-direction: column; - min-height: 0; -} -.debug-modal .text-content pre { - flex: 1; - overflow: auto; -} - -.click-feedback { - background: var(--havelock); - color: white; - font-size: 0.85rem; - border-radius: 5px; - padding: 2px 4px; - user-select: none; - text-align: center; -} -.click-feedback:before { - content: ""; - background: var(--havelock); - position: absolute; - top: calc(100% - 2px); - left: calc(50% - 2px); - width: 4px; - height: 4px; - border-radius: 0px; - transform: rotate(45deg); -} - -.viewer header { - white-space: nowrap; - height: 25px; - display: flex; - box-shadow: 0 1px 3px -2px rgba(0, 0, 0, 0.7); - padding-left: 12px; -} - -.viewer .header-cell { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; - height: 25px; - line-height: 25px; - padding: 0 12px; - color: var(--aqua); - user-select: none; - transition: border 150ms; - position: relative; - display: flex; - align-items: center; - overflow: hidden; -} -.viewer .header-cell.count, -.viewer .header-cell.interval { - justify-content: flex-end; -} -.viewer .header-cell:before, -.viewer .header-cell:after { - content: ""; - position: absolute; - height: 60%; - width: 1px; - background: var(--cloudy); - top: 20%; -} -.viewer .header-cell:before { - left: -1px; -} -.viewer .header-cell:after { - right: 0px; -} -.viewer .header-cell.active:before, -.viewer .header-cell.active:after, -.viewer .header-cell:hover:before, -.viewer .header-cell:hover:after { - content: ""; -} -.viewer .header-cell:active, -.viewer .header-cell.active { - background: var(--coconut); -} -.viewer .header-cell.sorted { - font-weight: bold; -} -.viewer .header-cell.sorted svg { - margin-left: 7.417px; -} - -.viewer .col-resizer { - width: 12px; - height: 100%; - background: transparent; - position: absolute; - right: -2px; - top: 0; - cursor: col-resize; -} - -.time-span-pickers { - -webkit-app-region: no-drag; - z-index: 1; - position: relative; - display: flex; - align-items: flex-start; -} -.time-span-pickers .time-span-menu { - background: linear-gradient(#ffffff, 0.5px, #fefefe 2px, #f6f6f6); - border: none; - box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.1), - 0 0.5px 0 0 rgba(0, 0, 0, 0.15); - border-radius: 4px; - justify-content: center; - min-width: 0px; - margin-left: 3px; -} -.time-span-pickers .time-span-menu:active:not(:disabled) { - background: linear-gradient(#fefefe, 0.5px, #f3f3f3 2px); -} -.time-span-pickers .span-duration { - margin-top: 5px; -} - -.time-picker-button-input { - position: relative; - display: flex; - align-items: flex-start; -} -.time-picker-button-input input { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; - margin: 0; - width: 135px; - height: 22px; - border-radius: 3px; - border: none; - padding-left: 8px; - line-height: 22px; -} -.time-picker-button-input input:focus, -.time-picker-button-input input:active { - z-index: 1; - box-shadow: 0 0 0 2px var(--havelock); - outline: none !important; -} - -.time-picker-button { - position: relative; -} -.time-picker-button .toolbar-button { - position: relative; - min-width: 60px; -} -.time-picker-button .hover-zone { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; -} -.time-picker-button > .hover-zone { - z-index: -1; -} -.time-picker-button.hovering .hover-zone { - top: -20px; - bottom: -20px; -} -.time-picker-button .changed-dot { - position: absolute; - width: 8px; - height: 8px; - background: var(--havelock); - top: calc(50% - 4px); - left: -4px; - border-radius: 50%; - border: 1px solid white; - cursor: pointer; - transition: all 150ms; -} - -.time-piece { - padding: 0 3px; - position: relative; -} -.time-piece[data-unit="hour"], -.time-piece[data-unit="minute"], -.time-piece[data-unit="second"] { - font-weight: normal; - padding-right: 0; -} -.time-piece .hover-zone { - z-index: -1; -} - -.steppers { - position: fixed; - left: 0; - top: 0; - transition: all 25ms; -} - -.stepper { - width: 20px; - height: 18px; - background: rgba(0, 0, 0, 0.2); - display: flex; - align-items: center; - justify-content: center; - position: absolute; - transition: background-color 100ms; -} -.stepper:hover { - background: rgba(0, 0, 0, 0.3); -} -.stepper:active { - background: rgba(0, 0, 0, 0.4); -} -.stepper.step-up { - border-radius: 4px 4px 0 0; -} -.stepper.step-down { - border-radius: 0 0 4px 4px; -} - -.input-suggestions { - min-width: 100%; - position: absolute; - box-shadow: 0 2px 15px 0px rgba(0, 0, 0, 0.3); - top: 100%; - left: 0; - border-radius: 3px; - background: white; - font-size: 11px; - user-select: none; -} -.input-suggestions .suggestion { - font-family: var(--mono-font); - padding: 6px 8px; - margin: 0; - white-space: nowrap; - height: 25px; - cursor: default; -} -.input-suggestions .suggestion:hover { - background: var(--hover-light-bg); -} -.input-suggestions .suggestion.active, -.input-suggestions .suggestion:active { - background: var(--havelock); - color: white; -} -.input-suggestions .suggestion.active:first-child, -.input-suggestions .suggestion:active:first-child { - border-radius: 3px 3px 0 0; -} -.input-suggestions .suggestion.active:last-child, -.input-suggestions .suggestion:active:last-child { - border-radius: 0 0 3px 3px; -} -.input-suggestions .suggestion.error { - color: var(--lead); -} - -.tab { - position: absolute; - left: 0; - user-select: none; - -webkit-app-region: no-drag; - height: 80%; - border-radius: 10px 10px 2px 2px; - background: transparent; - cursor: default; - will-change: transform; - transition: none; - box-shadow: 1px 0 0 0 var(--border-color), - inset 0 -1px 0 0 var(--border-color); -} -.tab .tab-content { - overflow: hidden; - display: flex; - justify-content: space-between; - align-items: center; - height: 100%; - position: relative; - opacity: 0.75; -} -.tab .icon { - margin-left: 24px; - margin-right: 8px; -} -.tab .title { - font-family: system-ui; - font-size: 14px; - line-height: 16px; - margin: 0; - font-weight: 400; - color: var(--foreground-color); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - flex: 1; -} -.tab .close-button { - margin-right: 10px; - position: relative; -} -.tab .close-button:hover { - background: rgba(0, 0, 0, 0.3); -} -.tab:hover { - background-color: var(--tab-background-hover); - box-shadow: inset -1px 0 var(--border-color), -1px 0 var(--border-color), - inset 0 -1px var(--border-color); -} -.tab:hover .title { - color: var(--foreground-color); -} -.tab:hover .close-button svg { - fill: var(--foreground-color); -} -.tab:hover .tab-content { - opacity: 0.9; -} -.tab.active { - background: var(--chrome-color); - z-index: 1; - box-shadow: 1px 0 0 0 var(--border-color), -1px 0 0 0 var(--border-color), - inset 0 -1px 0 0 var(--border-color); -} -.tab.active .title { - color: var(--foreground-color); -} -.tab.active .tab-content { - opacity: 1; -} -.tab.active .close-button svg { - fill: var(--foreground-color); -} -.tab.active .close-button:after { - background: rgba(0, 0, 0, 0.1); -} -.tab.active .close-button:active:after { - background: rgba(0, 0, 0, 0.2); -} -.tab.is-new.active { - background: white; -} -.tab.preview { - font-style: italic; -} - -.column-description { - width: 180px; - color: white; - font-size: 11px; - border-radius: 8px; - font-family: system-ui; - white-space: normal; -} -.column-description .tip-title { - display: flex; - justify-content: space-between; - height: 22px; - line-height: 22px; - border-radius: 8px 8px 0 0; - padding: 0 10px; - text-align: center; -} -.column-description .tip-title p { - margin: 0; -} -.column-description .tip-title p:first-child { - font-weight: bold; -} -.column-description .tip-title p:last-child { - font-style: italic; -} -.column-description .tip-body { - overflow-y: auto; - max-height: 260px; - word-wrap: break-word; - padding: 0 10px; -} -.column-description .tip-body ul, -.column-description .tip-body ol { - padding: 0 16px; -} -.column-description .tip-footer { - border-top: 1px solid rgba(255, 255, 255, 0.2); - padding: 10px; - border-radius: 0 0 8px 8px; -} -.column-description .tip-footer a { - text-decoration: underline; - cursor: pointer; - color: var(--havelock); -} - -.brand { - -webkit-app-region: drag; - text-align: center; - margin-top: 50px; - margin-bottom: 24px; -} -.brand h1 { - font-family: system-ui; - font-weight: bold; - font-size: 16px; - margin: 0; - margin-top: 1rem; -} -.brand span { - margin: 0; - font-size: 0.7rem; -} - -.brand-volcano { - filter: drop-shadow(1px 1px 1px rgba(0, 0, 0, 0.19)); -} - -.empty-search-page { - height: 100%; - outline: 1px solid blue; - width: 400px; -} - -.mac-spinner { - width: 24px; - height: 24px; - position: relative; - transform: scale(0.8); -} -.mac-spinner .bar-container { - position: absolute; - width: 100%; - height: 100%; - transform: translate(50%, 6px); -} -.mac-spinner .bar { - position: absolute; - left: 0px; - top: 0px; - width: 2px; - height: 6px; - background: var(--aqua); - transform-origin: bottom center; - border-radius: 2px; - opacity: 0.05; - animation: opacity-pulse 800ms infinite linear; -} -.mac-spinner .bar:nth-child(1) { - transform: rotate(0deg) translateY(-6px); - animation-delay: 0ms; -} -.mac-spinner .bar:nth-child(2) { - transform: rotate(30deg) translateY(-6px); - animation-delay: 66.6666666667ms; -} -.mac-spinner .bar:nth-child(3) { - transform: rotate(60deg) translateY(-6px); - animation-delay: 133.3333333333ms; -} -.mac-spinner .bar:nth-child(4) { - transform: rotate(90deg) translateY(-6px); - animation-delay: 200ms; -} -.mac-spinner .bar:nth-child(5) { - transform: rotate(120deg) translateY(-6px); - animation-delay: 266.6666666667ms; -} -.mac-spinner .bar:nth-child(6) { - transform: rotate(150deg) translateY(-6px); - animation-delay: 333.3333333333ms; -} -.mac-spinner .bar:nth-child(7) { - transform: rotate(180deg) translateY(-6px); - animation-delay: 400ms; -} -.mac-spinner .bar:nth-child(8) { - transform: rotate(210deg) translateY(-6px); - animation-delay: 466.6666666667ms; -} -.mac-spinner .bar:nth-child(9) { - transform: rotate(240deg) translateY(-6px); - animation-delay: 533.3333333333ms; -} -.mac-spinner .bar:nth-child(10) { - transform: rotate(270deg) translateY(-6px); - animation-delay: 600ms; -} -.mac-spinner .bar:nth-child(11) { - transform: rotate(300deg) translateY(-6px); - animation-delay: 666.6666666667ms; -} -.mac-spinner .bar:nth-child(12) { - transform: rotate(330deg) translateY(-6px); - animation-delay: 733.3333333333ms; -} -.mac-spinner.light .bar { - background: white; -} - -@keyframes opacity-pulse { - from { - opacity: 1; - } - to { - opacity: 0.01; - } -} -.saved-pools-list { - user-select: none; - overflow-x: hidden; - overflow-y: auto; - min-height: 0px; - position: relative; - margin: 0; - padding: 0; -} -.saved-pools-list:before { - content: ""; - position: sticky; - top: 0; - left: 0; - width: 100%; - height: 22px; - background: orange; -} -.saved-pools-list a { - -webkit-user-drag: none; -} -.saved-pools-list li { - list-style-type: none; - display: flex; - align-items: center; -} -.saved-pools-list li:hover { - background-color: rgba(0, 0, 0, 0.03); -} -.saved-pools-list li:active { - background-color: rgba(0, 0, 0, 0.08); -} -.saved-pools-list .pool-link { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; - line-height: 18px; - color: var(--aqua); - display: flex; - align-items: center; - justify-content: space-between; - text-decoration: none; - flex: 1; - height: 24px; - width: 100%; - padding-left: 22px; - cursor: default; -} -.using-keyboard .saved-pools-list .pool-link:focus { - outline: none; - background: var(--havelock); - color: white; -} -.using-keyboard .saved-pools-list .pool-link:focus svg { - fill: white; -} -.saved-pools-list .current-pool-link { - outline: none; - background: var(--havelock); - color: white; -} -.saved-pools-list .current-pool-link .pool-icon { - fill: white; - stroke: white; -} -.saved-pools-list .current-pool-link .pool-icon .chunk { - fill: white; -} -.saved-pools-list .current-pool-link .small-progress-bar .progress-track { - background-color: rgba(0, 0, 0, 0.15); -} -.saved-pools-list .current-pool-link .small-progress-bar .progress-fill { - background-color: white; -} -.saved-pools-list .current-pool-link:hover { - background: var(--havelock); -} -.saved-pools-list .pool-icon { - width: 13px; - height: 13px; - flex-shrink: 0; -} -.saved-pools-list .name { - display: block; - padding-left: 6px; - overflow-x: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.saved-pools-list .small-progress-bar { - flex: 1; - margin: 0px 5px; -} - -.progress-indicator { - display: flex; - align-items: center; - width: 100%; -} -.progress-indicator .close-button { - margin-left: 8px; - width: 12px; - height: 12px; -} -.progress-indicator .close-button svg { - width: 8px; - height: 8px; -} - -.progress-track { - box-sizing: content-box; - height: 6px; - background: rgba(0, 0, 0, 0.05); - width: 100%; - border-radius: 6px; - box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.1); - overflow: hidden; -} - -.progress-fill { - width: 0%; - background: var(--havelock); - height: 100%; - transition: width 1000ms; -} - -@keyframes fake-loading { - from { - width: 5%; - } - 10% { - width: 8%; - } - 20% { - width: 30%; - } - 30% { - width: 32%; - } - 40% { - width: 38%; - } - 50% { - width: 45%; - } - 60% { - width: 55%; - } - 70% { - width: 89%; - } - 80% { - width: 90%; - } - 90% { - width: 98%; - } - to { - width: 100%; - } -} -.packet-post-progress { - width: 100%; - height: 100%; - display: flex; - justify-content: space-between; - align-items: center; - padding: 0 6px; -} -.packet-post-progress label { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; - line-height: 24px; - white-space: nowrap; -} -.packet-post-progress .progress-indicator { - max-width: 220px; - padding: 0 12px; - width: 220px; -} -.packet-post-progress .group { - display: flex; - align-items: center; - height: 100%; -} -.packet-post-progress .warnings { - height: 100%; - padding: 0 12px; - display: flex; - fill: #f37406; - align-items: center; -} -.packet-post-progress .warnings svg { - width: 14px; -} -.packet-post-progress .warnings label { - min-width: 15px; - margin-left: 5px; - text-align: center; - color: #f37406; - font-family: system-ui; - letter-spacing: 0.07px; - font-size: 11px; - line-height: 17px; - font-weight: 700; - font-weight: 800; -} -.packet-post-progress .warnings:not(.disabled):hover { - background: rgba(0, 0, 0, 0.05); -} -.packet-post-progress .warnings:not(.disabled):active { - background: rgba(0, 0, 0, 0.1); -} -.packet-post-progress .warnings.disabled { - pointer-events: none; -} -.packet-post-progress .warnings.disabled svg { - fill: var(--cloudy); -} -.packet-post-progress .warnings.disabled label { - color: var(--cloudy); -} - -#about-root { - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; -} - -.about-window { - animation: fadein 800ms; -} -.about-window .about-logo { - display: flex; - justify-content: center; - margin-top: 24px; - margin-bottom: 12px; -} -.about-window .about-content { - display: flex; - flex-direction: column; - padding-top: 24px; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; -} -.about-window .about-content p { - margin: 0; -} -.about-window .about-content a { - color: var(--havelock); - cursor: pointer; -} -.about-window .about-content section { - display: flex; - padding: 3px; -} -.about-window .about-content label { - margin-right: 12px; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 600; - user-select: none; - width: 60px; -} -.about-window .about-content hr { - border: none; - box-shadow: 0 0 0 0.5px var(--border-color); - margin: 18px 0 12px 0; -} -.about-window .about-content footer section { - justify-content: center; -} -.about-window .octocat-small { - width: 15px; - height: 15px; - margin: 0 3px; -} - -.tab-search-loading { - animation: fadein 300ms; - flex: 1; - display: flex; - justify-content: center; - align-items: center; -} -.tab-search-loading .message { - padding: 8px; - user-select: none; - display: flex; - align-items: center; - margin-bottom: 50px; -} -.tab-search-loading .message p { - margin: 0; - margin-right: 8px; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; -} -.tab-search-loading .message .mac-spinner { - transform: scale(0.6); -} - -.toolbar-button { - background: linear-gradient(#ffffff, 0.5px, #fefefe 2px, #f6f6f6); - border: none; - box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.1), - 0 0.5px 0 0 rgba(0, 0, 0, 0.15); - border-radius: 4px; - user-select: none; - min-width: 48px; - -webkit-app-region: no-drag; - height: 22px; - padding: 0 4px; - display: flex; - align-items: center; - justify-content: center; -} -.toolbar-button:active:not(:disabled) { - background: linear-gradient(#fefefe, 0.5px, #f3f3f3 2px); -} -.toolbar-button > * { - pointer-events: none; -} -.toolbar-button .icon { - display: flex; - margin: 0 4px; -} -.toolbar-button .icon svg { - fill: var(--slate); - height: 16px; - width: 16px; -} -.toolbar-button .text { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; - white-space: nowrap; - color: var(--aqua); - display: flex; - line-height: 16px; - height: 16px; - padding: 0 4px; - white-space: nowrap; -} -.toolbar-button:disabled { - cursor: not-allowed; -} -.toolbar-button:disabled .icon { - opacity: 0.25; -} -.toolbar-button:disabled .text { - opacity: 0.5; -} -.toolbar-button:disabled + label { - opacity: 0.5; -} -.toolbar-button.dragging { - background: var(--havelock); -} -.toolbar-button.dragging .text { - color: white; -} -.toolbar-button.dragging .icon { - fill: white; -} - -.toolbar-button-primary { - background: linear-gradient(#4b91e2, #3a87df); -} -.toolbar-button-primary .text { - color: white; -} -.toolbar-button-primary:active:not(:disabled) { - background: var(--azure); -} - -@keyframes updown { - from { - transform: translateY(5px); - } - to { - transform: translateY(-5px); - } -} -div.load-files-input { - margin: 24px 0; - min-width: 360px; - position: relative; - border-radius: 16px; - border: 2px dashed var(--orange); - box-shadow: inset 0 0 2px 0px rgba(0, 0, 0, 0.3); - background: white; - width: 100%; - height: 150px; - overflow: hidden; - padding: 22px; - box-shadow: none; - user-select: none; -} -div.load-files-input > * { - pointer-events: none; -} -div.load-files-input .content { - display: flex; - justify-content: space-between; - align-items: center; - height: 100%; - width: 100%; -} -div.load-files-input .controls { - z-index: 1; -} -div.load-files-input .controls button { - width: auto; - pointer-events: all; -} -div.load-files-input .controls p { - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 11px; - line-height: 17px; - font-weight: 400; - color: var(--slate); -} -div.load-files-input .file-types { - display: flex; - justify-content: space-between; - align-items: center; -} -div.load-files-input .file-types svg { - filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.15)); -} -div.load-files-input .files-stack { - position: relative; - margin-left: 22px; - height: 64px; - width: 54px; -} -div.load-files-input .files-stack svg { - position: absolute; - top: 0; - left: 0; -} -div.load-files-input .files-stack svg:nth-child(2) { - top: 2px; - left: 3px; -} -div.load-files-input .files-stack svg:nth-child(3) { - top: 4px; - left: 6px; -} -div.load-files-input .radiation { - z-index: 0; - right: -190px; - top: -50%; - height: 300px; - width: 300px; - position: absolute; -} -div.load-files-input .radiation div { - position: absolute; - width: 300px; - height: 300px; - background: var(--cello); - opacity: 0.03; - border-radius: 50%; -} -div.load-files-input .radiation div:nth-child(1) { - transform: translateX(-25px) scale(1.1); -} -div.load-files-input .radiation div:nth-child(2) { - transform: translateX(-50px) scale(1.2); -} -div.load-files-input input[type="file"] { - width: 0.1px; - height: 0.1px; - opacity: 0; - overflow: hidden; - position: absolute; - z-index: -1; -} -div.load-files-input .drag-over-content { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - align-items: center; - justify-content: center; - z-index: 1; - opacity: 0; - border-radius: 14px; -} -div.load-files-input .drag-over-content svg { - fill: white; - margin-right: 12px; - height: 16px; - width: 16px; -} -div.load-files-input .drag-over-content p { - display: flex; - align-items: center; - pointer-events: none; - font-family: system-ui; - font-weight: 500; - font-size: 13px; - text-transform: uppercase; - letter-spacing: 1px; - animation: updown 1200ms ease-in-out infinite alternate; - color: white; -} -div.load-files-input.dragging { - transition: all 1s; - border-style: solid; - box-shadow: 0 8px 16px -1px rgba(0, 0, 0, 0.5); -} -div.load-files-input.dragging .content { - transition: opacity 1s; - opacity: 0; -} -div.load-files-input.dragging .drag-over-content { - transition: opacity 1s; - opacity: 1; -} -div.load-files-input.dragging .drag-over-content p { - animation: updown 1200ms ease-in-out infinite alternate; -} -div.load-files-input.dragging .radiation { - z-index: 1; - transition: transform 1000ms; - transform: scale(3.3); -} -div.load-files-input.dragging .radiation div { - transition: opacity 1500ms; - opacity: 1; -} -div.load-files-input.dragging button { - pointer-events: none; -} - -.ingest-warnings-modal { - max-width: 90%; - width: 800px; -} -.ingest-warnings-modal .text-content { - display: flex; - flex-direction: column; - min-height: 0; -} -.ingest-warnings-modal .text-content > * { - flex-shrink: 0; -} -.ingest-warnings-modal .text-content pre.output { - min-height: 0; - flex: 1; - overflow: auto; -} - -#detail-root { - height: 100%; - width: 100%; -} - -.log-detail-window { - display: flex; - width: 100%; - height: 100%; - flex-direction: column; - background: var(--snow); -} -.log-detail-window .pane-header { - background: var(--ivory); - border-bottom: 1px solid #dbdbdb; -} -.log-detail-window .detail-pane-content { - display: flex; - justify-content: space-between; -} -.log-detail-window .detail-pane-content .column { - width: 50%; - margin: 12px; -} - -/* Common */ -.history-buttons { - display: flex; - align-items: center; -} - -.info-notice-wrapper { - position: fixed; - bottom: 0; - right: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - padding-bottom: 24px; -} - -.info-notice { - white-space: nowrap; - user-select: none; - background: var(--cello); - color: white; - border-radius: 8px; - height: 32px; - box-shadow: 0 2px 3px 0px rgba(0, 0, 0, 0.4), - inset 0 0 0 0.5px rgba(0, 0, 0, 0.3); - display: flex; - align-items: center; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; - margin-bottom: 12px; - animation: popup 2s; -} -.info-notice .x-button { - margin-right: 6px; -} -.info-notice p { - margin: 0 12px; -} - -@keyframes popup { - from { - transform: translateY(100px); - } - 20% { - transform: translateY(0px); - } - to { - transform: translateY(0px); - } -} -.bevel-button { - color: white; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; - background: linear-gradient(#1ca0f2, #0e97ec); - border: none; - border-radius: 4px; - box-shadow: inset 0 0 0 0.5px #0c84cf, - inset 0 1px 0 0 rgba(255, 255, 255, 0.5), 0 0.5px 1px 0 rgba(0, 0, 0, 0.15); - letter-spacing: 0.5px; -} -.bevel-button:active { - background: #0c8ad9; - box-shadow: none; -} - -.x-button { - background: none; - border: none; - width: 23px; - height: 23px; - display: flex; - align-items: center; - justify-content: center; - min-width: 17px; - padding: 0; - position: relative; - user-select: none; - border-radius: 2px; - outline: none; -} -.x-button svg { - width: 9px; - height: 9px; - fill: #b3b3b3; -} -.x-button:hover { - background: rgba(255, 255, 255, 0.2); -} -.x-button:hover svg { - fill: white; -} -.x-button:active { - background: rgba(255, 255, 255, 0.1); -} -.x-button:active svg { - fill: #b3b3b3; -} - -.html-context-menu { - position: fixed; - bottom: 20px; - right: 20px; - width: 300px; - max-height: 100vh; - background: white; - overflow: auto; - box-shadow: 0 0 3px 3px rgba(0, 0, 0, 0.15); - user-select: none; - animation: fadein 300ms; -} -.html-context-menu ul { - list-style: none; - padding: 20px 0; - margin: 0; - font-family: system-ui; - letter-spacing: -0.08px; - font-size: 13px; - line-height: 18px; - font-weight: 400; -} -.html-context-menu li { - margin: 0; - padding: 4px 20px; -} -.html-context-menu li:hover { - background: #fafafa; -} -.html-context-menu li.disabled { - opacity: 0.2; - pointer-events: none; -} -.html-context-menu hr { - border-top: 0; -} - -.toaster.toaster { - background: var(--wet-cement); - color: white; - border-radius: 8px; - box-shadow: 0 3px 10px rgba(0, 0, 0, 0.25), 0 3px 3px rgba(0, 0, 0, 0.05); - max-width: 90%; - font-size: 13px; -} -.toaster.toaster [role="status"] { - margin-left: 10px; -} - -.scroll-shadow { - transition: box-shadow 100ms; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0); -} - -.scroll-shadow-show { - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); -} - -.zed-table { - display: flex; - min-height: 0; - flex-flow: column; - height: 100%; - width: 100%; - font-family: var(--mono-font); - --header-height: 28px; - --row-height: 20px; -} - -.zed-table__header { - width: 100%; - position: sticky; - top: 0; - left: 0; - background: white; - z-index: 1; - font-family: var(--body-font); -} - -.zed-table__header-group { - display: flex; - align-items: center; - position: relative; - height: var(--header-height); - border-bottom: 1px solid var(--border-color); -} -.zed-table__header-group--parent { - display: flex; - align-items: center; - position: relative; - height: var(--header-height); - border-bottom: none; -} - -.zed-table__header-cell { - flex-shrink: 0; - line-height: var(--header-height); - height: 100%; - white-space: nowrap; - text-align: left; - font-weight: 700; - font-size: 11px; - position: relative; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 10px; - border-right: 1px solid var(--border-color); -} -.zed-table__header-cell:not(.isPlaceholder).hasChildren { - border-bottom: 1px solid var(--border-color); -} - -.zed-table__header-cell-info { - display: flex; - align-items: center; - height: 100%; - min-width: 0; - position: sticky; - left: 10px; -} - -.hasChildren .zed-table__header-cell-text { - font-weight: normal; - font-style: italic; -} - -.zed-table__header-cell-text { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - padding-right: 2px; -} - -.zed-table__sort-icon { - margin: 0 4px; - width: 11px; - height: 11px; - align-items: center; - justify-content: center; - flex-shrink: 0; -} - -.zed-table__header-resize-area { - width: 17px; - height: 100%; - position: absolute; - cursor: col-resize; - display: flex; - justify-content: center; - bottom: 0; - right: -8px; - z-index: 2; - border: 1px solid white; -} - -.zed-table__cell { - --background-color: #f9f9f9; - background-color: var(--background-color); - overflow: hidden; - white-space: nowrap; - padding: 0 10px; - padding-right: 0; - border-right: 2px solid white; -} -.zed-table__cell.even { - --background-color: white; -} -.zed-table__cell a { - display: flex; - align-items: center; - user-select: none; -} -.zed-table__cell a:hover { - background-color: rgba(0, 0, 0, 0.04); - border-radius: 3px; - cursor: default; -} - -.zed-table__line { - white-space: pre; - height: var(--row-height); - display: flex; - align-items: center; -} - -.zed-table__header-cell-menu-button { - display: flex; - align-items: center; - justify-content: center; - height: 20px; - width: 20px; - border-radius: 6px; - border: none; - z-index: 1; - opacity: 0; - background: none; - transition: all 200ms; - position: sticky; - right: 10px; -} -.zed-table__header-cell-menu-button:hover { - background: rgba(0, 0, 0, 0.08); -} -.zed-table__header-cell:hover .zed-table__header-cell-menu-button { - opacity: 1; -} -.zed-table--resizing .zed-table__header-cell-menu-button { - opacity: 0 !important; -} - -.list-item { - height: 28px; - display: flex; - align-items: center; - cursor: default; - user-select: none; - outline: none; - white-space: nowrap; - padding: 0 10px; -} -.list-item--over-folder { - background-color: hsla(0deg, 0%, 0%, 0.06); -} -.list-item--dragging:not(.list-item--selected) { - background-color: inherit; -} -.list-item:hover .list-item__menu { - width: auto; - visibility: visible; -} - -.list-item__background { - display: flex; - align-items: center; - width: 100%; - height: 100%; - border-radius: 6px; - font-size: 13px; -} -.list-item__background:hover:not(.dragging) { - background: rgba(0, 0, 0, 0.03); -} -.list-item--has-click .list-item__background:active:not(.dragging) { - background: rgba(0, 0, 0, 0.05); -} -.list-item__background.droppable { - background: rgba(0, 0, 0, 0.1); -} -[aria-role="tree-item"]:focus-visible .list-item__background { - background-color: var(--primary-color-light); -} -.list-item__background[aria-selected="true"] { - border-radius: 0; - outline: none; - background-color: var(--primary-color); - color: white; -} -.list-item__background[aria-selected="true"] svg { - fill: white; - opacity: 1; -} -.list-item__background[aria-selected="true"]:hover { - background-color: var(--primary-color); -} -.list-item__background[aria-selected="true"].selected-start { - border-top-left-radius: 6px; - border-top-right-radius: 6px; -} -.list-item__background[aria-selected="true"].selected-end { - border-bottom-left-radius: 6px; - border-bottom-right-radius: 6px; -} - -.list-item .list-item__toggle { - width: 16px; - transition: transform 200ms; -} -.list-item .list-item__toggle:hover, -.list-item .list-item__toggle:active { - background: none !important; -} -.list-item .list-item__toggle--open { - transform: rotate(90deg); -} - -.list-item__icon { - width: 22px; - height: 28px; - display: flex; - align-items: center; - justify-content: center; - margin-right: 2px; - flex-shrink: 0; -} -.list-item__icon:hover, -.list-item__icon:active { - background: none !important; -} - -.list-item__content { - overflow: hidden; - min-width: 0; - text-overflow: ellipsis; - flex: 1; -} - -.list-item__menu { - padding: 0; - flex-shrink: 0; - width: 0; - overflow: hidden; - display: flex; - align-items: center; -} - -.list-item__menu-item:hover, -.list-item__menu-item:active { - background: none !important; -} - -.columns-tree__type { - font-size: 10px; - display: inline-block; - margin-left: 2px; -} - -.columns-tree__item--hidden { - opacity: 0.5; -} -.columns-tree__item--hidden .list-item__menu { - visibility: visible; - width: auto; -} - -[class*="-bg-color"] { - background: #afafaf; - fill: #afafaf; -} - -.conn-bg-color { - background-color: #86c8b7; - fill: #86c8b7; -} - -.dhcp-bg-color { - background-color: #00578a; - fill: #00578a; -} - -.dns-bg-color { - background-color: #1ca0f2; - fill: #1ca0f2; -} - -.ftp-bg-color { - background-color: #392277; - fill: #392277; -} - -.http-bg-color { - background-color: hsl(49deg, 93%, 58%); - fill: hsl(49deg, 93%, 58%); -} - -.files-bg-color { - background-color: #ad3f95; - fill: #ad3f95; -} - -.mysql-bg-color { - background-color: #d28204; - fill: #d28204; -} - -.irc-bg-color { - background-color: #00d1a6; - fill: #00d1a6; -} - -.radius-bg-color { - background-color: #ffd901; - fill: #ffd901; -} - -.kerberos-bg-color { - background-color: #fbf758; - fill: #fbf758; -} - -.sip-bg-color { - background-color: #006c7b; - fill: #006c7b; -} - -.smtp-bg-color { - background-color: #e2e317; - fill: #e2e317; -} - -.ssl-bg-color { - background-color: hsl(0deg, 0%, 3%); - fill: hsl(0deg, 0%, 3%); -} - -.ssh-bg-color { - background-color: #535765; - fill: #535765; -} - -.syslog-bg-color { - background-color: #ddb81d; - fill: #ddb81d; -} - -.tunnel-bg-color { - background-color: #007249; - fill: #007249; -} - -.dce_rpc-bg-color { - background-color: #929292; - fill: #929292; -} - -.ntlm-bg-color { - background-color: #6284a4; - fill: #6284a4; -} - -.rdp-bg-color { - background-color: #081d5b; - fill: #081d5b; -} - -.smb_files-bg-color { - background-color: #27eeff; - fill: #27eeff; -} - -.smb_mapping-bg-color { - background-color: #0511d4; - fill: #0511d4; -} - -.weird-bg-color { - background-color: #5e6373; - fill: #5e6373; -} - -.x509-bg-color { - background-color: #eeb457; - fill: #eeb457; -} - -.pe-bg-color { - background-color: #e65835; - fill: #e65835; -} - -.dpd-bg-color { - background-color: #256453; - fill: #256453; -} - -.notice-bg-color { - background-color: red; - fill: red; -} - -.capture_loss-bg-color { - background-color: purple; - fill: purple; -} - -.software-bg-color { - background-color: hsl(203deg, 89%, 68%); - fill: hsl(203deg, 89%, 68%); -} - -.stats-bg-color { - background-color: #5ec4a8; - fill: #5ec4a8; -} - -.known_hosts-bg-color { - background-color: #eeb457; - fill: #eeb457; -} - -.known_services-bg-color { - background-color: #e99f29; - fill: #e99f29; -} - -.alert-1-bg-color { - background-color: var(--alert-1); - fill: var(--alert-1); -} - -.alert-2-bg-color { - background-color: var(--alert-2); - fill: var(--alert-2); -} - -.alert-3-bg-color { - background-color: var(--alert-3); - fill: var(--alert-3); -} - -.zeek-path-tag { - display: inline-block; - border-radius: 3px; - padding: 0 6px; - line-height: 17px; - font-weight: bold; - color: white; - text-align: center; -} - -.results-pane { - display: flex; - flex-direction: column; - border: none; - position: relative; - flex: 1; - min-height: 0; -} - -.results-pane__content { - flex: 1; - overflow: hidden; -} - -.zed-list-view { - font-size: 13px; - font-family: var(--mono-font), sans-serif; - line-height: 20px; -} - -.zed-view { - display: inline-flex; - white-space: pre; - align-items: center; -} -.zed-view a { - cursor: default; - border-radius: 3px; - display: inline-flex; - white-space: pre; - align-items: center; -} -.zed-view a:hover { - background: rgba(0, 0, 0, 0.04); -} -.zed-view a:active { - background: rgba(0, 0, 0, 0.07); -} -.zed-view i { - display: inline-flex; - align-items: center; - height: 20px; - margin-right: 2px; -} -.zed-view i svg { - fill: var(--aqua); - width: 14px; - height: 14px; -} -.zed-view__more-link { - background: var(--button-background); - color: var(--zed-key); - padding: 0 12px; -} -.zed-view__more-link:hover { - background: var(--button-background-hover); - color: var(--foreground-color); -} -.zed-view__more-link:active { - background: var(--button-background-active); -} - -/*# sourceMappingURL=main.css.map */ diff --git a/apps/zui/public/pool-wall-background.svg b/apps/zui/public/pool-wall-background.svg deleted file mode 100644 index e1110a05a2..0000000000 --- a/apps/zui/public/pool-wall-background.svg +++ /dev/null @@ -1,5638 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/zui/src/app/commands/editor.ts b/apps/zui/src/app/commands/editor.ts deleted file mode 100644 index aa78ba0639..0000000000 --- a/apps/zui/src/app/commands/editor.ts +++ /dev/null @@ -1,117 +0,0 @@ -import * as zed from "@brimdata/zed-js" -import program from "src/js/models/program" -import { - appendQueryCountBy, - appendQueryExclude, - appendQueryIn, - appendQueryInclude, - appendQueryNotIn, - appendQuerySortBy, -} from "src/js/flows/searchBar/actions" -import {copyToClipboard} from "src/js/lib/doc" -import Editor from "src/js/state/Editor" -import {toZedScript} from "src/js/zed-script/toZedScript" -import submitSearch from "../query-home/flows/submit-search" -import {createCommand} from "./command" - -type ColumnName = string | string[] - -export const copyValueToClipboard = createCommand( - "copyValueToClipboard", - (_, value: zed.Any) => { - const selection = document.getSelection() - copyToClipboard( - selection.isCollapsed ? value.toString() : selection.toString() - ) - } -) - -export const countByField = createCommand( - "countByField", - ({api}, field: zed.Field) => { - api.dispatch(appendQueryCountBy(field.path)) - api.dispatch(submitSearch()) - } -) - -export const filterEqualsValue = createCommand( - "filterEqualsValue", - ({api}, field: zed.Field) => { - api.dispatch(appendQueryInclude(field)) - api.dispatch(submitSearch()) - } -) - -export const filterNotEqualsValue = createCommand( - "filterNotEqualsValue", - ({api}, field: zed.Field) => { - api.dispatch(appendQueryExclude(field)) - api.dispatch(submitSearch()) - } -) - -export const filterInField = createCommand( - "filterInField", - ({api}, field: zed.Field, value: zed.Any) => { - if (value) { - api.dispatch(appendQueryIn(field, value as zed.Value)) - api.dispatch(submitSearch()) - } - } -) - -export const filterNotInField = createCommand( - "filterNotInField", - ({api}, field: zed.Field, value: zed.Any) => { - if (value) { - api.dispatch(appendQueryNotIn(field, value)) - api.dispatch(submitSearch()) - } - } -) - -export const newSearchWithValue = createCommand( - "newSearchWithValue", - ({api}, field: zed.Field) => { - api.dispatch(Editor.setValue(toZedScript(field.data))) - api.dispatch(submitSearch()) - } -) - -export const pivotToValues = createCommand( - "pivotToValues", - ({api}, field: zed.Field) => { - // So this only works if the count() by field is in the editor, not in a pin. - const record = field.rootRecord - api.current.query.toZed() - const newProgram = program(api.editor.value) - .drillDown(record as zed.Record) - .string() - - if (newProgram) { - api.dispatch(Editor.setValue(newProgram)) - api.dispatch(submitSearch()) - } - } -) - -export const sortAsc = createCommand( - "sortAsc", - ({api}, columnName: ColumnName) => { - api.dispatch(appendQuerySortBy(columnName, "asc")) - api.dispatch(submitSearch()) - } -) - -export const sortDesc = createCommand( - "sortDesc", - ({api}, columnName: ColumnName) => { - api.dispatch(appendQuerySortBy(columnName, "desc")) - api.dispatch(submitSearch()) - } -) - -export const fuse = createCommand("fuse", ({api}) => { - api.editor.append(api.editor.value.trim().length === 0 ? "fuse" : " | fuse") - api.dispatch(submitSearch()) -}) diff --git a/apps/zui/src/app/commands/pins.ts b/apps/zui/src/app/commands/pins.ts deleted file mode 100644 index 195ee72cc1..0000000000 --- a/apps/zui/src/app/commands/pins.ts +++ /dev/null @@ -1,125 +0,0 @@ -import * as zed from "@brimdata/zed-js" -import ZuiApi from "src/js/api/zui-api" -import {DateTuple} from "src/js/lib/TimeWindow" -import Editor from "src/js/state/Editor" -import {TimeRangeQueryPin} from "src/js/state/Editor/types" -import Pools from "src/js/state/Pools" -import submitSearch from "../query-home/flows/submit-search" -import {createCommand} from "./command" -import Current from "src/js/state/Current" -import PoolSettings from "src/js/state/PoolSettings" -import Tabs from "src/js/state/Tabs" - -export const createFromEditor = createCommand( - "pins.createFromEditor", - ({dispatch, api}) => { - if (api.editor.value.trim() === "") return - dispatch(Editor.pinValue()) - dispatch(submitSearch()) - } -) - -export const createGeneric = createCommand( - "pins.createGeneric", - ({dispatch, api}) => { - dispatch(Editor.addPin({type: "generic", value: ""})) - dispatch(Editor.editPin(api.editor.pins.length - 1)) - } -) - -export const createFrom = createCommand<[value?: string]>( - "pins.createFrom", - ({dispatch, api}, value = "") => { - dispatch(Editor.addPin({type: "from", value})) - if (value.length === 0) { - dispatch(Editor.editPin(api.editor.pins.length - 1)) - } else { - dispatch(submitSearch()) - } - } -) - -export const updateFrom = createCommand( - "pins.updateFrom", - ({dispatch, getState, api}, value: string) => { - if (Tabs.none(getState())) { - api.queries.open({pins: [{type: "from", value}], value: ""}) - } else { - dispatch(Editor.setFrom(value)) - dispatch(submitSearch()) - } - } -) - -function defaultFrom(now: Date) { - return new Date( - Date.UTC(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0) - ) -} - -function defaultTo(now: Date) { - return new Date( - Date.UTC(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0, 0) - ) -} - -async function defaultRange(api: ZuiApi): Promise { - const range = await api.dispatch(Pools.getTimeRange(api.current.poolName)) - const now = new Date() - const from = (range && range[0]) || defaultFrom(now) - const to = (range && range[1]) || defaultTo(now) - return [from, to] -} - -export const createTimeRange = createCommand( - "pins.createTimeRange", - async ({dispatch, api, getState}) => { - const pins = Editor.getPins(getState()) - const [from, to] = await defaultRange(api) - const poolId = Current.getPoolFromQuery(getState())?.id - const {timeField} = PoolSettings.findWithDefaults(getState(), poolId) - dispatch( - Editor.addPin({ - type: "time-range", - field: timeField, - from: from.toISOString(), - to: to.toISOString(), - }) - ) - dispatch(Editor.editPin(pins.length)) - } -) - -function currentRange(api: ZuiApi) { - const pin = api.editor.pins.find( - (p) => p.type === "time-range" - ) as TimeRangeQueryPin - if (pin) return [new Date(pin.from), new Date(pin.to)] as const - else return null -} - -export const setTimeRangeFrom = createCommand( - "pins.setTimeRangeFrom", - async ({api}, value: zed.Any) => { - if (!(value instanceof zed.Time)) return - const current = currentRange(api) - const defaults = await defaultRange(api) - const from = value.toDate() - const to = current ? current[1] : defaults[1] - api.dispatch(Editor.setTimeRange({from, to})) - api.dispatch(submitSearch()) - } -) - -export const setTimeRangeTo = createCommand( - "pins.setTimeRangeFrom", - async ({api}, value: zed.Any) => { - if (!(value instanceof zed.Time)) return - const current = currentRange(api) - const defaults = await defaultRange(api) - const from = current ? current[0] : defaults[0] - const to = value.toDate() - api.dispatch(Editor.setTimeRange({from, to})) - api.dispatch(submitSearch()) - } -) diff --git a/apps/zui/src/app/commands/queries.ts b/apps/zui/src/app/commands/queries.ts index bdd5ace264..976e778aa2 100644 --- a/apps/zui/src/app/commands/queries.ts +++ b/apps/zui/src/app/commands/queries.ts @@ -101,7 +101,7 @@ export const deleteCmd = createCommand( ) export const rename = createCommand("queries.rename", ({dispatch}) => { - dispatch(Layout.showTitleForm("update")) + dispatch(Layout.showTitleForm()) }) export const openLatestVersion = createCommand( diff --git a/apps/zui/src/app/commands/run-query.ts b/apps/zui/src/app/commands/run-query.ts index 6f27631444..89aea6bf29 100644 --- a/apps/zui/src/app/commands/run-query.ts +++ b/apps/zui/src/app/commands/run-query.ts @@ -1,6 +1,6 @@ +import {submitSearch} from "src/domain/session/handlers" import {createCommand} from "./command" -import submitSearch from "src/app/query-home/flows/submit-search" -export const runQuery = createCommand("submitSearch", ({dispatch}) => { - dispatch(submitSearch()) +export const runQuery = createCommand("submitSearch", () => { + submitSearch() }) diff --git a/apps/zui/src/app/commands/show-history-pane.ts b/apps/zui/src/app/commands/show-history-pane.ts deleted file mode 100644 index bb7b904d73..0000000000 --- a/apps/zui/src/app/commands/show-history-pane.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {createCommand} from "./command" - -export const showHistoryPane = createCommand("showHistoryPane", ({api}) => - api.layout.activatePane("history") -) diff --git a/apps/zui/src/app/commands/values.ts b/apps/zui/src/app/commands/values.ts deleted file mode 100644 index 8097617146..0000000000 --- a/apps/zui/src/app/commands/values.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as zed from "@brimdata/zed-js" -import {viewLogDetail} from "src/js/flows/viewLogDetail" -import virusTotal from "src/js/services/virusTotal" -import Modal from "src/js/state/Modal" -import {createCommand} from "./command" -import {invoke} from "src/core/invoke" - -export const showValueDetails = createCommand( - "showValueDetails", - ({api, dispatch}, value: zed.Any) => { - dispatch(viewLogDetail(value as zed.Record)) - api.layout.activatePane("detail") - } -) - -export const showWhoIs = createCommand( - "showWhoIs", - ({dispatch}, value: zed.Any) => { - dispatch(Modal.show("whois", {addr: value.toString()})) - } -) - -export const openVirusTotal = createCommand( - "openVirusTotal", - (_ctx, value: zed.Any) => { - if (value instanceof zed.Primitive && !value.isUnset()) { - invoke("openLinkOp", virusTotal.url(value.toString())) - } - } -) diff --git a/apps/zui/src/app/core/Data.tsx b/apps/zui/src/app/core/Data.tsx index 7b2894576a..d1253c444e 100644 --- a/apps/zui/src/app/core/Data.tsx +++ b/apps/zui/src/app/core/Data.tsx @@ -1,36 +1,14 @@ import styled from "styled-components" export const Data = styled.dl` - ${(p) => p.theme.typography.labelSmall} + font-family: var(--mono-font); display: flex; align-items: center; justify-content: center; position: relative; margin: 0; - padding: 0 12px; - height: 24px; cursor: default; - &:after { - content: ""; - position: absolute; - bottom: 0; - left: 12px; - right: 0; - height: 1px; - box-shadow: 0 0.5px 0 var(--cloudy); - } - - &:last-of-type:after { - display: none; - } - - &:hover { - background: rgba(0, 0, 0, 0.025); - } - - &:first-of-type:last-of-type:hover { - background: none; - } + min-height: 26px; ` export const Name = styled.dt` @@ -42,7 +20,6 @@ export const Value = styled.dd` flex: 1; text-align: right; margin: 0 0 0 8px; - color: var(--slate); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; diff --git a/apps/zui/src/app/core/icon-temp.tsx b/apps/zui/src/app/core/icon-temp.tsx deleted file mode 100644 index 12ed81d254..0000000000 --- a/apps/zui/src/app/core/icon-temp.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from "react" -import classNames from "classnames" -import styled from "styled-components" -import icons from "./icons" - -export type IconName = keyof typeof icons - -type Props = { - name: IconName - className?: string - size?: number - fill?: string - stroke?: string -} - -const Wrap = styled.i<{ - size?: number - fill?: string - stroke?: string -}>` - display: flex; - svg { - height: ${(p) => p.size || 22}px; - width: ${(p) => p.size || 22}px; - fill: ${(p) => p.fill || "currentColor"}; - stroke: ${(p) => p.stroke || "inherit"}; - } -` - -export default function Icon(props: Props) { - const SVG = icons[props.name] - if (!SVG) throw new Error(`No Icon: "${props.name}"`) - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/braces.tsx b/apps/zui/src/app/core/icons/braces.tsx deleted file mode 100644 index e771a7b30d..0000000000 --- a/apps/zui/src/app/core/icons/braces.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" -export default function Braces(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/branch.tsx b/apps/zui/src/app/core/icons/branch.tsx deleted file mode 100644 index 78942a3aba..0000000000 --- a/apps/zui/src/app/core/icons/branch.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react" -export default function Branch(props: any) { - return ( - - - - - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/carrot down.tsx b/apps/zui/src/app/core/icons/carrot down.tsx deleted file mode 100644 index 8f7e8b6836..0000000000 --- a/apps/zui/src/app/core/icons/carrot down.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react" -export default function CarrotDown(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/chart.tsx b/apps/zui/src/app/core/icons/chart.tsx deleted file mode 100644 index 1eaf82d4c2..0000000000 --- a/apps/zui/src/app/core/icons/chart.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" -export default function Chart(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/check.tsx b/apps/zui/src/app/core/icons/check.tsx deleted file mode 100644 index a4e60d3c68..0000000000 --- a/apps/zui/src/app/core/icons/check.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from "react" - -export default function Check(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/chevron-down.tsx b/apps/zui/src/app/core/icons/chevron-down.tsx deleted file mode 100644 index 53c9422394..0000000000 --- a/apps/zui/src/app/core/icons/chevron-down.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" -export default function ChevronDown(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/chevron-left.tsx b/apps/zui/src/app/core/icons/chevron-left.tsx deleted file mode 100644 index 13f83a094e..0000000000 --- a/apps/zui/src/app/core/icons/chevron-left.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react" -export default function ChevronLeft(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/chevron-right.tsx b/apps/zui/src/app/core/icons/chevron-right.tsx deleted file mode 100644 index 6b08a917b9..0000000000 --- a/apps/zui/src/app/core/icons/chevron-right.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react" -export default function ChevronRight(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/chevron-up.tsx b/apps/zui/src/app/core/icons/chevron-up.tsx deleted file mode 100644 index 9168903108..0000000000 --- a/apps/zui/src/app/core/icons/chevron-up.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react" -export default function ChevronUp(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/close.tsx b/apps/zui/src/app/core/icons/close.tsx deleted file mode 100644 index 6393f877d0..0000000000 --- a/apps/zui/src/app/core/icons/close.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react" -export default function Close(props: any) { - return ( - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/collapse-horizontal.tsx b/apps/zui/src/app/core/icons/collapse-horizontal.tsx deleted file mode 100644 index 686073971f..0000000000 --- a/apps/zui/src/app/core/icons/collapse-horizontal.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from "react" -export default function CollapseHorizontal(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/collapse.tsx b/apps/zui/src/app/core/icons/collapse.tsx deleted file mode 100644 index 6e479e4b7c..0000000000 --- a/apps/zui/src/app/core/icons/collapse.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react" -export default function Collapse(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/columns.tsx b/apps/zui/src/app/core/icons/columns.tsx deleted file mode 100644 index f5fc8f7c18..0000000000 --- a/apps/zui/src/app/core/icons/columns.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react" -export default function Columns(props: any) { - return ( - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/detach.tsx b/apps/zui/src/app/core/icons/detach.tsx deleted file mode 100644 index e03b3c00a3..0000000000 --- a/apps/zui/src/app/core/icons/detach.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" -export default function Detach(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/doc-plain.tsx b/apps/zui/src/app/core/icons/doc-plain.tsx deleted file mode 100644 index 2202dcc90a..0000000000 --- a/apps/zui/src/app/core/icons/doc-plain.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react" -export default function DocPlain(props: any) { - return ( - - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/double-chevron-right.tsx b/apps/zui/src/app/core/icons/double-chevron-right.tsx deleted file mode 100644 index 6c5d2b3544..0000000000 --- a/apps/zui/src/app/core/icons/double-chevron-right.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" -export default function DoubleChevronRight(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/duplicate.tsx b/apps/zui/src/app/core/icons/duplicate.tsx deleted file mode 100644 index c17d31c5de..0000000000 --- a/apps/zui/src/app/core/icons/duplicate.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react" - -export default function Duplicate(props: any) { - return ( - - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/expand-horizontal.tsx b/apps/zui/src/app/core/icons/expand-horizontal.tsx deleted file mode 100644 index b1391ebb4a..0000000000 --- a/apps/zui/src/app/core/icons/expand-horizontal.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from "react" - -export default function ExpandHorizontal(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/expand.tsx b/apps/zui/src/app/core/icons/expand.tsx deleted file mode 100644 index 77019e6310..0000000000 --- a/apps/zui/src/app/core/icons/expand.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react" -export default function Expand(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/export.tsx b/apps/zui/src/app/core/icons/export.tsx deleted file mode 100644 index f241f8e78c..0000000000 --- a/apps/zui/src/app/core/icons/export.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react" -export default function Export(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/file-border.tsx b/apps/zui/src/app/core/icons/file-border.tsx deleted file mode 100644 index 044b89f167..0000000000 --- a/apps/zui/src/app/core/icons/file-border.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react" -export default function FileBorder(props: any) { - return ( - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/file-filled.tsx b/apps/zui/src/app/core/icons/file-filled.tsx deleted file mode 100644 index 2a1771d8e4..0000000000 --- a/apps/zui/src/app/core/icons/file-filled.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react" -export default function FileFilled(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/folder.tsx b/apps/zui/src/app/core/icons/folder.tsx deleted file mode 100644 index 0e95917ac2..0000000000 --- a/apps/zui/src/app/core/icons/folder.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from "react" -export default function Folder(props: any) { - return ( - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/grid.tsx b/apps/zui/src/app/core/icons/grid.tsx deleted file mode 100644 index 636f4beb10..0000000000 --- a/apps/zui/src/app/core/icons/grid.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" -export default function Grid(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/hide.tsx b/apps/zui/src/app/core/icons/hide.tsx deleted file mode 100644 index ad72ce9c6e..0000000000 --- a/apps/zui/src/app/core/icons/hide.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from "react" -export default function Hide(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/history.tsx b/apps/zui/src/app/core/icons/history.tsx deleted file mode 100644 index 6163084cf7..0000000000 --- a/apps/zui/src/app/core/icons/history.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react" -export default function History(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/index.ts b/apps/zui/src/app/core/icons/index.ts deleted file mode 100644 index 4bd62eb761..0000000000 --- a/apps/zui/src/app/core/icons/index.ts +++ /dev/null @@ -1,95 +0,0 @@ -import threeDots from "./three-dots" -import chart from "./chart" -import grid from "./grid" -import list from "./list" -import view from "./view" -import sharkfin from "./sharkfin" -import exportIcon from "./export" -import columns from "./columns" -import chevronDown from "./chevron-down" -import chevronUp from "./chevron-up" -import chevronLeft from "./chevron-left" -import chevronRight from "./chevron-right" -import doubleChevronRight from "./double-chevron-right" -import reload from "./reload" -import warning from "./warning" -import braces from "./braces" -import expand from "./expand" -import collapse from "./collapse" -import pool from "./pool" -import history from "./history" -import folder from "./folder" -import query from "./query" -import fileBorder from "./file-border" -import fileFilled from "./file-filled" -import docPlain from "./doc-plain" -import tag from "./tag" -import run from "./run" -import pin from "./pin" -import lock from "./lock" -import close from "./close" -import plus from "./plus" -import zui from "./zui" -import LeftArrow from "./left-arrow" -import RightArrow from "./right-arrow" -import sidebarToggle from "./sidebar-toggle" -import check from "./check" -import update from "./update" -import detach from "./detach" -import threeDotsStacked from "./three-dots-stacked" -import ExpandHorizontal from "./expand-horizontal" -import CollapseHorizontal from "./collapse-horizontal" -import show from "./show" -import hide from "./hide" -import SortAsc from "./sort-asc" -import SortDesc from "./sort-desc" -import RightSidebarToggle from "./right-sidebar-toggle" - -export default { - check, - update, - detach, - braces, - expand, - collapse, - chart, - grid, - list, - lock, - view, - sharkfin, - export: exportIcon, - columns, - "chevron-down": chevronDown, - "chevron-up": chevronUp, - "chevron-left": chevronLeft, - "chevron-right": chevronRight, - "double-chevron-right": doubleChevronRight, - "three-dots": threeDots, - reload, - warning, - history, - folder, - pool, - query, - run, - "sidebar-toggle": sidebarToggle, - "right-sidebar-toggle": RightSidebarToggle, - "file-border": fileBorder, - "file-filled": fileFilled, - "doc-plain": docPlain, - tag, - pin, - close, - plus, - zui, - "left-arrow": LeftArrow, - "right-arrow": RightArrow, - "three-dots-stacked": threeDotsStacked, - "expand-horizontal": ExpandHorizontal, - "collapse-horizontal": CollapseHorizontal, - show, - hide, - "sort-asc": SortAsc, - "sort-desc": SortDesc, -} diff --git a/apps/zui/src/app/core/icons/lamda.tsx b/apps/zui/src/app/core/icons/lamda.tsx deleted file mode 100644 index 0c430f46c6..0000000000 --- a/apps/zui/src/app/core/icons/lamda.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react" -export default function Lamda(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/left-arrow.tsx b/apps/zui/src/app/core/icons/left-arrow.tsx deleted file mode 100644 index 58e9ce4ada..0000000000 --- a/apps/zui/src/app/core/icons/left-arrow.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from "react" - -export default function LeftArrow(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/list.tsx b/apps/zui/src/app/core/icons/list.tsx deleted file mode 100644 index bf7ac1d6f3..0000000000 --- a/apps/zui/src/app/core/icons/list.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" -export default function List(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/lock.tsx b/apps/zui/src/app/core/icons/lock.tsx deleted file mode 100644 index e73a3a8c95..0000000000 --- a/apps/zui/src/app/core/icons/lock.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from "react" - -export default function Lock(props: any) { - return ( - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/pin.tsx b/apps/zui/src/app/core/icons/pin.tsx deleted file mode 100644 index efdc05a4db..0000000000 --- a/apps/zui/src/app/core/icons/pin.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from "react" -export default function Pin(props: any) { - return ( - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/plus.tsx b/apps/zui/src/app/core/icons/plus.tsx deleted file mode 100644 index 3bca7ad5e8..0000000000 --- a/apps/zui/src/app/core/icons/plus.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react" -export default function Plus(props: any) { - return ( - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/pool.tsx b/apps/zui/src/app/core/icons/pool.tsx deleted file mode 100644 index ce71a58e99..0000000000 --- a/apps/zui/src/app/core/icons/pool.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react" -export default function Pool(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/query.tsx b/apps/zui/src/app/core/icons/query.tsx deleted file mode 100644 index b44636c221..0000000000 --- a/apps/zui/src/app/core/icons/query.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from "react" -export default function Query(props: any) { - return ( - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/reload.tsx b/apps/zui/src/app/core/icons/reload.tsx deleted file mode 100644 index 361b37d23e..0000000000 --- a/apps/zui/src/app/core/icons/reload.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" -export default function Reload(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/right-arrow.tsx b/apps/zui/src/app/core/icons/right-arrow.tsx deleted file mode 100644 index 5be05bd335..0000000000 --- a/apps/zui/src/app/core/icons/right-arrow.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from "react" - -export default function RightArrow(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/right-sidebar-toggle.tsx b/apps/zui/src/app/core/icons/right-sidebar-toggle.tsx deleted file mode 100644 index edae85756d..0000000000 --- a/apps/zui/src/app/core/icons/right-sidebar-toggle.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react" - -const RightSidebarToggle = (props: any) => { - return ( - - - - ) -} - -export default RightSidebarToggle diff --git a/apps/zui/src/app/core/icons/run.tsx b/apps/zui/src/app/core/icons/run.tsx deleted file mode 100644 index 7489b9c757..0000000000 --- a/apps/zui/src/app/core/icons/run.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react" - -export default function Run(props: any) { - return ( - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/sharkfin.tsx b/apps/zui/src/app/core/icons/sharkfin.tsx deleted file mode 100644 index fe80bc06c8..0000000000 --- a/apps/zui/src/app/core/icons/sharkfin.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from "react" -export default function Sharkfin(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/show.tsx b/apps/zui/src/app/core/icons/show.tsx deleted file mode 100644 index 39cf436435..0000000000 --- a/apps/zui/src/app/core/icons/show.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from "react" - -export default function Show(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/sidebar-toggle.tsx b/apps/zui/src/app/core/icons/sidebar-toggle.tsx deleted file mode 100644 index 9f67752928..0000000000 --- a/apps/zui/src/app/core/icons/sidebar-toggle.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" - -const SidebarToggle = (props: any) => { - return ( - - - - ) -} - -export default SidebarToggle diff --git a/apps/zui/src/app/core/icons/snippet.tsx b/apps/zui/src/app/core/icons/snippet.tsx deleted file mode 100644 index 050eb1a3c6..0000000000 --- a/apps/zui/src/app/core/icons/snippet.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react" - -export default function Snippet(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/sort-asc.tsx b/apps/zui/src/app/core/icons/sort-asc.tsx deleted file mode 100644 index ae23a402be..0000000000 --- a/apps/zui/src/app/core/icons/sort-asc.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react" - -export default function SortAsc(props: any) { - return ( - - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/sort-desc.tsx b/apps/zui/src/app/core/icons/sort-desc.tsx deleted file mode 100644 index ea3d59ff8a..0000000000 --- a/apps/zui/src/app/core/icons/sort-desc.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react" - -export default function SortDesc(props) { - return ( - - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/tag.tsx b/apps/zui/src/app/core/icons/tag.tsx deleted file mode 100644 index 75964d4859..0000000000 --- a/apps/zui/src/app/core/icons/tag.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react" -export default function Tag(props: any) { - return ( - - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/three-dots-stacked.tsx b/apps/zui/src/app/core/icons/three-dots-stacked.tsx deleted file mode 100644 index 0f3af3a6ca..0000000000 --- a/apps/zui/src/app/core/icons/three-dots-stacked.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" - -export default function ThreeDots(props: any) { - return ( - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/three-dots.tsx b/apps/zui/src/app/core/icons/three-dots.tsx deleted file mode 100644 index 07b1979297..0000000000 --- a/apps/zui/src/app/core/icons/three-dots.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react" -export default function ThreeDots(props: any) { - return ( - - - - - - ) -} diff --git a/apps/zui/src/app/core/icons/update.tsx b/apps/zui/src/app/core/icons/update.tsx deleted file mode 100644 index 7b6e0cbc86..0000000000 --- a/apps/zui/src/app/core/icons/update.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react" -export default function Update(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/view.tsx b/apps/zui/src/app/core/icons/view.tsx deleted file mode 100644 index 6d98c938b6..0000000000 --- a/apps/zui/src/app/core/icons/view.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react" -export default function View(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/warning.tsx b/apps/zui/src/app/core/icons/warning.tsx deleted file mode 100644 index f9299fec80..0000000000 --- a/apps/zui/src/app/core/icons/warning.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from "react" -export default function Warning(props: any) { - return ( - - - - ) -} diff --git a/apps/zui/src/app/core/icons/zui.tsx b/apps/zui/src/app/core/icons/zui.tsx deleted file mode 100644 index 68008ce36d..0000000000 --- a/apps/zui/src/app/core/icons/zui.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react" -export default function Zui(props: any) { - return ( - - - - - - - ) -} diff --git a/apps/zui/src/app/core/models/active-query.ts b/apps/zui/src/app/core/models/active-query.ts index 45f4276275..7d879443c7 100644 --- a/apps/zui/src/app/core/models/active-query.ts +++ b/apps/zui/src/app/core/models/active-query.ts @@ -36,7 +36,7 @@ export class ActiveQuery { } isModified() { - return !this.isAnonymous() && !this.query.hasVersion(this.versionId()) + return !this.isAnonymous() && !this.isLatest() } isOutdated() { diff --git a/apps/zui/src/app/detail/Fields.tsx b/apps/zui/src/app/detail/Fields.tsx index 9323d40767..07728e7c0b 100644 --- a/apps/zui/src/app/detail/Fields.tsx +++ b/apps/zui/src/app/detail/Fields.tsx @@ -1,9 +1,7 @@ import {Data, Name, Value} from "src/app/core/Data" import {useZedFormatter} from "src/app/core/format" import {zedTypeClassName} from "src/app/core/utils/zed-type-class-name" -import React, {memo, useCallback, useMemo, useState} from "react" -import Tooltip from "src/js/components/Tooltip" -import ColumnDescription from "src/js/components/LogDetails/ColumnDescription" +import React, {memo, useMemo} from "react" import * as zed from "@brimdata/zed-js" import Panel from "./Panel" import PanelHeading from "./PanelHeading" @@ -14,23 +12,19 @@ type Props = { type DTProps = { fields: zed.Field[] - onHover: (f: zed.Field) => void format: (f: zed.Value) => string } const LIMIT = 500 const DataPanel = React.memo(function DataTable({ fields, - onHover, format, }: DTProps) { const items = fields.slice(0, LIMIT).filter((f) => !!f) return ( {items.map((field, index) => ( - onHover(field)}> - - {field.path.join(" ‣ ")} - + + {field.path.join(" ‣ ")} {format(field.data as zed.Primitive)} @@ -46,37 +40,8 @@ const DataPanel = React.memo(function DataTable({ ) }) -function TooltipAnchor({children}) { - return ( - - {children} - - ) -} - -function ColumnTooltip({field, record}) { - return ( - - - - ) -} - export default memo(function Fields({record}: Props) { - const [hovered, setHovered] = useState({name: "", type: ""}) const format = useZedFormatter() - const onHover = useCallback((field: any) => { - setHovered(field) - }, []) const fields = useMemo(() => { if (record) { @@ -89,8 +54,7 @@ export default memo(function Fields({record}: Props) { return (
Fields - - +
) }) diff --git a/apps/zui/src/app/detail/Panel.tsx b/apps/zui/src/app/detail/Panel.tsx index 39e73b1ae7..a980c8a9e5 100644 --- a/apps/zui/src/app/detail/Panel.tsx +++ b/apps/zui/src/app/detail/Panel.tsx @@ -1,19 +1,20 @@ import React, {memo, ReactNode} from "react" import InlineTableLoading from "src/js/components/InlineTableLoading" -import styled from "styled-components" import {ChartWrap} from "./Shared" - -export const BG = styled.div` - background: white; - border-radius: 8px; - box-shadow: 0 0 1px var(--slate); -` +import styled from "styled-components" type Props = { isLoading?: boolean children: ReactNode } +const BG = styled.div` + background: var(--bg-color); + background: var(--emphasis-bg-less); + border-radius: 8px; + padding: 0.5rem 1rem; +` + export default memo(function Panel({isLoading, children}: Props) { return ( diff --git a/apps/zui/src/app/detail/PanelHeading.tsx b/apps/zui/src/app/detail/PanelHeading.tsx index d0a6af7749..52c5166c14 100644 --- a/apps/zui/src/app/detail/PanelHeading.tsx +++ b/apps/zui/src/app/detail/PanelHeading.tsx @@ -9,12 +9,14 @@ const BG = styled.div` h4 { margin: 0; - ${(p) => p.theme.typography.headingList} + font-weight: bold; + font-size: 1rem; + padding-left: 0.5rem; } .burst-1, .burst-2 { - background-color: var(--lead); + background-color: var(--chrome-color); } ` diff --git a/apps/zui/src/app/detail/Shared.tsx b/apps/zui/src/app/detail/Shared.tsx index d5079b84e8..d59b27dc4c 100644 --- a/apps/zui/src/app/detail/Shared.tsx +++ b/apps/zui/src/app/detail/Shared.tsx @@ -12,6 +12,6 @@ export const Caption = styled.p` ${(p) => p.theme.typography.labelSmall} font-style: italic; text-align: right; - color: var(--slate); + color: var(--fg-color-less); margin-right: 4px; ` diff --git a/apps/zui/src/app/features/inspector/list.styled.tsx b/apps/zui/src/app/features/inspector/list.styled.tsx deleted file mode 100644 index d7d4998bd9..0000000000 --- a/apps/zui/src/app/features/inspector/list.styled.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import {FixedSizeList} from "react-window" -import styled from "styled-components" -import {ComponentType, PropsWithChildren} from "react" - -export const List: ComponentType> = styled( - FixedSizeList -)` - font-size: 13px; - font-family: var(--mono-font), sans-serif; - line-height: 20px; - - .inspector-row { - display: inline-flex; - white-space: pre; - align-items: center; - } - - a { - cursor: default; - &:hover { - background: rgba(0, 0, 0, 0.04); - } - &:active { - background: rgba(0, 0, 0, 0.07); - } - border-radius: 3px; - display: inline-flex; - white-space: pre; - align-items: center; - } - - i { - display: inline-flex; - align-items: center; - height: 20px; - margin-right: 2px; - svg { - fill: var(--aqua); - width: 14px; - height: 14px; - } - } - - a.render-more { - background: var(--button-background); - color: var(--zed-key); - padding: 0 12px; - &:hover { - background: var(--button-background-hover); - color: var(--foreground-color); - } - &:active { - background: var(--button-background-active); - } - } -` diff --git a/apps/zui/src/app/features/inspector/templates/container.tsx b/apps/zui/src/app/features/inspector/templates/container.tsx index c16ed259f7..6f31c66668 100644 --- a/apps/zui/src/app/features/inspector/templates/container.tsx +++ b/apps/zui/src/app/features/inspector/templates/container.tsx @@ -1,6 +1,6 @@ import React, {ReactNode} from "react" import {ContainerView} from "../views/container-view" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import classNames from "classnames" import * as zed from "@brimdata/zed-js" import {note} from "./note" @@ -76,9 +76,9 @@ export function name(view: ContainerView) { export function icon(view: ContainerView) { if (view.isExpanded()) { - return + return } else { - return + return } } diff --git a/apps/zui/src/app/features/inspector/templates/item.tsx b/apps/zui/src/app/features/inspector/templates/item.tsx index 70515c9ea5..7092893856 100644 --- a/apps/zui/src/app/features/inspector/templates/item.tsx +++ b/apps/zui/src/app/features/inspector/templates/item.tsx @@ -7,17 +7,18 @@ export function clickHandlers(view: View) { return { onContextMenu: (e: React.MouseEvent) => { const fn = ctx.onContextMenu - fn && fn(e as any, value, field) + fn && fn(e as any, value as any, field) }, onClick: (e: React.MouseEvent) => { const fn = ctx.onClick - fn && fn(e as any, value, field) + fn && fn(e as any, value as any, field) }, } } export function item(view: View, mode: RenderMode) { const props = { + role: "gridcell", key: "item-" + view.id, className: view.className, ...clickHandlers(view), diff --git a/apps/zui/src/app/features/inspector/templates/key.tsx b/apps/zui/src/app/features/inspector/templates/key.tsx index d22709ad72..9a763caad5 100644 --- a/apps/zui/src/app/features/inspector/templates/key.tsx +++ b/apps/zui/src/app/features/inspector/templates/key.tsx @@ -6,7 +6,12 @@ import {clickHandlers, item} from "./item" // The key could be a complext type in the case of a map export function key(view: View) { return ( - + {typeof view.key === "string" ? view.key : item(createView({...view.args, value: view.key}), "single")} diff --git a/apps/zui/src/app/features/right-pane/common.tsx b/apps/zui/src/app/features/right-pane/common.tsx index ad5d2cdfcf..430a27a549 100644 --- a/apps/zui/src/app/features/right-pane/common.tsx +++ b/apps/zui/src/app/features/right-pane/common.tsx @@ -17,9 +17,6 @@ export const PaneBody = styled.div` export const PaneHeader = styled.header` user-select: none; position: relative; - svg { - fill: var(--slate); - } flex-shrink: 0; display: flex; align-items: center; diff --git a/apps/zui/src/app/features/right-pane/history/history-item.tsx b/apps/zui/src/app/features/right-pane/history/history-item.tsx index 6c7ff91882..7606e748a6 100644 --- a/apps/zui/src/app/features/right-pane/history/history-item.tsx +++ b/apps/zui/src/app/features/right-pane/history/history-item.tsx @@ -6,15 +6,14 @@ import Current from "src/js/state/Current" import Queries from "src/js/state/Queries" import QueryVersions from "src/js/state/QueryVersions" import styled from "styled-components" -import {Timeline} from "./timeline" import {useEntryMenu} from "./use-entry-menu" import {State} from "src/js/state/types" import {ActiveQuery} from "src/app/core/models/active-query" import {NodeRendererProps} from "react-arborist" const Wrap = styled.div` - height: 28px; - padding: 0 10px; + height: 100%; + padding: 0 0.25rem; cursor: default; ` const BG = styled.div` @@ -23,13 +22,12 @@ const BG = styled.div` border-radius: 6px; display: flex; align-items: center; - padding-left: 20px; - padding-right: 6px; + padding: 0 1rem; &:hover { - background-color: rgba(0, 0, 0, 0.04); + background-color: var(--emphasis-bg-less); } &:active { - background-color: rgba(0, 0, 0, 0.06); + background-color: var(--emphasis-bg-more); } &.deleted { cursor: not-allowed; @@ -37,16 +35,16 @@ const BG = styled.div` ` const Text = styled.p` + font-family: var(--mono-font); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - padding: 0 12px; flex: 1; .anonymous &, .modified &, .deleted & { - opacity: 0.65; + opacity: 0.7; font-weight: 400; } ` @@ -63,17 +61,6 @@ export type EntryType = | "deleted" | "modified" -function getColor(type: EntryType) { - switch (type) { - case "latest": - return "var(--primary-color)" - case "outdated": - return "var(--yellow)" - default: - return "var(--border-color)" - } -} - type Props = { version: string queryId: string @@ -133,14 +120,12 @@ export function HistoryItem({node}: NodeRendererProps) { api.queries.open(active.id(), {version: active.versionId(), history: false}) } const type = getType(active) - const color = getColor(type) const value = getValue(active) const timestamp = getTimestamp(active) return ( - {value} {timestamp} diff --git a/apps/zui/src/app/features/right-pane/history/section.tsx b/apps/zui/src/app/features/right-pane/history/section.tsx index a753f62f7d..49ab74dc23 100644 --- a/apps/zui/src/app/features/right-pane/history/section.tsx +++ b/apps/zui/src/app/features/right-pane/history/section.tsx @@ -8,6 +8,7 @@ import {EmptyText} from "../common" import {FillFlexParent} from "src/components/fill-flex-parent" import {Tree} from "react-arborist" import {useZuiApi} from "src/app/core/context" +import {TREE_ITEM_HEIGHT} from "../../sidebar/item" const BG = styled.div` display: flex; @@ -41,7 +42,7 @@ export function HistorySection() { {...dimens} data={history} padding={8} - rowHeight={26} + rowHeight={TREE_ITEM_HEIGHT} indent={8} disableDrag disableDrop diff --git a/apps/zui/src/app/features/right-pane/history/use-entry-menu.ts b/apps/zui/src/app/features/right-pane/history/use-entry-menu.ts index f97506b2f9..fdc32b72e7 100644 --- a/apps/zui/src/app/features/right-pane/history/use-entry-menu.ts +++ b/apps/zui/src/app/features/right-pane/history/use-entry-menu.ts @@ -1,6 +1,6 @@ import {useDispatch} from "react-redux" import useSelect from "src/app/core/hooks/use-select" -import {showContextMenu} from "src/js/lib/System" +import {showContextMenu} from "src/core/menu" import Current from "src/js/state/Current" import SessionHistories from "src/js/state/SessionHistories" diff --git a/apps/zui/src/app/features/right-pane/index.tsx b/apps/zui/src/app/features/right-pane/index.tsx index b2824ba8c8..9659d5f50f 100644 --- a/apps/zui/src/app/features/right-pane/index.tsx +++ b/apps/zui/src/app/features/right-pane/index.tsx @@ -13,12 +13,12 @@ import {SectionTabs} from "src/components/section-tabs" import {PaneName} from "src/js/state/Layout/types" import {ColumnsPane} from "src/views/columns-pane" import Appearance from "src/js/state/Appearance" +import Current from "src/js/state/Current" const Pane = styled(DraggablePane)` display: flex; flex-direction: column; - border-left: 1px solid var(--border-color); - background: var(--chrome-color); + grid-area: secondary-sidebar; ` const PaneContentSwitch = ({paneName}) => { @@ -37,9 +37,7 @@ const PaneContentSwitch = ({paneName}) => { } const BG = styled.div` - height: 37px; - background: var(--chrome-color); - border-bottom: 1px solid var(--border-color); + height: 41px; flex-shrink: 0; padding: 0 8px; ` @@ -76,7 +74,6 @@ export function Menu(props: {paneName: string}) { function Container({children}) { const dispatch = useDispatch() - const width = useSelector(Appearance.secondarySidebarWidth) const isOpen = useSelector(Appearance.secondarySidebarIsOpen) const onDrag = (e: React.MouseEvent) => { @@ -89,7 +86,7 @@ function Container({children}) { return ( // @ts-ignore - + {children} ) @@ -108,4 +105,10 @@ const RightPane = () => { ) } -export default RightPane +const WithRightPane = () => { + const tab = useSelector(Current.getTabId) + if (!tab) return null + return +} + +export default WithRightPane diff --git a/apps/zui/src/app/features/right-pane/version-item.tsx b/apps/zui/src/app/features/right-pane/version-item.tsx index fd614c01bb..44b35e237a 100644 --- a/apps/zui/src/app/features/right-pane/version-item.tsx +++ b/apps/zui/src/app/features/right-pane/version-item.tsx @@ -33,13 +33,14 @@ const Dot = styled.div` ` const Container = styled.div` - height: 28px; + height: 100%; width: 100%; cursor: default; user-select: none; outline: none; white-space: nowrap; padding: 0 10px; + font-size: 15px; &:not(:last-child) { ${Dot}:before { @@ -48,7 +49,7 @@ const Container = styled.div` left: 2px; top: 16px; margin-top: 7px; - border-left: 1px solid var(--hawkes-blue); + border-left: 1px solid var(--primary-color-dark); height: 14px; width: 1px; } diff --git a/apps/zui/src/app/features/right-pane/versions-section.tsx b/apps/zui/src/app/features/right-pane/versions-section.tsx index 6d8189eb20..60af7c71d7 100644 --- a/apps/zui/src/app/features/right-pane/versions-section.tsx +++ b/apps/zui/src/app/features/right-pane/versions-section.tsx @@ -7,6 +7,7 @@ import {QueryModel} from "src/js/models/query-model" import {EmptyText} from "./common" import {FillFlexParent} from "src/components/fill-flex-parent" import {useZuiApi} from "src/app/core/context" +import {TREE_ITEM_HEIGHT} from "../sidebar/item" const EmptyMessage = () => { return Open a saved query to see the previous versions. @@ -38,7 +39,7 @@ const VersionsList = ({query}: {query: QueryModel}) => { {...dimens} disableDrag indent={16} - rowHeight={28} + rowHeight={TREE_ITEM_HEIGHT} padding={8} data={data} selection={currentId} diff --git a/apps/zui/src/app/features/sidebar/content.tsx b/apps/zui/src/app/features/sidebar/content.tsx index 805b71ae0b..48c9798bc9 100644 --- a/apps/zui/src/app/features/sidebar/content.tsx +++ b/apps/zui/src/app/features/sidebar/content.tsx @@ -13,7 +13,7 @@ export const Content = styled.div` right: 0; width: 100%; height: 1px; - box-shadow: inset 0 0.5px 0 0 var(--aqua); + box-shadow: inset 0 0.5px 0 0 var(--border-color); opacity: 0.12; } ` diff --git a/apps/zui/src/app/features/sidebar/index.tsx b/apps/zui/src/app/features/sidebar/index.tsx index 0e05a36c5c..5cae65d90c 100644 --- a/apps/zui/src/app/features/sidebar/index.tsx +++ b/apps/zui/src/app/features/sidebar/index.tsx @@ -14,7 +14,7 @@ import {Body} from "./body" const EmptyText = styled.div` ${(p) => p.theme.typography.labelNormal} - color: var(--slate); + color: var(--fg-color-less); margin-top: 110px; padding: 0 24px; text-align: center; @@ -34,11 +34,11 @@ const PaneSwitch = ({name}) => { const Pane = styled(DraggablePane)` height: 100%; width: 100%; - background: var(--sidebar-background); overflow-x: unset; grid-area: sidebar; display: flex; flex-direction: column; + font-size: 15px; ` const SidebarTop = styled.div` diff --git a/apps/zui/src/app/features/sidebar/item.tsx b/apps/zui/src/app/features/sidebar/item.tsx index 7646083ac1..a5c48d1f96 100644 --- a/apps/zui/src/app/features/sidebar/item.tsx +++ b/apps/zui/src/app/features/sidebar/item.tsx @@ -9,12 +9,14 @@ import React, { useRef, } from "react" import {NodeState} from "react-arborist" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import ProgressIndicator from "src/js/components/ProgressIndicator" import styled, {CSSProperties} from "styled-components" +export const TREE_ITEM_HEIGHT = 32 + const Container = styled.div` - height: 28px; + height: ${TREE_ITEM_HEIGHT}px; display: flex; align-items: center; cursor: default; @@ -47,11 +49,11 @@ const BG = styled.div` border-radius: 6px; &:hover:not(.dragging) { - background: var(--sidebar-item-hover); + background: var(--emphasis-bg-less); } &:active:not(.dragging) { - background: var(--sidebar-item-active); + background: var(--emphasis-bg); box-shadow: var(--sidebar-item-active-shadow); } @@ -66,18 +68,17 @@ const BG = styled.div` &[aria-selected="true"] { border-radius: 0; outline: none; - background-color: var(--primary-color); - box-shadow: var(--sidebar-item-active-shadow); - color: white; + box-shadow: var(--shadow-small); + background: var(--selected-bg); + svg { - fill: white; opacity: 1; } &:hover { - background-color: var(--primary-color); + background-color: var(--selected-bg); } &:active { - background-color: var(--primary-color-dark); + background-color: var(--selected-bg-active); } &.selected-start { border-top-left-radius: 6px; @@ -103,11 +104,9 @@ const Input = styled.input` const ItemIconBG = styled.div<{isFolder: boolean}>` margin-left: ${(p) => (p.isFolder ? 0 : 16)}px; + display: flex; svg { - width: 14px; - height: 14px; opacity: 0.5; - fill: var(--foreground-color); } ` @@ -125,9 +124,6 @@ const ProgressBG = styled.div` .progress-track { background-color: rgba(0, 0, 0, 0.15); } - .progress-fill { - background-color: white; - } flex: 0.5; max-width: 50px; margin: 0 10px; @@ -147,7 +143,7 @@ function Toggle(props: ItemProps) { props.onToggle() }} > - + ) } diff --git a/apps/zui/src/app/features/sidebar/lake-picker.tsx b/apps/zui/src/app/features/sidebar/lake-picker.tsx index 21f556644f..6926eea01d 100644 --- a/apps/zui/src/app/features/sidebar/lake-picker.tsx +++ b/apps/zui/src/app/features/sidebar/lake-picker.tsx @@ -1,9 +1,8 @@ import React from "react" import useLakeId from "src/app/router/hooks/use-lake-id" -import {MenuItemConstructorOptions} from "electron" import {useDispatch, useSelector} from "react-redux" import styled from "styled-components" -import {showContextMenu} from "src/js/lib/System" +import {MenuItem, showContextMenu} from "src/core/menu" import Current from "src/js/state/Current" import Modal from "src/js/state/Modal" import {AppDispatch} from "src/js/state/types" @@ -36,7 +35,7 @@ const NameColumn = styled.div` overflow: hidden; label { display: block; - font-size: 14px; + font-size: 15px; font-weight: bold; text-overflow: ellipsis; white-space: nowrap; @@ -44,9 +43,9 @@ const NameColumn = styled.div` } label:last-child { - font-size: 13px; + font-size: 12px; font-weight: normal; - font-family: var(--moo-font); + font-family: var(--mono-font); opacity: 0.5; } ` @@ -55,7 +54,7 @@ const showLakeSelectMenu = () => (dispatch, getState) => { const lakes = Lakes.all(getState()) const currentId = Current.getLakeId(getState()) - const template: MenuItemConstructorOptions[] = [ + const template: MenuItem[] = [ { label: "Get Info", click: () => dispatch(Modal.show("view-lake")), diff --git a/apps/zui/src/app/features/sidebar/plus-button.tsx b/apps/zui/src/app/features/sidebar/plus-button.tsx index 0bb347b188..834a7ef075 100644 --- a/apps/zui/src/app/features/sidebar/plus-button.tsx +++ b/apps/zui/src/app/features/sidebar/plus-button.tsx @@ -3,16 +3,16 @@ import styled from "styled-components" import useCallbackRef from "src/js/components/hooks/useCallbackRef" import {useZuiApi} from "src/app/core/context" -import {MenuItemConstructorOptions} from "electron" -import {showContextMenu} from "src/js/lib/System" +import {MenuItem, showContextMenu} from "src/core/menu" import {useDispatch} from "src/app/core/state" import useLakeId from "src/app/router/hooks/use-lake-id" import Tabs from "src/js/state/Tabs" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import {connectToLake} from "src/app/commands/connect-to-lake" import Modal from "src/js/state/Modal" export const Button = styled.button` + color: white; display: flex; flex-shrink: 0; align-items: center; @@ -47,7 +47,7 @@ export default function PlusButton() { } const onClick = () => { - const template: MenuItemConstructorOptions[] = [ + const template: MenuItem[] = [ { label: "New Query Session", click: () => dispatch(Tabs.createQuerySession()), @@ -73,7 +73,7 @@ export default function PlusButton() { return ( <> { - + setSearchTerm(e.currentTarget.value)} diff --git a/apps/zui/src/app/features/sidebar/pools-section/pool-item.tsx b/apps/zui/src/app/features/sidebar/pools-section/pool-item.tsx index 3ef644ec8c..42942001a5 100644 --- a/apps/zui/src/app/features/sidebar/pools-section/pool-item.tsx +++ b/apps/zui/src/app/features/sidebar/pools-section/pool-item.tsx @@ -1,16 +1,17 @@ import React from "react" import {useSelector} from "react-redux" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import {Pool} from "src/app/core/pools/pool" import Loads from "src/js/state/Loads" import {Item} from "../item" import {NodeRendererProps} from "react-arborist" import {poolContextMenu} from "src/app/menus/pool-context-menu" -import {updateFrom} from "src/app/commands/pins" import {useAfterDelayOf} from "src/app/core/hooks/use-after-delay-of" import Config from "src/js/state/Config" import {PoolName} from "./pool-name" import {State} from "src/js/state/types" +import {showMenu} from "src/core/menu" +import {setFromPin} from "src/domain/session/handlers" const PoolItem = ({node, tree, style, dragHandle}: NodeRendererProps) => { const pool = node.data @@ -30,7 +31,7 @@ const PoolItem = ({node, tree, style, dragHandle}: NodeRendererProps) => { icon={node.isInternal ? : } state={node.state} innerStyle={style} - onContextMenu={() => poolContextMenu.build(tree, node).show()} + onContextMenu={() => showMenu(poolContextMenu(tree, node))} onSubmit={(name: string) => node.submit(name)} onReset={() => node.reset()} onToggle={() => node.toggle()} @@ -38,7 +39,7 @@ const PoolItem = ({node, tree, style, dragHandle}: NodeRendererProps) => { onClick={(e) => { if (e.altKey) { e.stopPropagation() - updateFrom.run(node.data.name) + setFromPin(node.data.name) } else { afterDelayOf(480, () => { node.isOnlySelection && node.edit() diff --git a/apps/zui/src/app/features/sidebar/pools-section/pools-tree.tsx b/apps/zui/src/app/features/sidebar/pools-section/pools-tree.tsx index 455fcbffef..65ed33f9ed 100644 --- a/apps/zui/src/app/features/sidebar/pools-section/pools-tree.tsx +++ b/apps/zui/src/app/features/sidebar/pools-section/pools-tree.tsx @@ -17,6 +17,7 @@ import Config from "src/js/state/Config" import {Pool} from "src/app/core/pools/pool" import {PoolName} from "./pool-name" import Appearance from "src/js/state/Appearance" +import {TREE_ITEM_HEIGHT} from "../item" export function PoolsTree(props: {searchTerm: string}) { const dispatch = useDispatch() @@ -51,7 +52,7 @@ export function PoolsTree(props: {searchTerm: string}) { disableDrag disableDrop indent={16} - rowHeight={28} + rowHeight={TREE_ITEM_HEIGHT} padding={8} height={dimens.height} width={dimens.width} diff --git a/apps/zui/src/app/features/sidebar/queries-section/empty.tsx b/apps/zui/src/app/features/sidebar/queries-section/empty.tsx index cc87bb115f..a9f8485dec 100644 --- a/apps/zui/src/app/features/sidebar/queries-section/empty.tsx +++ b/apps/zui/src/app/features/sidebar/queries-section/empty.tsx @@ -1,5 +1,5 @@ import React from "react" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import EmptySection from "src/js/components/common/EmptySection" import styled from "styled-components" diff --git a/apps/zui/src/app/features/sidebar/queries-section/index.tsx b/apps/zui/src/app/features/sidebar/queries-section/index.tsx index 5f8efcd9b9..f8fc789b34 100644 --- a/apps/zui/src/app/features/sidebar/queries-section/index.tsx +++ b/apps/zui/src/app/features/sidebar/queries-section/index.tsx @@ -1,11 +1,11 @@ import React, {useState} from "react" import {useDispatch, useSelector} from "react-redux" -import {SwitchButton} from "src/app/core/components/switch-button" import Appearance from "src/js/state/Appearance" import {Content} from "../content" import {SearchBar} from "../search-bar" import {Toolbar} from "../toolbar" import {QueriesTree} from "./queries-tree" +import {ToolbarTabs} from "src/components/toolbar-tabs" export function QueriesSection() { const dispatch = useDispatch() @@ -18,17 +18,17 @@ export function QueriesSection() { - dispatch(Appearance.setQueriesView("local")), - active: "local" === view, + checked: "local" === view, }, { label: "Remote", click: () => dispatch(Appearance.setQueriesView("remote")), - active: "remote" === view, + checked: "remote" === view, }, ]} /> diff --git a/apps/zui/src/app/features/sidebar/queries-section/queries-tree.tsx b/apps/zui/src/app/features/sidebar/queries-section/queries-tree.tsx index 3c3611c384..dacfb5aaf7 100644 --- a/apps/zui/src/app/features/sidebar/queries-section/queries-tree.tsx +++ b/apps/zui/src/app/features/sidebar/queries-section/queries-tree.tsx @@ -16,6 +16,9 @@ import {FillFlexParent} from "src/components/fill-flex-parent" import QueryItem from "./query-item" import {selectQuery} from "src/app/events/select-query-event" import Appearance from "src/js/state/Appearance" +import {Empty} from "./empty" +import {TREE_ITEM_HEIGHT} from "../item" +import {showMenu} from "src/core/menu" type Props = { source: "local" | "remote" @@ -35,8 +38,11 @@ export function QueriesTree(props: Props) { function LocalQueriesTree({searchTerm}: Props) { const queries = useSelector(Queries.raw).items - - return + if (queries.length) { + return + } else { + return + } } function RemoteQueriesTree({searchTerm}) { @@ -45,7 +51,11 @@ function RemoteQueriesTree({searchTerm}) { useEffect(() => { dispatch(refreshRemoteQueries()) }, []) - return + if (queries.length) { + return + } else { + return + } } function QueryTree(props: { @@ -59,7 +69,7 @@ function QueryTree(props: { const tree = useRef>() const [{isOver}, drop] = useQueryImportOnDrop() const initialOpenState = useSelector(Appearance.getQueriesOpenState) - selectQuery.useListener((id) => tree.current.select(id)) + selectQuery.useListener((id) => tree.current?.select(id)) return ( <> @@ -85,7 +95,7 @@ function QueryTree(props: { node.data.name.toLowerCase().includes(term.toLowerCase()) } indent={16} - rowHeight={28} + rowHeight={TREE_ITEM_HEIGHT} data={props.queries} childrenAccessor="items" onActivate={(node) => { @@ -118,7 +128,7 @@ function QueryTree(props: { }} onContextMenu={() => { if (tree.current) { - queryTreeContextMenu.build(tree.current).show() + showMenu(queryTreeContextMenu(tree.current)) } }} > diff --git a/apps/zui/src/app/features/sidebar/queries-section/query-item.tsx b/apps/zui/src/app/features/sidebar/queries-section/query-item.tsx index 59ee043dd4..a76b3a6e90 100644 --- a/apps/zui/src/app/features/sidebar/queries-section/query-item.tsx +++ b/apps/zui/src/app/features/sidebar/queries-section/query-item.tsx @@ -1,11 +1,12 @@ import React from "react" import styled from "styled-components" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import {Item} from "../item" import {NodeRendererProps} from "react-arborist" import {Query} from "src/js/state/Queries/types" import {queryContextMenu} from "src/app/menus/query-context-menu" import {useAfterDelayOf} from "src/app/core/hooks/use-after-delay-of" +import {showMenu} from "src/core/menu" const FolderIcon = styled(Icon).attrs({name: "folder"})`` const QueryIcon = styled(Icon).attrs({name: "query"})`` @@ -30,7 +31,7 @@ const QueryItem = ({ onToggle={() => node.toggle()} onContextMenu={(e) => { e.stopPropagation() - queryContextMenu.build(tree, node).show() + showMenu(queryContextMenu(tree, node)) }} onSubmit={(name) => node.submit(name)} onReset={() => node.reset()} diff --git a/apps/zui/src/app/features/sidebar/search-bar.tsx b/apps/zui/src/app/features/sidebar/search-bar.tsx index 3d2b948a14..f310995f2a 100644 --- a/apps/zui/src/app/features/sidebar/search-bar.tsx +++ b/apps/zui/src/app/features/sidebar/search-bar.tsx @@ -1,5 +1,5 @@ import React from "react" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import styled from "styled-components" const BG = styled.div` @@ -7,9 +7,9 @@ const BG = styled.div` align-items: center; border: none; border-radius: 5px; - border: 1px solid var(--border-color); - padding: 2px 12px; + padding: 5px 12px; width: 100%; + background: var(--emphasis-bg); svg { width: 16px; @@ -25,7 +25,7 @@ const BG = styled.div` const Input = styled.input` &::placeholder { - color: var(--foreground-color); + color: var(--fg-color); opacity: 0.4; } height: 22px; diff --git a/apps/zui/src/app/features/sidebar/sidebar-toggle-button.tsx b/apps/zui/src/app/features/sidebar/sidebar-toggle-button.tsx index 84db366494..56c0ff3ff3 100644 --- a/apps/zui/src/app/features/sidebar/sidebar-toggle-button.tsx +++ b/apps/zui/src/app/features/sidebar/sidebar-toggle-button.tsx @@ -2,12 +2,15 @@ import React from "react" import {useDispatch} from "src/app/core/state" import Appearance from "src/js/state/Appearance" import {IconButton} from "src/components/icon-button" +import {useSelector} from "react-redux" export const SidebarToggleButton = () => { const dispatch = useDispatch() + const open = useSelector(Appearance.sidebarIsOpen) + const name = open ? "layout_leftbar_close" : "layout_leftbar_open" return ( { export const RightSidebarToggleButton = () => { const dispatch = useDispatch() + const open = useSelector(Appearance.secondarySidebarIsOpen) + const name = open ? "layout_rightbar_close" : "layout_rightbar_open" return ( { - return [ - { - label: "Hide Column", - iconName: "show", - click: () => column.hide(), - visible: column.isVisible, - }, - { - label: "Show Column", - iconName: "hide", - click: () => column.show(), - visible: !column.isVisible, - }, - ] - } -) +export const columnListItemMenu = createMenu((ctx, column: TableColumn) => { + return [ + { + label: "Hide Column", + iconName: "show", + click: () => hideColumn(column.id), + visible: column.isVisible, + }, + { + label: "Show Column", + iconName: "hide", + click: () => showColumn(column.id), + visible: !column.isVisible, + }, + ] +}) diff --git a/apps/zui/src/app/menus/columns-toolbar-menu.ts b/apps/zui/src/app/menus/columns-toolbar-menu.ts index 4e0d4b0497..8a8bd0b85c 100644 --- a/apps/zui/src/app/menus/columns-toolbar-menu.ts +++ b/apps/zui/src/app/menus/columns-toolbar-menu.ts @@ -1,20 +1,17 @@ import {createMenu, MenuItem} from "src/core/menu" -import {TableViewApi} from "src/zui-kit/core/table-view/table-view-api" +import {hideAllColumns, showAllColumns} from "src/domain/results/handlers" -export const columnsToolbarMenu = createMenu( - "columnsToolbarMenu", - (ctx, table: TableViewApi) => { - return [ - { - label: "Show All", - iconName: "show", - click: () => table.showAllColumns(), - }, - { - label: "Hide All", - iconName: "hide", - click: () => table.hideAllColumns(), - }, - ] as MenuItem[] - } -) +export const columnsToolbarMenu = createMenu(() => { + return [ + { + label: "Show All", + iconName: "show", + click: () => showAllColumns(), + }, + { + label: "Hide All", + iconName: "hide", + click: () => hideAllColumns(), + }, + ] as MenuItem[] +}) diff --git a/apps/zui/src/app/menus/header-context-menu.ts b/apps/zui/src/app/menus/header-context-menu.ts index cc4b1c57ed..5252e05393 100644 --- a/apps/zui/src/app/menus/header-context-menu.ts +++ b/apps/zui/src/app/menus/header-context-menu.ts @@ -5,8 +5,8 @@ import { appendQueryCountBy, appendQuerySortBy, } from "src/js/flows/searchBar/actions" -import submitSearch from "../query-home/flows/submit-search" import {createMenu} from "src/core/menu" +import {submitSearch} from "src/domain/session/handlers" function getWhenContext(api: ZuiApi, column: ZedColumn) { const query = api.current.query @@ -21,25 +21,24 @@ function getWhenContext(api: ZuiApi, column: ZedColumn) { } export const headerContextMenu = createMenu( - "headerContextMenu", (ctx, api: TableViewApi, column: ZedColumn) => { const when = getWhenContext(ctx.api, column) const dispatch = ctx.api.dispatch return [ { - label: "Sort Ascending", + label: "Sort Asc", enabled: !when.isSortedAsc, click: () => { dispatch(appendQuerySortBy(column.path, "asc")) - dispatch(submitSearch()) + submitSearch() }, }, { - label: "Sort Descending", + label: "Sort Desc", enabled: !when.isSortedDesc, click: () => { dispatch(appendQuerySortBy(column.path, "desc")) - dispatch(submitSearch()) + submitSearch() }, }, { @@ -50,7 +49,7 @@ export const headerContextMenu = createMenu( enabled: !when.isSummarized, click: () => { dispatch(appendQueryCountBy(column.path)) - dispatch(submitSearch()) + submitSearch() }, }, { diff --git a/apps/zui/src/app/menus/new-pin-menu.ts b/apps/zui/src/app/menus/new-pin-menu.ts deleted file mode 100644 index b469c60065..0000000000 --- a/apps/zui/src/app/menus/new-pin-menu.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {createMenu} from "src/core/menu" -import * as pins from "src/app/commands/pins" - -export const newPinMenu = createMenu("newPinMenu", ({api}) => { - return [ - { - label: "New 'From' Pin", - command: pins.createFrom.bind(), - }, - {label: "New 'Time Range' Pin", command: pins.createTimeRange.bind()}, - { - label: "New Zed Snippet Pin", - command: pins.createGeneric.bind(), - }, - {type: "separator"}, - { - label: "Pin Editor Value", - enabled: !!api.editor.value.trim(), - command: pins.createFromEditor.bind(), - }, - ] -}) diff --git a/apps/zui/src/app/menus/open-query-menu.ts b/apps/zui/src/app/menus/open-query-menu.ts index 91ccee5c20..3cd2f0ab79 100644 --- a/apps/zui/src/app/menus/open-query-menu.ts +++ b/apps/zui/src/app/menus/open-query-menu.ts @@ -2,7 +2,7 @@ import {MenuItemConstructorOptions} from "electron" import {Item} from "src/js/state/Queries/types" import {createMenu} from "src/core/menu" -export const openQueryMenu = createMenu("openQueryMenu", ({api}) => { +export const openQueryMenu = createMenu(({api}) => { function createMenuItems(items: Item[]) { return items.map((query) => { if ("items" in query) { diff --git a/apps/zui/src/app/menus/pool-context-menu.ts b/apps/zui/src/app/menus/pool-context-menu.ts index 8e580f581d..eb0a6bebd5 100644 --- a/apps/zui/src/app/menus/pool-context-menu.ts +++ b/apps/zui/src/app/menus/pool-context-menu.ts @@ -1,17 +1,16 @@ import {NodeApi, TreeApi} from "react-arborist" -import {updateFrom} from "../commands/pins" import {Pool} from "../core/pools/pool" import {createMenu} from "src/core/menu" +import {setFromPin} from "src/domain/session/handlers" export const poolContextMenu = createMenu( - "poolContextMenu", (_, tree: TreeApi, node: NodeApi) => { const ids = tree.selectedIds const multi = ids.has(node.id) && ids.size > 1 return [ { label: "Use as From Pin", - command: updateFrom.bind(node.data.name), + click: () => setFromPin(node.data.name), }, {type: "separator"}, { diff --git a/apps/zui/src/app/menus/pool-toolbar-menu.ts b/apps/zui/src/app/menus/pool-toolbar-menu.ts index 930be285a5..18c5bc6a33 100644 --- a/apps/zui/src/app/menus/pool-toolbar-menu.ts +++ b/apps/zui/src/app/menus/pool-toolbar-menu.ts @@ -2,31 +2,28 @@ import {Pool} from "../core/pools/pool" import {createMenu} from "src/core/menu" import {chooseFiles} from "src/domain/loads/handlers" -export const poolToolbarMenu = createMenu( - "poolToolbarMenu", - ({api}, pool: Pool) => { - return [ - { - display: "icon-label", - label: "Load Data", - iconName: "doc-plain", - click: async () => { - chooseFiles(pool.id) - }, - title: "Load data into this pool.", +export const poolToolbarMenu = createMenu(({api}, pool: Pool) => { + return [ + { + display: "icon-label", + label: "Load Data", + iconName: "file_upload", + click: async () => { + chooseFiles(pool.id) }, - { - display: "icon-label", - label: "Query Pool", - iconName: "query", - click: () => { - api.queries.open({ - pins: [{type: "from", value: pool.name}], - value: "", - }) - }, - title: "Open a new session query with this pool as the from clause.", + title: "Load data into this pool.", + }, + { + display: "icon-label", + label: "Query Pool", + iconName: "query", + click: () => { + api.queries.open({ + pins: [{type: "from", value: pool.name}], + value: "", + }) }, - ] - } -) + title: "Open a new session query with this pool as the from clause.", + }, + ] +}) diff --git a/apps/zui/src/app/menus/query-context-menu.ts b/apps/zui/src/app/menus/query-context-menu.ts index d855305cf2..c699dae0a4 100644 --- a/apps/zui/src/app/menus/query-context-menu.ts +++ b/apps/zui/src/app/menus/query-context-menu.ts @@ -7,7 +7,6 @@ import {openQuery} from "../commands/open-query" import {createMenu} from "src/core/menu" export const queryContextMenu = createMenu( - "queryContextMenu", (_, tree: TreeApi, node: NodeApi) => { const ids = tree.selectedIds const multi = ids.has(node.id) && ids.size > 1 @@ -33,18 +32,18 @@ export const queryContextMenu = createMenu( { label: "Open Query", visible: node.isLeaf, - command: openQuery.bind(node.id), + click: () => openQuery.run(node.id), }, {type: "separator"}, { label: "Export Query Group...", - command: exportQueryGroup.bind(node as NodeApi), + click: () => exportQueryGroup.run(node as NodeApi), visible: node.isInternal, }, { label: "Copy Query Value", visible: node.isLeaf, - command: copyQueryToClipboard.bind(node.data.id), + click: () => copyQueryToClipboard.run(node.data.id), }, {type: "separator"}, { @@ -55,7 +54,7 @@ export const queryContextMenu = createMenu( { label: "Delete", accelerator: "Backspace", - command: deleteQueries.bind(multi ? Array.from(ids) : [node.id]), + click: () => deleteQueries.run(multi ? Array.from(ids) : [node.id]), }, ] } diff --git a/apps/zui/src/app/menus/query-tree-context-menu.ts b/apps/zui/src/app/menus/query-tree-context-menu.ts index bc2c64938c..e2b7728912 100644 --- a/apps/zui/src/app/menus/query-tree-context-menu.ts +++ b/apps/zui/src/app/menus/query-tree-context-menu.ts @@ -3,7 +3,6 @@ import {Group, Query} from "src/js/state/Queries/types" import {createMenu} from "src/core/menu" export const queryTreeContextMenu = createMenu( - "queryTreeContextMenu", (_, tree: TreeApi) => { return [ { diff --git a/apps/zui/src/app/menus/saved-query-menu.ts b/apps/zui/src/app/menus/saved-query-menu.ts index f763c17084..d19b04d965 100644 --- a/apps/zui/src/app/menus/saved-query-menu.ts +++ b/apps/zui/src/app/menus/saved-query-menu.ts @@ -3,69 +3,66 @@ import {ActiveQuery} from "../core/models/active-query" import {createMenu} from "src/core/menu" import {openQueryMenu} from "./open-query-menu" -export const savedQueryMenu = createMenu( - "savedQueryMenu", - (_, active: ActiveQuery) => { - const query = active.query - return [ - { - label: "Go to Latest Version", - command: queries.openLatestVersion.bind(), - visible: active.isOutdated(), - }, - {label: "Switch Query", nestedMenu: openQueryMenu}, - {type: "separator"}, - { - label: "Duplicate", - command: queries.duplicate.bind(), - enabled: !query.isReadOnly, - }, - { - label: "Move To Remote", - command: queries.moveToSource.bind("remote"), - enabled: !query.isReadOnly, - visible: query.isLocal, - }, - { - label: "Move To Local", - command: queries.moveToSource.bind("local"), - enabled: !query.isReadOnly, - visible: query.isRemote, - }, - { - label: "Copy To Remote", - command: queries.copyToSource.bind("remote"), - enabled: !query.isReadOnly, - visible: query.isLocal, - }, - { - label: "Copy To Local", - command: queries.copyToSource.bind("local"), - enabled: !query.isReadOnly, - visible: query.isRemote, - }, - { - label: "Lock Query", - command: queries.lock.bind(), - visible: !query.isReadOnly, - }, +export const savedQueryMenu = createMenu((_, active: ActiveQuery) => { + const query = active.query + return [ + { + label: "Go to Latest Version", + click: () => queries.openLatestVersion.run(), + visible: active.isOutdated(), + }, + {label: "Switch Query", nestedMenu: openQueryMenu()}, + {type: "separator"}, + { + label: "Duplicate", + click: () => queries.duplicate.run(), + enabled: !query.isReadOnly, + }, + { + label: "Move To Remote", + click: () => queries.moveToSource.run("remote"), + enabled: !query.isReadOnly, + visible: query.isLocal, + }, + { + label: "Move To Local", + click: () => queries.moveToSource.run("local"), + enabled: !query.isReadOnly, + visible: query.isRemote, + }, + { + label: "Copy To Remote", + click: () => queries.copyToSource.run("remote"), + enabled: !query.isReadOnly, + visible: query.isLocal, + }, + { + label: "Copy To Local", + click: () => queries.copyToSource.run("local"), + enabled: !query.isReadOnly, + visible: query.isRemote, + }, + { + label: "Lock Query", + click: () => queries.lock.run(), + visible: !query.isReadOnly, + }, - {type: "separator"}, - { - label: "Unlock Query", - command: queries.unlock.bind(), - visible: query.isReadOnly, - }, - { - label: "Rename...", - command: queries.rename.bind(), - enabled: !query.isReadOnly, - }, - { - label: "Delete", - command: queries.deleteCmd.bind(), - enabled: !query.isReadOnly, - }, - ] - } -) + {type: "separator"}, + { + label: "Unlock Query", + click: () => queries.unlock.run(), + visible: query.isReadOnly, + }, + { + label: "Rename...", + click: () => queries.rename.run(), + enabled: !query.isReadOnly, + }, + { + label: "Delete", + click: () => queries.deleteCmd.run(), + enabled: !query.isReadOnly, + }, + ] +}) diff --git a/apps/zui/src/app/menus/value-context-menu.ts b/apps/zui/src/app/menus/value-context-menu.ts index 79ccb94584..e1cdb50e80 100644 --- a/apps/zui/src/app/menus/value-context-menu.ts +++ b/apps/zui/src/app/menus/value-context-menu.ts @@ -1,9 +1,6 @@ import * as zed from "@brimdata/zed-js" import {createMenu} from "src/core/menu" import ZuiApi from "src/js/api/zui-api" -import * as editor from "../commands/editor" -import * as pins from "../commands/pins" -import * as values from "../commands/values" function getWhenContext(api: ZuiApi, value: zed.Any) { return { @@ -16,7 +13,6 @@ function getWhenContext(api: ZuiApi, value: zed.Any) { } export const valueContextMenu = createMenu( - "valueContextMenu", ({api}, value: zed.Any, field: zed.Field | null, rootValue: zed.Value) => { const when = getWhenContext(api, value) @@ -24,77 +20,77 @@ export const valueContextMenu = createMenu( { label: "Filter == Value", visible: when.isPrimitive, - command: editor.filterEqualsValue.bind(field), + command: "editor.filterEqualsValue", }, { label: "Filter != Value", visible: when.isPrimitive, - command: editor.filterNotEqualsValue.bind(field), + command: "editor.filterNotEqualsValue", }, { label: "Filter In Field", visible: when.isIterable, - command: editor.filterInField.bind(field, value), + command: "editor.filterInField", }, { label: "Filter Not In Field", visible: when.isIterable, - command: editor.filterNotInField.bind(field, value), + command: "editor.filterNotInField", }, { label: "New Search With Value", - command: editor.newSearchWithValue.bind(field), + command: "editor.newSearchWithValue", }, {type: "separator"}, { label: "Pivot to Values", - command: editor.pivotToValues.bind(field), + command: "editor.pivotToValues", enabled: when.isGroupBy, }, { label: "Count By Field", - command: editor.countByField.bind(field), + command: "editor.countByField", enabled: !when.isGroupBy, }, {type: "separator"}, { label: "Copy", - command: editor.copyValueToClipboard.bind(value), + command: "editor.copyValueToClipboard", }, { label: "Copy Full Value", - command: editor.copyValueToClipboard.bind(value), + command: "editor.copyValueToClipboard", visible: value !== rootValue, }, {type: "separator"}, { label: "Sort Asc", - command: editor.sortAsc.bind(field.path), + command: "editor.sortAsc", }, - {label: "Sort Desc", command: editor.sortDesc.bind(field.path)}, + {label: "Sort Desc", command: "editor.sortDesc"}, {type: "separator"}, { label: "Set Time Range From", - command: pins.setTimeRangeFrom.bind(value), + command: "session.setTimeRangeFrom", }, { label: "Set Time Range To", - command: pins.setTimeRangeTo.bind(value), + command: "session.setTimeRangeTo", }, {type: "separator"}, { label: "Show In Detail Pane", - command: values.showValueDetails.bind(rootValue), + command: "session.showValueDetails", }, {type: "separator"}, { label: "Whois Lookup", - command: values.showWhoIs.bind(value), + command: "session.showWhoIs", enabled: when.isIp, }, { label: "Virus Total", - command: values.openVirusTotal.bind(value), + command: "session.openVirusTotal", }, ] } diff --git a/apps/zui/src/app/query-home/editor-resizer.tsx b/apps/zui/src/app/query-home/editor-resizer.tsx deleted file mode 100644 index e7da168b70..0000000000 --- a/apps/zui/src/app/query-home/editor-resizer.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import DragAnchor from "src/components/drag-anchor" -import {useDispatch} from "../core/state" -import Layout from "src/js/state/Layout" -import {useRef} from "react" -import useSelect from "../core/hooks/use-select" - -export function EditorResizer() { - const dispatch = useDispatch() - const select = useSelect() - const start = useRef(0) - - const onStart = () => { - start.current = select(Layout.getEditorHeight) - } - - const onDrag = (e, {dy}) => { - dispatch(Layout.setEditorHeight(start.current + dy)) - } - - return -} diff --git a/apps/zui/src/app/query-home/flows/new-tab.ts b/apps/zui/src/app/query-home/flows/new-tab.ts deleted file mode 100644 index e140993f76..0000000000 --- a/apps/zui/src/app/query-home/flows/new-tab.ts +++ /dev/null @@ -1,6 +0,0 @@ -import Tabs from "src/js/state/Tabs" -import {Thunk} from "src/js/state/types" - -export const newTab = (): Thunk => (dispatch) => { - dispatch(Tabs.createQuerySession()) -} diff --git a/apps/zui/src/app/query-home/flows/submit-search.ts b/apps/zui/src/app/query-home/flows/submit-search.ts deleted file mode 100644 index a23f0fa2ed..0000000000 --- a/apps/zui/src/app/query-home/flows/submit-search.ts +++ /dev/null @@ -1,41 +0,0 @@ -import Current from "src/js/state/Current" -import Editor from "src/js/state/Editor" -import Results from "src/js/state/Results" -import QueryVersions from "../../../js/state/QueryVersions" -import {Thunk} from "src/js/state/types" -import {QueryModel} from "../../../js/models/query-model" -import {RESULTS_QUERY} from "src/views/results-pane/run-results-query" -import Table from "src/js/state/Table" -import Inspector from "src/js/state/Inspector" - -const submitSearch = - (): Thunk => - (dispatch, getState, {api}) => { - dispatch(Table.setScrollPosition({top: 0, left: 0})) - dispatch(Inspector.setScrollPosition({top: 0, left: 0})) - - const nextVersion = Editor.getSnapshot(getState()) - const active = Current.getActiveQuery(getState()) - const error = QueryModel.checkSyntax(nextVersion) - - // An error with the syntax - if (error) { - const tabId = Current.getTabId(getState()) - dispatch(Results.error({id: RESULTS_QUERY, error, tabId})) - return - } - - // Reuse the version url if the next version is the same as the latest - // of this query, either session or saved. - if (QueryVersions.areEqual(active.version, nextVersion)) { - api.queries.open(active.id(), {version: active.versionId()}) - return - } - - // This is a new query, add a new version to the session, - // And open the current active query with the version set to the new one. - api.queries.addVersion(active.session.id, nextVersion) - api.queries.open(active.id(), {version: nextVersion.version}) - } - -export default submitSearch diff --git a/apps/zui/src/app/query-home/index.tsx b/apps/zui/src/app/query-home/index.tsx deleted file mode 100644 index d297349190..0000000000 --- a/apps/zui/src/app/query-home/index.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React, {useCallback, useContext, useState} from "react" -import {useSelector} from "react-redux" -import Current from "src/js/state/Current" - -import styled from "styled-components" -import {queryPath} from "../router/utils/paths" -import SearchArea from "./search-area" -import RightPane from "../features/right-pane" -import {TitleBar} from "./title-bar/title-bar" -import {ResultsToolbar} from "./toolbar/results-toolbar" -import {Redirect} from "react-router" -import {ActiveQuery} from "../core/models/active-query" -import {ResultsPane} from "src/views/results-pane" -import {TableViewApi} from "src/zui-kit/core/table-view/table-view-api" -import {HistogramPane} from "src/views/histogram-pane" - -const MainContent = styled.div` - display: flex; - flex-direction: column; - flex: 1; - height: 100%; - min-width: 320px; - background: white; -` - -const ContentWrap = styled.div` - display: flex; - width: 100%; - height: 100%; - min-height: 0; - min-width: 0; -` - -const ResultsContext = React.createContext<{ - table: TableViewApi | null - setTable: (v: TableViewApi | null) => void - query: ActiveQuery -}>(null) - -export function useResultsContext() { - const value = useContext(ResultsContext) - if (!value) throw new Error("Provide MainTableContext") - return value -} - -function ResultsProvider({children}) { - const [table, setTable] = useState(null) - const query = useSelector(Current.getActiveQuery) - const value = { - query, - table, - setTable: useCallback((table: TableViewApi | null) => setTable(table), []), - } - return ( - {children} - ) -} - -const QueryHome = () => { - const activeQuery = useSelector(Current.getActiveQuery) - const tabId = useSelector(Current.getTabId) - - if (activeQuery.isDeleted()) { - return - } - - return ( - - - - - - - - - - - - - ) -} - -export default QueryHome diff --git a/apps/zui/src/app/query-home/query-home.module.css b/apps/zui/src/app/query-home/query-home.module.css deleted file mode 100644 index c665c15597..0000000000 --- a/apps/zui/src/app/query-home/query-home.module.css +++ /dev/null @@ -1,31 +0,0 @@ -.borderResizeHandle { - width: 100%; - height: 11px; - position: relative; -} - -.borderResizeHandle:after { - content: ""; - position: absolute; - background: var(--border-color); - top: 5px; - left: 0; - right: 0; - height: 1px; -} - -.invisibleResizeHandle { - width: 100%; - height: 11px; - position: relative; - transform: translateY(5px); -} - -.resultsToolbar { - border-top: 1px solid var(--border-color); -} - -.panel { - display: flex; - flex-direction: column; -} diff --git a/apps/zui/src/app/query-home/results/data-hook.ts b/apps/zui/src/app/query-home/results/data-hook.ts deleted file mode 100644 index 16febd1aef..0000000000 --- a/apps/zui/src/app/query-home/results/data-hook.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {useDeferredValue} from "react" -import {useSelector} from "react-redux" -import Results from "src/js/state/Results" -import {RESULTS_QUERY} from "src/views/results-pane/run-results-query" - -export function useResultsData() { - const values = useSelector(Results.getValues(RESULTS_QUERY)) - const shapes = useSelector(Results.getShapes(RESULTS_QUERY)) - - return { - values: useDeferredValue(values), - shapes: useDeferredValue(shapes), - } -} diff --git a/apps/zui/src/app/query-home/results/results.styled.tsx b/apps/zui/src/app/query-home/results/results.styled.tsx deleted file mode 100644 index de04f44db1..0000000000 --- a/apps/zui/src/app/query-home/results/results.styled.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import React, {ComponentProps} from "react" -import styled from "styled-components" - -export const BG = styled.div` - display: flex; - flex-direction: column; - border: none; - position: relative; - flex: 1; -` - -export const Toolbar = styled.header` - background: white; - display: flex; - align-items: center; - justify-content: center; -` -export const Body = styled.div` - flex: 1; - overflow: hidden; -` - -export const Button = styled.button` - ${(p) => p.theme.typography.labelNormal} - border: none; - display: flex; - align-items: center; - justify-content: center; - padding: 0 6px; - border-radius: 5px; - - span { - opacity: 0.5; - border-top: 2px solid transparent; - border-bottom: 2px solid transparent; - min-width: 60px; - font-size: 11px; - text-transform: uppercase; - font-weight: 500; - padding: 0 6px; - } - - &:hover { - span { - opacity: 0.7; - transition: opacity 0.2s; - } - } - - &:active { - span { - opacity: 0.8; - } - } - - &[aria-pressed="true"] { - span { - opacity: 1; - border-bottom-color: var(--havelock); - } - } -` - -export const ButtonSwitch = styled.nav` - border-radius: 6px; - background: var(--button-background); - display: flex; - margin: 0; - height: 22px; - // z-index sits just above the drag anchor - z-index: 100; - margin-top: -11px; - margin-bottom: 10px; -` - -export const Group = styled.div` - display: flex; -` - -export const TableButton = (props: ComponentProps) => ( - -) - -export const ObjectsButton = (props: ComponentProps) => ( - -) diff --git a/apps/zui/src/app/query-home/search-area/index.tsx b/apps/zui/src/app/query-home/search-area/index.tsx deleted file mode 100644 index 60bd28d68b..0000000000 --- a/apps/zui/src/app/query-home/search-area/index.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from "react" -import styled from "styled-components" - -import {useSelector} from "react-redux" -import {Pins} from "./pins/pins" -import Editor from "src/js/state/Editor" -import Layout from "src/js/state/Layout" -import {EditorResizer} from "../editor-resizer" -import {ZedEditor} from "./zed-editor" -import {useDispatch} from "src/app/core/state" -import {cmdOrCtrl} from "src/app/core/utils/keyboard" -import submitSearch from "../flows/submit-search" -import Config from "src/js/state/Config" -import {useTabId} from "src/app/core/hooks/use-tab-id" - -const Group = styled.div` - display: flex; - flex-direction: column; - padding: 0; - position: relative; -` - -export default function SearchArea() { - const value = useSelector(Editor.getValue) - const height = useSelector(Layout.getEditorHeight) - const runOnEnter = useSelector(Config.getRunOnEnter) - const dispatch = useDispatch() - const tabId = useTabId() - const onChange = (v: string) => { - dispatch(Editor.setValue(v)) - } - - const onKey = (e: React.KeyboardEvent) => { - const isEnterKey = e.key === "Enter" - const isModKey = e.shiftKey || cmdOrCtrl(e) - if (isEnterKey) { - if ((runOnEnter && !isModKey) || (!runOnEnter && isModKey)) { - e.preventDefault() - dispatch(submitSearch()) - } - } - } - - return ( - <> - - - - - - - ) -} diff --git a/apps/zui/src/app/query-home/search-area/pins/base-pin.tsx b/apps/zui/src/app/query-home/search-area/pins/base-pin.tsx deleted file mode 100644 index d38e4df780..0000000000 --- a/apps/zui/src/app/query-home/search-area/pins/base-pin.tsx +++ /dev/null @@ -1,207 +0,0 @@ -import React, {useEffect} from "react" -import {darken, transparentize} from "polished" -import {ReactNode} from "react" -import styled from "styled-components" -import Icon from "src/app/core/icon-temp" -import {Dialog, useDialog} from "./dialog" -import {useSelector} from "react-redux" -import {useDispatch} from "src/app/core/state" -import Editor from "src/js/state/Editor" -import pinContextMenu from "./pin-context-menu" -import classNames from "classnames" -import mergeRefs from "src/app/core/utils/merge-refs" -import usePinDnd from "./use-pin-dnd" -import useCallbackRef from "src/js/components/hooks/useCallbackRef" -import {QueryPin} from "src/js/state/Editor/types" -import buildPin from "src/js/state/Editor/models/build-pin" -import {isEqual} from "lodash" -import submitSearch from "../../flows/submit-search" -import {cssVar} from "src/js/lib/cssVar" - -const primary = cssVar("--primary-color") as string -const buttonColor = transparentize(0.8, primary) -const buttonHoverColor = transparentize(0.75, primary) -const buttonActiveColor = transparentize(0.7, primary) -const labelColor = darken(0.4, primary) -const prefixColor = darken(0.3, primary) - -export const Button = styled.button` - font-family: var(--mono-font); - position: relative; - margin-right: 4px; - margin-bottom: 4px; - max-width: 100%; - height: 20px; - white-space: nowrap; - line-height: 1; - display: flex; - align-items: center; - justify-content: flex-start; - color: ${labelColor}; - background: ${buttonColor}; - border: none; - border-radius: 8px; - box-shadow: 0; - border: 1px solid transparent; - - &:hover { - background: ${buttonHoverColor}; - } - &:active { - background: ${buttonActiveColor}; - } - - &.disabled { - text-decoration: line-through; - opacity: 0.5; - } -` - -export const Prefix = styled.span` - opacity: 0.5; - margin-right: 8px; - text-transform: uppercase; - font-size: 11px; - color: ${prefixColor}; - font-weight: bold; - flex-shrink: 0; -` - -const Label = styled.span` - overflow: hidden; - text-overflow: ellipsis; - line-height: 17px; -` - -const Dropdown = styled(Icon).attrs({name: "chevron-down"})` - flex: 0 0 13px; - flex-basis: 13px; - margin-left: 4px; - svg { - width: 13px; - height: 13px; - } -` - -const DropCursor = styled.div` - position: absolute; - left: -4px; - top: -4px; - width: 2px; - height: calc(100% + 8px); - border-radius: 1px; - background: var(--primary-color); -` - -const DropCursorRight = styled(DropCursor)` - left: initial; - right: -4px; -` - -function BaseForm(props: PinProps) { - const dispatch = useDispatch() - - function onSubmit(pin: QueryPin) { - if (isEqual(pin, props.pin)) return - dispatch(Editor.updatePin(pin)) - dispatch(submitSearch()) - } - - function onDelete() { - dispatch(Editor.deletePin(props.index)) - dispatch(submitSearch()) - } - - function onReset() { - dispatch(Editor.cancelPinEdit()) - } - - useDialog({onCancel: onReset, onClose: onReset}) - - return ( - - ) -} - -export type PinProps = { - index: number - label: ReactNode - pin: QueryPin - prefix?: string - showMenu?: () => void - form?: React.FC> -} - -export type PinFormProps = { - pin: Pin - onSubmit: (pin: Pin) => void - onReset: () => void - onDelete: () => void -} - -/** - * If you pass a form to this component, it will render it - * in a dialog when editing. If you pass a showMenu function - * to it, it will call it when editing. - */ -export const BasePin = React.forwardRef(function BasePin( - props: PinProps, - forwardedRef -) { - const [button, setButton] = useCallbackRef() - const dndRef = usePinDnd(props.index) - const pinCount = useSelector(Editor.getPinCount) - const hoverIndex = useSelector(Editor.getPinHoverIndex) - const lastPin = props.index + 1 === pinCount - const isHovering = hoverIndex === props.index - const isHoveringLastItem = lastPin && hoverIndex === pinCount - const dispatch = useDispatch() - const isEditing = useSelector(Editor.getPinEditIndex) === props.index - const onClick = () => dispatch(Editor.editPin(props.index)) - const onContextMenu = () => dispatch(pinContextMenu(props.index)) - const className = classNames({disabled: props.pin.disabled}) - - useEffect(() => { - if (props.showMenu && isEditing) props.showMenu() - }, [isEditing, props.showMenu]) - - return ( - <> - - {props.form && ( - - - - )} - - ) -}) diff --git a/apps/zui/src/app/query-home/search-area/pins/from-pin/from-pin.tsx b/apps/zui/src/app/query-home/search-area/pins/from-pin/from-pin.tsx deleted file mode 100644 index 542a64ddaf..0000000000 --- a/apps/zui/src/app/query-home/search-area/pins/from-pin/from-pin.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import {isString} from "lodash" -import React, {useRef} from "react" -import {useDispatch} from "src/app/core/state" -import submitSearch from "src/app/query-home/flows/submit-search" -import Editor from "src/js/state/Editor" -import {FromQueryPin} from "src/js/state/Editor/types" -import {BasePin} from "../base-pin" -import {showMenu} from "./show-menu" - -export default function FromPin(props: {pin: FromQueryPin; index: number}) { - const dispatch = useDispatch() - const ref = useRef() - return ( - { - if (!ref.current) return - dispatch(showMenu(ref.current)).then((value: string) => { - if (isString(value)) { - if (value !== props.pin.value) { - dispatch(Editor.updatePin({value})) - dispatch(submitSearch()) - } - } else dispatch(Editor.cancelPinEdit()) - }) - }} - /> - ) -} diff --git a/apps/zui/src/app/query-home/search-area/pins/from-pin/show-menu.ts b/apps/zui/src/app/query-home/search-area/pins/from-pin/show-menu.ts deleted file mode 100644 index 9f31680bd7..0000000000 --- a/apps/zui/src/app/query-home/search-area/pins/from-pin/show-menu.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {showContextMenu} from "src/js/lib/System" -import Current from "src/js/state/Current" -import Pools from "src/js/state/Pools" -import popupPosition from "../../popup-position" - -export const showMenu = (anchor: HTMLElement) => (dispatch, getState) => { - const s = getState() - const lakeId = Current.getLakeId(s) - const pools = Pools.getPools(lakeId)(s) - - let selected = null - const template = pools - ? pools - .sort((a, b) => (a.name > b.name ? 1 : -1)) - .map((p) => ({ - label: p.name, - click: () => { - selected = p.name - }, - })) - : [ - { - label: "No pools in lake", - enabled: false, - }, - ] - - return new Promise((resolve) => { - showContextMenu(template, { - callback: () => resolve(selected), - ...popupPosition(anchor), - }) - }) -} diff --git a/apps/zui/src/app/query-home/search-area/pins/generic-pin/generic-pin.tsx b/apps/zui/src/app/query-home/search-area/pins/generic-pin/generic-pin.tsx deleted file mode 100644 index 7df2dba699..0000000000 --- a/apps/zui/src/app/query-home/search-area/pins/generic-pin/generic-pin.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react" -import {GenericQueryPin} from "src/js/state/Editor/types" -import {BasePin} from "../base-pin" -import {Form} from "./form" - -export default function GenericPin(props: { - pin: GenericQueryPin - index: number -}) { - return ( - - ) -} diff --git a/apps/zui/src/app/query-home/search-area/pins/new-pin-button.tsx b/apps/zui/src/app/query-home/search-area/pins/new-pin-button.tsx deleted file mode 100644 index 44f197249b..0000000000 --- a/apps/zui/src/app/query-home/search-area/pins/new-pin-button.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react" -import Icon from "src/app/core/icon-temp" -import {newPinMenu} from "src/app/menus/new-pin-menu" -import styled from "styled-components" - -const Button = styled.button` - border-radius: 6px; - display: flex; - height: 20px; - width: 34px; - border: none; - margin: 0; - margin-bottom: 4px; - margin-right: 8px; - align-items: center; - justify-content: center; - background-color: transparent; - &:hover { - background-color: rgb(0 0 0 / 0.05); - } - &:active { - background-color: rgb(0 0 0 / 0.08); - } -` - -export function NewPinButton() { - return ( - - ) -} diff --git a/apps/zui/src/app/query-home/search-area/pins/pin-context-menu.ts b/apps/zui/src/app/query-home/search-area/pins/pin-context-menu.ts deleted file mode 100644 index 765823e493..0000000000 --- a/apps/zui/src/app/query-home/search-area/pins/pin-context-menu.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {MenuItemConstructorOptions} from "electron/main" -import {showContextMenu} from "src/js/lib/System" -import Editor from "src/js/state/Editor" -import submitSearch from "../../flows/submit-search" - -export default function pinContextMenu(index: number) { - return (dispatch, getState) => { - const pins = Editor.getPins(getState()) - const pin = pins[index] - - showContextMenu([ - { - label: "Edit", - click: () => dispatch(Editor.editPin(index)), - }, - {type: "separator"}, - { - label: "Disable", - enabled: !pin.disabled, - click: () => { - dispatch(Editor.disablePin(index)) - dispatch(submitSearch()) - }, - }, - { - label: "Disable Others", - enabled: pins.some((p) => !p.disabled), - click: () => { - dispatch(Editor.disableOtherPins(index)) - dispatch(submitSearch()) - }, - }, - {type: "separator"}, - { - label: "Enable", - enabled: !!pin.disabled, - click: () => { - dispatch(Editor.enablePin(index)) - dispatch(submitSearch()) - }, - }, - { - label: "Enable Others", - enabled: pins.some((p) => p.disabled), - click: () => { - dispatch(Editor.enableOtherPins(index)) - dispatch(submitSearch()) - }, - }, - {type: "separator"}, - { - label: "Delete", - click: () => { - dispatch(Editor.deletePin(index)) - dispatch(submitSearch()) - }, - }, - { - label: "Delete to the Right", - click: () => { - dispatch(Editor.deletePinsToTheRight(index)) - dispatch(submitSearch()) - }, - }, - { - label: "Delete All", - click: () => { - dispatch(Editor.deleteAllPins()) - dispatch(submitSearch()) - }, - }, - ] as MenuItemConstructorOptions[]) - } -} diff --git a/apps/zui/src/app/query-home/search-area/pins/pins.tsx b/apps/zui/src/app/query-home/search-area/pins/pins.tsx deleted file mode 100644 index 2f643e3979..0000000000 --- a/apps/zui/src/app/query-home/search-area/pins/pins.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from "react" -import styled from "styled-components" -import Editor from "src/js/state/Editor" -import {useSelector} from "react-redux" -import {QueryPin} from "src/js/state/Editor/types" -import FromPin from "./from-pin/from-pin" -import GenericPin from "./generic-pin/generic-pin" -import TimeRangePin from "./time-range-pin/time-range-pin" -import {NewPinButton} from "./new-pin-button" -import {compact, isEmpty} from "lodash" -import {PlaceholderFromPin} from "./placeholder-pin" - -const Container = styled.section` - display: flex; - padding: 12px 16px 4px 16px; - flex-wrap: wrap; - background: var(--editor-background); - align-items: center; - z-index: 1; -` - -function renderPin(pin: QueryPin, index: number) { - switch (pin.type) { - case "from": - return - case "generic": - return - case "time-range": - return - } -} - -export function Pins() { - const pins = useSelector(Editor.getPins) - return ( - - - {pins.map(renderPin)} - {isEmpty(compact(pins)) && } - - ) -} diff --git a/apps/zui/src/app/query-home/search-area/pins/placeholder-pin.tsx b/apps/zui/src/app/query-home/search-area/pins/placeholder-pin.tsx deleted file mode 100644 index 348d229108..0000000000 --- a/apps/zui/src/app/query-home/search-area/pins/placeholder-pin.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from "react" -import {createFrom} from "src/app/commands/pins" -import Icon from "src/app/core/icon-temp" -import styled from "styled-components" -import {Button, Prefix} from "./base-pin" - -export const Text = styled(Prefix)` - color: var(--placeholder-color); - opacity: 1; -` - -export const PlaceholderPin = styled(Button)` - --placeholder-color: var(--foreground-color); - - background: transparent; - border: 1px dashed var(--placeholder-color); - color: var(--placeholder-color); - opacity: 0.2; - &:hover { - background: transparent; - opacity: 0.5; - } -` - -export function PlaceholderFromPin() { - return ( - createFrom.run()}> - FROM - - - ) -} diff --git a/apps/zui/src/app/query-home/search-area/pins/time-range-pin/time-range-pin.tsx b/apps/zui/src/app/query-home/search-area/pins/time-range-pin/time-range-pin.tsx deleted file mode 100644 index a24dc1ec29..0000000000 --- a/apps/zui/src/app/query-home/search-area/pins/time-range-pin/time-range-pin.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from "react" -import {TimeRangeQueryPin} from "src/js/state/Editor/types" -import styled from "styled-components" -import {BasePin} from "../base-pin" -import Form from "./form" - -const Sep = styled.span` - padding: 0 10px; - opacity: 0.5; -` - -export default function TimeRangePin(props: { - pin: TimeRangeQueryPin - index: number -}) { - const label = ( - <> - {props.pin.from} - - {props.pin.to} - - ) - return ( - - ) -} diff --git a/apps/zui/src/app/query-home/search-area/popup-position.ts b/apps/zui/src/app/query-home/search-area/popup-position.ts deleted file mode 100644 index 979826e7a4..0000000000 --- a/apps/zui/src/app/query-home/search-area/popup-position.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default function popupPosition(anchor: HTMLElement) { - const {x, y, height} = anchor.getBoundingClientRect() - const pad = 10 - return {x: Math.round(x), y: Math.round(y + height + pad)} -} diff --git a/apps/zui/src/app/query-home/title-bar/button.tsx b/apps/zui/src/app/query-home/title-bar/button.tsx deleted file mode 100644 index e73e192d0c..0000000000 --- a/apps/zui/src/app/query-home/title-bar/button.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import classNames from "classnames" -import React, {ButtonHTMLAttributes} from "react" -import Icon, {IconName} from "src/app/core/icon-temp" -import styled from "styled-components" - -const Btn = styled.button` - background: var(--button-background); - border: none; - height: 24px; - min-width: 58px; - padding: 0 10px 0 10px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 6px; - gap: 6px; - white-space: nowrap; - - &:hover { - background: var(--button-background-hover); - } - &:active { - background: var(--button-background-active); - } - - &.primary { - background: var(--primary-color); - color: white; - svg { - fill: white; - } - &:hover { - background: var(--primary-color-dark); - } - &:active { - background: var(--primary-color-darker); - } - } - - &:disabled { - svg { - opacity: 0.3; - } - } -` - -const Text = styled.span` - font-size: 12px; - line-height: 12px; - font-weight: 500; -` - -type Props = { - children?: string - icon?: IconName - iconSize?: number - primary?: boolean -} & ButtonHTMLAttributes - -export function Button({ - icon, - iconSize, - primary, - children, - className, - ...rest -}: Props) { - return ( - - {icon && } - {children && {children}} - - ) -} diff --git a/apps/zui/src/app/query-home/title-bar/context.tsx b/apps/zui/src/app/query-home/title-bar/context.tsx deleted file mode 100644 index caf5217815..0000000000 --- a/apps/zui/src/app/query-home/title-bar/context.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React, {ReactNode, useContext} from "react" -import {ActiveQuery} from "src/app/core/models/active-query" - -const TitleBarContext = React.createContext(null) - -export function useActiveQuery() { - const ctx = useContext(TitleBarContext) - if (ctx === null) { - throw new Error("Need to provide title bar context a value") - } else { - return ctx - } -} - -type Props = { - activeQuery: ActiveQuery - children: ReactNode -} - -export function TitleBarProvider(props: Props) { - return ( - - {props.children} - - ) -} diff --git a/apps/zui/src/app/query-home/title-bar/detatch-button.tsx b/apps/zui/src/app/query-home/title-bar/detatch-button.tsx deleted file mode 100644 index 0108fcd55a..0000000000 --- a/apps/zui/src/app/query-home/title-bar/detatch-button.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react" -import styled from "styled-components" -import {useZuiApi} from "src/app/core/context" -import useSelect from "src/app/core/hooks/use-select" -import {IconButton} from "./icon-button" -import Editor from "src/js/state/Editor" - -const Detatch = styled(IconButton)` - height: 18px; - width: 18px; -` - -export function DetatchButton() { - const select = useSelect() - const api = useZuiApi() - - function onClick() { - const snapshot = select(Editor.getSnapshot) - api.queries.open(snapshot) - } - return -} diff --git a/apps/zui/src/app/query-home/title-bar/heading-button.tsx b/apps/zui/src/app/query-home/title-bar/heading-button.tsx deleted file mode 100644 index 71b8fbaf9b..0000000000 --- a/apps/zui/src/app/query-home/title-bar/heading-button.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import styled from "styled-components" - -export const HeadingButton = styled.button` - background: transparent; - border: none; - height: 22px; - display: flex; - gap: 4px; - align-items: center; - justify-content: center; - border-radius: 6px; - padding: 0 6px; - min-width: 0; - margin-left: 10px; - margin-right: 10px; - flex: 1; - - &:hover { - background: var(--button-background); - * { - opacity: 1; - } - } - &:active { - background: var(--button-background-active); - } -` diff --git a/apps/zui/src/app/query-home/title-bar/heading-form.tsx b/apps/zui/src/app/query-home/title-bar/heading-form.tsx deleted file mode 100644 index 4ea8ea42be..0000000000 --- a/apps/zui/src/app/query-home/title-bar/heading-form.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React, {useRef} from "react" -import {useAutoSelect} from "src/app/core/hooks/use-auto-select" -import useEscapeKey from "src/js/components/hooks/useEscapeKey" -import styled from "styled-components" -import {useHeadingForm} from "./use-heading-form" -import forms from "src/components/forms.module.css" - -const Form = styled.form` - display: flex; - gap: 10px; - width: 100%; - margin: 0 auto; - padding-left: 6px; - padding-right: 16px; - height: 28px; -` - -const Input = styled.input` - font-weight: 700; - flex: 1; -` - -export default function HeadingForm() { - const form = useHeadingForm() - const ref = useRef() - useAutoSelect(ref) - useEscapeKey(form.onReset) - return ( -
- - - -
- ) -} diff --git a/apps/zui/src/app/query-home/title-bar/heading-menu.tsx b/apps/zui/src/app/query-home/title-bar/heading-menu.tsx deleted file mode 100644 index f2dcf3707e..0000000000 --- a/apps/zui/src/app/query-home/title-bar/heading-menu.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import styled from "styled-components" -import React from "react" -import {IconButton} from "./icon-button" -import {useActiveQuery} from "./context" -import {savedQueryMenu} from "src/app/menus/saved-query-menu" - -const MenuButton = styled(IconButton)` - height: 22px; - width: 22px; -` - -export function HeadingMenu() { - const active = useActiveQuery() - - return ( - savedQueryMenu.build(active).showUnder(e.currentTarget)} - /> - ) -} diff --git a/apps/zui/src/app/query-home/title-bar/heading-saved.tsx b/apps/zui/src/app/query-home/title-bar/heading-saved.tsx deleted file mode 100644 index aaaeeb64be..0000000000 --- a/apps/zui/src/app/query-home/title-bar/heading-saved.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import classNames from "classnames" -import React from "react" -import {useDispatch} from "src/app/core/state" -import Layout from "src/js/state/Layout" -import styled from "styled-components" -import {useActiveQuery} from "./context" -import {DetatchButton} from "./detatch-button" -import {HeadingButton} from "./heading-button" -import {HeadingMenu} from "./heading-menu" -import {OrangeTag} from "./orange-tag" -import {NavActions} from "./nav-actions" -import {QueryActions} from "./query-actions" - -const BG = styled.div` - display: flex; - min-width: 120px; - justify-content: center; - align-items: center; - flex: 1; - background: rgba(0, 0, 0, 0.05); - height: 28px; - border-radius: 14px; - justify-content: space-between; - padding: 0 8px; -` - -const Title = styled.h2` - font-size: 14px; - font-weight: 700; - line-height: 18px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - &.modified { - font-style: italic; - } -` - -const Wrap = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - padding: 0 16px; - gap: 12px; - background: white; -` - -export function HeadingSaved() { - return ( - - - - - - ) -} - -function SavedQuery() { - const dispatch = useDispatch() - const active = useActiveQuery() - - if (!active.isSaved()) return null - - function onClick() { - dispatch(Layout.showTitleForm("create")) - } - return ( - - - - - {active.name()} {active.isModified() && "*"} - - {active.isOutdated() && Outdated} - - - - ) -} diff --git a/apps/zui/src/app/query-home/title-bar/heading.tsx b/apps/zui/src/app/query-home/title-bar/heading.tsx deleted file mode 100644 index d2558a994c..0000000000 --- a/apps/zui/src/app/query-home/title-bar/heading.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react" -import {useSelector} from "react-redux" -import Layout from "src/js/state/Layout" -import HeadingForm from "./heading-form" -import {HeadingSaved} from "./heading-saved" - -export function Heading() { - const isEditing = useSelector(Layout.getIsEditingTitle) - if (isEditing) { - return - } else { - return - } -} diff --git a/apps/zui/src/app/query-home/title-bar/icon-button.tsx b/apps/zui/src/app/query-home/title-bar/icon-button.tsx deleted file mode 100644 index 3eb731db4b..0000000000 --- a/apps/zui/src/app/query-home/title-bar/icon-button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React, {ButtonHTMLAttributes} from "react" -import Icon, {IconName} from "src/app/core/icon-temp" -import styled from "styled-components" - -const Button = styled.button` - background: white; - border: none; - height: 22px; - width: 28px; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - border-radius: 6px; - background: none; - - &:hover { - background: rgba(0, 0, 0, 0.06); - } - &:active { - background: rgba(0, 0, 0, 0.1); - } - - &:disabled { - opacity: 0.2; - } -` - -type Props = { - icon: IconName - size?: number -} & ButtonHTMLAttributes - -export const IconButton = React.forwardRef( - function IconButton({icon, size, ...rest}: Props, ref) { - return ( - - ) - } -) diff --git a/apps/zui/src/app/query-home/title-bar/nav-actions.tsx b/apps/zui/src/app/query-home/title-bar/nav-actions.tsx deleted file mode 100644 index 2137f35aa7..0000000000 --- a/apps/zui/src/app/query-home/title-bar/nav-actions.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from "react" -import {useSelector} from "react-redux" -import {IconButton} from "src/components/icon-button" -import Current from "src/js/state/Current" -import Layout from "src/js/state/Layout" -import {PaneName} from "src/js/state/Layout/types" -import styled from "styled-components" - -const Nav = styled.div` - display: flex; - button { - } -` - -export function NavActions() { - const isEditing = useSelector(Layout.getIsEditingTitle) - const history = useSelector(Current.getHistory) - - if (isEditing) return null - return ( - - ) -} diff --git a/apps/zui/src/app/query-home/title-bar/orange-tag.tsx b/apps/zui/src/app/query-home/title-bar/orange-tag.tsx deleted file mode 100644 index aa39365946..0000000000 --- a/apps/zui/src/app/query-home/title-bar/orange-tag.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import styled from "styled-components" - -export const OrangeTag = styled.div` - font-size: 10px; - line-height: 10px; - height: 16px; - display: flex; - align-items: center; - justify-content: center; - padding: 0 4px; - font-weight: 700; - text-transform: uppercase; - background: #ffe5cb; - color: #8a4500; - border-radius: 3px; -` diff --git a/apps/zui/src/app/query-home/title-bar/plus-one.test.ts b/apps/zui/src/app/query-home/title-bar/plus-one.test.ts deleted file mode 100644 index 6d6df3ffe3..0000000000 --- a/apps/zui/src/app/query-home/title-bar/plus-one.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {plusOne} from "./plus-one" - -test("plus one", () => { - expect(plusOne("James")).toBe("James 2") -}) - -test("James 2", () => { - expect(plusOne("James 2")).toBe("James 3") -}) - -test("James 2.2", () => { - expect(plusOne("James 2.2")).toBe("James 2.3") -}) - -test("empty", () => { - expect(plusOne("")).toBe("") -}) diff --git a/apps/zui/src/app/query-home/title-bar/query-actions.tsx b/apps/zui/src/app/query-home/title-bar/query-actions.tsx deleted file mode 100644 index 45a828b9cc..0000000000 --- a/apps/zui/src/app/query-home/title-bar/query-actions.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React from "react" -import {useSelector} from "react-redux" -import {runQuery} from "src/app/commands/run-query" -import {useZuiApi} from "src/app/core/context" -import useSelect from "src/app/core/hooks/use-select" -import {useDispatch} from "src/app/core/state" -import Editor from "src/js/state/Editor" -import Layout from "src/js/state/Layout" -import styled from "styled-components" -import {useActiveQuery} from "./context" -import forms from "src/components/forms.module.css" -import {IconButton} from "src/components/icon-button" - -const Actions = styled.div` - display: flex; - gap: 10px; -` - -export function QueryActions() { - const active = useActiveQuery() - const isEditing = useSelector(Layout.getIsEditingTitle) - if (isEditing) return null - return ( - - {active.isModified() && } - - - - ) -} - -function Run() { - return ( - runQuery.run()} // 🎶 - iconName="run" - iconSize={16} - label={"Run"} - /> - ) -} - -function Create() { - const dispatch = useDispatch() - const active = useActiveQuery() - const text = active.isAnonymous() ? "Save" : "Save As" - const isEmpty = useSelector(Editor.isEmpty) - function onClick() { - dispatch(Layout.showTitleForm("create")) - } - - return ( - - ) -} - -function Update() { - const active = useActiveQuery() - const api = useZuiApi() - const select = useSelect() - - function onClick() { - const snapshot = select(Editor.getSnapshot) - const id = active.query.id - api.queries.addVersion(id, snapshot) - api.queries.open(id, {history: "replace"}) - } - - return ( - - ) -} diff --git a/apps/zui/src/app/query-home/title-bar/title-bar.tsx b/apps/zui/src/app/query-home/title-bar/title-bar.tsx deleted file mode 100644 index caf3e88b12..0000000000 --- a/apps/zui/src/app/query-home/title-bar/title-bar.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react" -import styled from "styled-components" -import {useSelector} from "react-redux" -import Current from "src/js/state/Current" -import {Heading} from "./heading" -import {TitleBarProvider} from "./context" - -const BG = styled.header.attrs({ - className: "title-bar", - "aria-label": "Title Bar", - "data-testid": "title-bar", -})` - flex-shrink: 0; - height: 37px; - display: flex; - align-items: center; -` - -export function TitleBar() { - const active = useSelector(Current.getActiveQuery) - return ( - - - - - - ) -} diff --git a/apps/zui/src/app/query-home/title-bar/use-heading-form.ts b/apps/zui/src/app/query-home/title-bar/use-heading-form.ts deleted file mode 100644 index cced530375..0000000000 --- a/apps/zui/src/app/query-home/title-bar/use-heading-form.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {FormEvent} from "react" -import {useSelector} from "react-redux" -import * as queries from "src/app/commands/queries" -import {useZuiApi} from "src/app/core/context" -import {useDispatch} from "src/app/core/state" -import Layout from "src/js/state/Layout" -import {useActiveQuery} from "./context" -import {plusOne} from "./plus-one" - -export function useHeadingForm() { - const active = useActiveQuery() - const api = useZuiApi() - const dispatch = useDispatch() - const action = useSelector(Layout.getTitleFormAction) - - async function createNewQuery(name: string) { - queries.save.run(name) - } - - function renameQuery(name: string) { - api.queries.rename(active.query.id, name) - } - - function getInput(e: FormEvent) { - return e.currentTarget.elements.namedItem("query-name") as HTMLInputElement - } - - function getDefaultValue() { - if (action === "create" && active.name()) { - return plusOne(active.name()) - } else { - return active.name() - } - } - - function getButtonText() { - return action === "create" ? "Create" : "Update" - } - - return { - onSubmit: (e: FormEvent) => { - e.preventDefault() - const input = getInput(e) - if (!input) { - dispatch(Layout.hideTitleForm()) - return - } - if (action === "update" && input.value === getDefaultValue()) { - dispatch(Layout.hideTitleForm()) - return - } - if (active.isAnonymous() || action === "create") { - createNewQuery(input.value) - } else { - renameQuery(input.value) - } - dispatch(Layout.hideTitleForm()) - }, - onReset: () => dispatch(Layout.hideTitleForm()), - defaultValue: getDefaultValue(), - buttonText: getButtonText(), - } -} diff --git a/apps/zui/src/app/query-home/toolbar/actions/button.tsx b/apps/zui/src/app/query-home/toolbar/actions/button.tsx deleted file mode 100644 index c67e6480a3..0000000000 --- a/apps/zui/src/app/query-home/toolbar/actions/button.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import classNames from "classnames" -import * as React from "react" - -import Icon from "src/app/core/icon-temp" -import styled from "styled-components" - -type Props = { - text?: string - icon?: React.ReactNode - dropdown?: boolean - disabled?: boolean - className?: string - isPrimary?: boolean - onClick: React.MouseEventHandler -} - -const DropdownIcon = styled(Icon).attrs({name: "chevron-down"})` - width: 9px; - height: 9px; - display: flex; - justify-contents: center; - align-items: center; - margin: 0 4px; -` - -const StyledIcon = styled.span` - display: flex; - margin: 0 4px; - - svg { - fill: black; - height: 16px; - width: 16px; - } -` -const Text = styled.span` - ${(p) => p.theme.typography.labelSmall} - white-space: nowrap; - color: rgba(0, 0, 0, 0.6); - display: flex; - line-height: 16px; - height: 16px; - padding: 0 4px; - white-space: nowrap; -` - -const StyledButton = styled.button` - // background: var(--button-background); - // &:active:not(:disabled) { - // background: linear-gradient(#fefefe, 0.5px, #f3f3f3 2px); - // } - background: none; - border: none; - border-radius: 6px; - user-select: none; - -webkit-app-region: no-drag; - height: 24px; - padding: 0 4px; - display: flex; - align-items: center; - justify-content: center; - - & > * { - pointer-events: none; - } - - &:disabled { - opacity: 0.2; - cursor: not-allowed; - } - - &:hover:not(:disabled) { - background: var(--button-background-hover); - } - &:active:not(:disabled) { - background: var(--button-background-active); - } - - &.primary { - background: linear-gradient(#4b91e2, #3a87df); - ${Text} { - color: white; - } - &:hover:not(:disabled) { - background: var(--primary-color); - } - &:hover:not(:disabled) { - background: var(--primary-color-dark); - } - &:active:not(:disabled) { - background: var(--primary-color-darker); - } - } -` - -const ToolbarButton = ({ - text, - icon, - disabled, - dropdown, - isPrimary, - onClick, - ...rest -}: Props) => { - return ( - - {!!icon && {icon}} - {!!text && {text}} - {!!dropdown && } - - ) -} - -export default ToolbarButton diff --git a/apps/zui/src/app/query-home/toolbar/results-toolbar.tsx b/apps/zui/src/app/query-home/toolbar/results-toolbar.tsx deleted file mode 100644 index 468c3c5d29..0000000000 --- a/apps/zui/src/app/query-home/toolbar/results-toolbar.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react" -import {ButtonMenu} from "src/components/button-menu" -import {Toolbar} from "src/components/toolbar" -import {ResultsViewSwitch} from "./results-view-switch" -import {useMenuInstance} from "src/core/menu/use-menu-instance" -import styles from "../query-home.module.css" - -export function ResultsToolbar() { - const menu = useMenuInstance("results.toolbarMenu") - return ( - - - - - ) -} diff --git a/apps/zui/src/app/query-home/toolbar/results-view-switch.tsx b/apps/zui/src/app/query-home/toolbar/results-view-switch.tsx deleted file mode 100644 index 0da6c509c1..0000000000 --- a/apps/zui/src/app/query-home/toolbar/results-view-switch.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, {startTransition} from "react" -import {useSelector} from "react-redux" -import useKeybinding from "src/app/core/hooks/use-keybinding" -import {useDispatch} from "src/app/core/state" -import {SectionTabs} from "src/components/section-tabs" -import Layout from "src/js/state/Layout" -import {ResultsView} from "src/js/state/Layout/types" -import styled from "styled-components" - -const BG = styled.div` - height: 100%; -` -const INSPECTOR = "INSPECTOR" -const TABLE = "TABLE" - -export function ResultsViewSwitch() { - const dispatch = useDispatch() - const view = useSelector(Layout.getResultsView) - - const setView = (view: ResultsView) => { - startTransition(() => { - dispatch(Layout.setResultsView(view as ResultsView)) - }) - } - - useKeybinding("ctrl+d", () => { - setView(view === TABLE ? INSPECTOR : TABLE) - }) - - return ( - - setView(TABLE), - checked: view === TABLE, - }, - { - label: "Inspector", - click: () => setView(INSPECTOR), - checked: view === INSPECTOR, - }, - ]} - /> - - ) -} diff --git a/apps/zui/src/app/router/routes.ts b/apps/zui/src/app/router/routes.ts index 09aee1da65..aa16057a2a 100644 --- a/apps/zui/src/app/router/routes.ts +++ b/apps/zui/src/app/router/routes.ts @@ -1,5 +1,5 @@ import {matchPath} from "react-router" -import {IconName} from "../core/icon-temp" +import {IconName} from "../../components/icon" /** * A single place to store all app route information. The title field is @@ -31,7 +31,7 @@ export const queryVersion: Route = { export const lakeReleaseNotes: Route = { title: "Release Notes", path: `/release-notes`, - icon: "doc-plain", + icon: "doc_plain", } export const releaseNotes: Route = { diff --git a/apps/zui/src/app/routes/app-wrapper/app-grid.tsx b/apps/zui/src/app/routes/app-wrapper/app-grid.tsx index b75d89f46e..9d6f32aada 100644 --- a/apps/zui/src/app/routes/app-wrapper/app-grid.tsx +++ b/apps/zui/src/app/routes/app-wrapper/app-grid.tsx @@ -7,20 +7,26 @@ const BG = styled.div` min-height: 0; height: 100vh; display: grid; - background: var(--sidebar-background); + + body:not(.is-dragging) & { + transition: grid-template-columns 300ms var(--pop-easing); + } ` export function AppGrid({children}) { const sidebarIsOpen = useSelector(Appearance.sidebarIsOpen) const sidebarWidth = useSelector(Appearance.sidebarWidth) + const secondarySidebarIsOpen = useSelector(Appearance.secondarySidebarIsOpen) + const secondarySidebarWidth = useSelector(Appearance.secondarySidebarWidth) + const areas = ` - "sidebar tabs" - "sidebar main" - "sidebar status" + "sidebar tabs secondary-sidebar" + "sidebar main secondary-sidebar" ` const width = sidebarIsOpen ? sidebarWidth : 0 - const rows = ["40px", "1fr", "28px"] - const columns = [`min(${width}px, 80vw)`, "1fr"] + const width2 = secondarySidebarIsOpen ? secondarySidebarWidth : 0 + const rows = ["40px", "1fr"] + const columns = [`min(${width}px, 70vw)`, "1fr", `min(${width2}px, 30vw)`] const style = { gridTemplateAreas: areas, gridTemplateRows: rows.join(" "), diff --git a/apps/zui/src/app/routes/app-wrapper/app-modals.tsx b/apps/zui/src/app/routes/app-wrapper/app-modals.tsx index 1c340a9991..9a13b033c1 100644 --- a/apps/zui/src/app/routes/app-wrapper/app-modals.tsx +++ b/apps/zui/src/app/routes/app-wrapper/app-modals.tsx @@ -1,6 +1,6 @@ import React from "react" import Toaster from "src/js/components/Toaster" -import Tooltip from "src/js/components/Tooltip" +import {Tooltip} from "src/components/tooltip" import ErrorNotice from "src/js/components/ErrorNotice" import HTMLContextMenu from "src/js/components/HTMLContextMenu" import {Modals} from "src/js/components/Modals" diff --git a/apps/zui/src/app/routes/app-wrapper/app-wrapper.tsx b/apps/zui/src/app/routes/app-wrapper/app-wrapper.tsx index 4ff9619513..a1be8be985 100644 --- a/apps/zui/src/app/routes/app-wrapper/app-wrapper.tsx +++ b/apps/zui/src/app/routes/app-wrapper/app-wrapper.tsx @@ -1,5 +1,4 @@ import React from "react" -import StatusBar from "src/js/components/status-bar/status-bar" import TabBar from "src/js/components/TabBar/TabBar" import {Sidebar} from "src/app/features/sidebar" import {AppModals} from "./app-modals" @@ -7,6 +6,7 @@ import {MainArea} from "./main-area" import {AppGrid} from "./app-grid" import useLakeId from "src/app/router/hooks/use-lake-id" import {DataDropzone} from "./data-dropzone" +import RightPane from "src/app/features/right-pane" export default function AppWrapper({children}) { const lakeId = useLakeId() @@ -16,7 +16,7 @@ export default function AppWrapper({children}) { {children} - + diff --git a/apps/zui/src/app/routes/app-wrapper/data-dropzone.module.css b/apps/zui/src/app/routes/app-wrapper/data-dropzone.module.css index 5d37752bac..38ba5716a1 100644 --- a/apps/zui/src/app/routes/app-wrapper/data-dropzone.module.css +++ b/apps/zui/src/app/routes/app-wrapper/data-dropzone.module.css @@ -41,7 +41,7 @@ .title em { font-style: normal; - color: var(--foreground-color); + color: var(--fg-color); } .note { diff --git a/apps/zui/src/app/routes/app-wrapper/main-area.tsx b/apps/zui/src/app/routes/app-wrapper/main-area.tsx index 60e6c85605..a92117d60d 100644 --- a/apps/zui/src/app/routes/app-wrapper/main-area.tsx +++ b/apps/zui/src/app/routes/app-wrapper/main-area.tsx @@ -9,14 +9,21 @@ import styled from "styled-components" const BG = styled.main` min-height: 0; min-width: 0; - height: 100%; display: flex; flex-direction: column; grid-area: main; overflow: hidden; - background: white; + background: var(--bg-color); z-index: 1; - box-shadow: -1px -1px 2px rgba(0, 0, 0, 0.1); + margin: 10px; + margin-top: 0; + border-radius: 6px; + box-shadow: var(--shadow-small); + border: 1px solid var(--border-color); + + @media (prefers-color-scheme: light) { + border: none; + } ` export function isInteractive() { @@ -33,7 +40,11 @@ export function MainArea({children}) { const dispatch = useDispatch() const touched = () => dispatch(isInteractive()) const sidebarIsOpen = useSelector(Appearance.sidebarIsOpen) - const style: CSSProperties = {borderTopLeftRadius: sidebarIsOpen ? 6 : 0} + const secondarySidebarIsOpen = useSelector(Appearance.secondarySidebarIsOpen) + const style: CSSProperties = { + marginLeft: sidebarIsOpen ? 0 : "10px", + marginRight: secondarySidebarIsOpen ? 0 : "10px", + } return ( diff --git a/apps/zui/src/components/button-menu.tsx b/apps/zui/src/components/button-menu.tsx index 72bb272c40..b39baed8ac 100644 --- a/apps/zui/src/components/button-menu.tsx +++ b/apps/zui/src/components/button-menu.tsx @@ -1,5 +1,5 @@ import classNames from "classnames" -import React from "react" +import React, {useMemo} from "react" import {MenuItem} from "src/core/menu" import styled from "styled-components" import {IconButton} from "./icon-button" @@ -27,8 +27,16 @@ const Buttons = styled.div` min-width: 0; ` -export function ButtonMenu(props: {label: string; items: MenuItem[]}) { - const menu = useResponsiveMenu(props.items) +export function ButtonMenu(props: { + label: string + items: MenuItem[] + justify?: "flex-start" | "flex-end" | "center" +}) { + const items = useMemo( + () => props.items.filter((i) => i.visible !== false), + [props.items] + ) + const menu = useResponsiveMenu(items) const buttons = menu.items.map((item: MenuItem, i: number) => { return ( @@ -41,8 +49,9 @@ export function ButtonMenu(props: {label: string; items: MenuItem[]}) { /> ) }) + const style = {justifyContent: props.justify ?? "flex-end"} return ( - + {buttons} {menu.hasHiddenItems ? ( diff --git a/apps/zui/src/components/debut.tsx b/apps/zui/src/components/debut.tsx index 3a14eec970..16c28606c9 100644 --- a/apps/zui/src/components/debut.tsx +++ b/apps/zui/src/components/debut.tsx @@ -11,6 +11,7 @@ export function useDebut(args: {afterExit?: () => any}) { setIsExiting, }, exit: () => setIsExiting(true), + cancelExit: () => setIsExiting(false), isExiting, } diff --git a/apps/zui/src/components/dialog/index.tsx b/apps/zui/src/components/dialog/index.tsx index bd7678245e..0cd9fc1c6f 100644 --- a/apps/zui/src/components/dialog/index.tsx +++ b/apps/zui/src/components/dialog/index.tsx @@ -44,7 +44,6 @@ export function Dialog(props: DialogProps) { target: node && props.isOpen ? node : null, targetPoint: props.dialogPoint, targetMargin: props.dialogMargin, - keepOnScreen: props.keepOnScreen, }) function onClose(e) { @@ -64,7 +63,7 @@ export function Dialog(props: DialogProps) { onClose={onClose} onCancel={onCancel} ref={setNode} - style={style} + style={{...style, position: "fixed"}} {...omit(props, ...nonHTMLProps)} > {props.children} diff --git a/apps/zui/src/components/drag-anchor.tsx b/apps/zui/src/components/drag-anchor.tsx index 4f30a2b94f..d07c21e93a 100644 --- a/apps/zui/src/components/drag-anchor.tsx +++ b/apps/zui/src/components/drag-anchor.tsx @@ -8,9 +8,9 @@ const Area = styled.div` background: transparent; pointer-events: all !important; z-index: 99; - --size: 7px; + --size: 11px; --padding: 1px; - --offset: -5px; + --offset: -4px; &.debug { background: red; @@ -93,6 +93,7 @@ export default class DragAnchor extends React.Component { const body = document.body body.style.cursor = this.getCursor() body.style.userSelect = "none" + body.classList.add("is-dragging") document.addEventListener("mousemove", this.move) document.addEventListener("mouseup", this.up) call(this.props.onStart, e) @@ -109,6 +110,7 @@ export default class DragAnchor extends React.Component { if (body) { body.style.cursor = "" body.style.userSelect = "" + body.classList.remove("is-dragging") document.removeEventListener("mousemove", this.move) document.removeEventListener("mouseup", this.up) } diff --git a/apps/zui/src/components/file-input.tsx b/apps/zui/src/components/file-input.tsx index a46b64b789..5333d05ced 100644 --- a/apps/zui/src/components/file-input.tsx +++ b/apps/zui/src/components/file-input.tsx @@ -22,7 +22,7 @@ export function FileInput( { input.current?.click() diff --git a/apps/zui/src/components/forms.module.css b/apps/zui/src/components/forms.module.css index 3398d30f61..03edf44a8a 100644 --- a/apps/zui/src/components/forms.module.css +++ b/apps/zui/src/components/forms.module.css @@ -81,7 +81,6 @@ padding: var(--form-padding); background: var(--primary-color); border: 1px solid var(--primary-color-dark); - box-shadow: 0 3px 3px -3px var(--foreground-color); color: white; font-weight: 500; min-width: 80px; @@ -108,7 +107,7 @@ line-height: var(--form-line-height); padding: var(--form-padding); border: 1px solid var(--border-color); - box-shadow: 0 3px 4px -4px var(--foreground-color-light); + box-shadow: 0 3px 4px -4px var(--bg-color-less); font-weight: 500; min-width: 80px; user-select: none; @@ -151,7 +150,7 @@ .form .actionLabel a { text-decoration: underline; cursor: pointer; - color: var(--foreground-color-light); + color: var(--fg-color-less); } .form .radioInput { diff --git a/apps/zui/src/components/icon-button.tsx b/apps/zui/src/components/icon-button.tsx index 1fc0a03222..b541183a1a 100644 --- a/apps/zui/src/components/icon-button.tsx +++ b/apps/zui/src/components/icon-button.tsx @@ -5,10 +5,9 @@ import React, { MutableRefObject, forwardRef, } from "react" -import {BoundCommand} from "src/app/commands/command" -import Icon from "src/app/core/icon-temp" -import {invoke} from "src/core/invoke" +import {Icon} from "src/components/icon" import {MenuItem} from "src/core/menu" +import {handleClick} from "src/core/menu/handle-click" import styled from "styled-components" const BG = styled.button` @@ -23,7 +22,7 @@ const BG = styled.button` align-items: center; justify-content: center; flex-shrink: 0; - transition: background 100ms; + transition: background var(--quick), transform var(--quick); -webkit-app-region: no-drag; &:disabled { @@ -32,17 +31,23 @@ const BG = styled.button` } &:hover:not(:disabled) { - background: var(--hover-dark); + background: var(--emphasis-bg); + svg { + transform: scale(1.1); + } } &:active:not(:disabled) { - background: var(--active-dark); + background: var(--emphasis-bg-more); + svg { + transform: scale(1.05); + } } &.icon-label { gap: 6px; padding: 0 8px; - border: 1px solid var(--border-color-dark); + border: 1px solid var(--border-color-more); font-weight: 500; font-size: 14px; height: 28px; @@ -53,18 +58,16 @@ export const IconButton = forwardRef(function IconButton( props: MenuItem & { className?: string onClick?: MouseEventHandler + buildMenu?: () => MenuItem[] }, ref: MutableRefObject ) { + // I think this needs to move into some core place function onClick(e: MouseEvent) { if (props.onClick) { props.onClick && props.onClick(e) - } else if (typeof props.command === "string") { - invoke("invokeCommandOp", props.command, props.args) - } else if (props.command instanceof BoundCommand) { - props.command.run() - } else if (props.click) { - props.click() + } else { + handleClick(props, e.currentTarget) } } @@ -72,13 +75,16 @@ export const IconButton = forwardRef(function IconButton( - + + {props?.nestedMenu?.length && } {props.display === "icon-label" ? props.label : null} ) diff --git a/apps/zui/src/components/icon/icon-names.ts b/apps/zui/src/components/icon/icon-names.ts new file mode 100644 index 0000000000..fbdf717bd8 --- /dev/null +++ b/apps/zui/src/components/icon/icon-names.ts @@ -0,0 +1,63 @@ +import {MingCuteIconName} from "./ming-cute-names" + +export type IconMapping = {[name: string]: MingCuteIconName} + +export type IconName = keyof typeof iconNames | keyof typeof customIconNames + +export const iconNames = { + chevron_down: "down", + chevron_left: "left", + chevron_right: "right", + chevron_up: "up", + add: "add_circle", + collapse_horizontal: "fold_horizontal", + doc_plain: "document", + double_chevron_right: "arrows_right", + expand_horizontal: "unfold_horizontal", + file_border: "document", + file_filled: "document", + left_arrow: "arrow_left", + right_arrow: "arrow_right", + sort_asc: "sort_ascending", + sort_desc: "sort_descending", + three_dots_stacked: "more_2", + three_dots: "more_1", + braces: "braces", + chart: "chart_line", + check: "check", + close: "close", + close_circle: "close_circle", + collapse: "fold_vertical", + columns: "table", + detach: "delete_back", + expand: "unfold_vertical", + export: "file_export", + folder: "folder", + grid: "grid", + hide: "eye_close", + history: "history", + list: "list_ordered", + lock: "lock", + pin: "pin_2", + plus: "add", + pool: "polkadot_DOT", + query: "search_2", + reload: "refresh_1", + run: "play", + reset: "arrow_to_left", + show: "eye", + tag: "tag", + update: "upload", + view: "layout", + warning: "warning", + layout_rightbar_open: "layout_rightbar_open", + layout_rightbar_close: "layout_rightbar_close", + layout_leftbar_open: "layout_leftbar_open", + layout_leftbar_close: "layout_leftbar_close", + file_upload: "file_upload", +} + +export const customIconNames = { + zui: "zui", + wireshark: "wireshark", +} diff --git a/apps/zui/src/components/icon/icon.module.css b/apps/zui/src/components/icon/icon.module.css new file mode 100644 index 0000000000..94f2fc1c98 --- /dev/null +++ b/apps/zui/src/components/icon/icon.module.css @@ -0,0 +1,4 @@ +.icon { + height: 1.1rem; + width: 1.1rem; +} diff --git a/apps/zui/src/components/icon/index.tsx b/apps/zui/src/components/icon/index.tsx new file mode 100644 index 0000000000..6ba171106f --- /dev/null +++ b/apps/zui/src/components/icon/index.tsx @@ -0,0 +1,35 @@ +import React from "react" +import styles from "./icon.module.css" +import {IconName as Name, customIconNames, iconNames} from "./icon-names" +import classNames from "classnames" + +type Props = { + name: Name + className?: string + size?: string + fill?: string + stroke?: string +} + +const iconStyle: "line" | "fill" = "line" + +export function Icon(props: Props) { + const customName = customIconNames[props.name] + const name = iconNames[props.name] + const path = customName + ? `/custom-icons.svg#${customName}` + : `/icons.svg#${name}_${iconStyle}` + const style = props.size ? {width: props.size, height: props.size} : undefined + + return ( + + + + ) +} + +export type IconName = Name diff --git a/apps/zui/src/components/icon/ming-cute-names.ts b/apps/zui/src/components/icon/ming-cute-names.ts new file mode 100644 index 0000000000..133c73745a --- /dev/null +++ b/apps/zui/src/components/icon/ming-cute-names.ts @@ -0,0 +1,1336 @@ +export type MingCuteIconName = + | "ABS" + | "AZ_sort_ascending_letters" + | "AZ_sort_descending_letters" + | "Android_2" + | "BNB" + | "Heading_1" + | "Heading_2" + | "Heading_3" + | "IDcard" + | "TV_towe" + | "UFO" + | "UFO_2" + | "VIP_1" + | "VIP_2" + | "VIP_3" + | "VIP_4" + | "XRP" + | "ZA_sort_ascending_letters" + | "ZA_sort_descending_letters" + | "add" + | "add_circle" + | "aerial_lift" + | "aiming" + | "aiming_2" + | "air_balloon" + | "air_condition" + | "air_condition_open" + | "airbnb" + | "airdrop" + | "airplane" + | "airplay" + | "airpods" + | "airpods_2" + | "alarm_1" + | "alarm_2" + | "album" + | "album_2" + | "alert" + | "alert_diamond" + | "alert_octagon" + | "align_arrow_down" + | "align_arrow_left" + | "align_arrow_right" + | "align_arrow_up" + | "align_bottom" + | "align_center" + | "align_horizontal_center" + | "align_justify" + | "align_left" + | "align_left_2" + | "align_right" + | "align_right_2" + | "align_top" + | "align_vertical_center" + | "alipay" + | "american_football" + | "anchor" + | "and" + | "android" + | "angel" + | "angry" + | "anniversary" + | "announcement" + | "anticlockwise" + | "anticlockwise_alt" + | "apple" + | "appstore" + | "archive" + | "arrow_down" + | "arrow_down_circle" + | "arrow_left" + | "arrow_left_circle" + | "arrow_left_down" + | "arrow_left_down_circle" + | "arrow_left_up" + | "arrow_left_up_circle" + | "arrow_right" + | "arrow_right_circle" + | "arrow_right_down" + | "arrow_right_down_circle" + | "arrow_right_up" + | "arrow_right_up_circle" + | "arrow_to_down" + | "arrow_to_left" + | "arrow_to_right" + | "arrow_to_up" + | "arrow_up" + | "arrow_up_circle" + | "arrows_down" + | "arrows_left" + | "arrows_right" + | "arrows_up" + | "artboard" + | "aspect_ratio" + | "asterisk" + | "asterisk_2" + | "at" + | "attachment" + | "attachment_2" + | "auction" + | "audio_tape" + | "auto_hold" + | "avalanche_AVAX" + | "award" + | "axe" + | "baby" + | "baby_carriage" + | "back" + | "back_2" + | "backboard" + | "background" + | "backpack" + | "badge" + | "badminton" + | "balance" + | "balloon_2" + | "bank" + | "bank_card" + | "bank_of_china_tower" + | "barbell" + | "barcode" + | "barcode_scan" + | "base_station" + | "base_station_2" + | "baseball" + | "basket" + | "basket_2" + | "basketball" + | "bath" + | "battery" + | "battery_1" + | "battery_2" + | "battery_3" + | "battery_4" + | "battery_automotive" + | "battery_charging" + | "bear" + | "beard" + | "bed" + | "bed_2" + | "bell_ringing" + | "big_ben" + | "bike" + | "bill" + | "binance_USD_BUSD" + | "binance_coin_BNB" + | "bird" + | "birthday_2" + | "black_board" + | "black_board_2" + | "blessing" + | "bling" + | "blockquote" + | "bluetooth" + | "bluetooth_off" + | "board" + | "body" + | "bold" + | "bomb" + | "bone" + | "book" + | "book_2" + | "book_3" + | "book_4" + | "book_5" + | "book_6" + | "bookmark" + | "bookmarks" + | "boom" + | "border_blank" + | "border_bottom" + | "border_horizontal" + | "border_inner" + | "border_left" + | "border_outer" + | "border_radius" + | "border_right" + | "border_top" + | "border_vertical" + | "bow_tie" + | "bowknot" + | "bowl" + | "box" + | "box_2" + | "box_3" + | "braces" + | "brackets" + | "brackets_angle" + | "brain" + | "brake" + | "bread" + | "bridge" + | "bridge_2" + | "brief" + | "briefcase" + | "brightness" + | "broom" + | "brush" + | "brush_2" + | "brush_3" + | "bug" + | "building_1" + | "building_2" + | "building_3" + | "building_4" + | "building_5" + | "building_6" + | "bulb" + | "burj_al_arab" + | "burj_khalifa_tower" + | "bus" + | "bus_2" + | "butterfly" + | "cactus" + | "cactus_2" + | "cake" + | "calendar" + | "calendar_2" + | "calendar_3" + | "calendar_add" + | "calendar_day" + | "calendar_month" + | "calendar_time_add" + | "calendar_week" + | "camcorder" + | "camcorder_2" + | "camcorder_3" + | "camera" + | "camera_2" + | "camera_rotate" + | "campground" + | "candle" + | "candy" + | "candy_2" + | "canton_tower" + | "capsule" + | "car" + | "car_2" + | "car_3" + | "car_door" + | "car_window" + | "card_pay" + | "card_refund" + | "cardano_ADA" + | "cardboard_vr" + | "carplay" + | "carrot" + | "cat" + | "ceiling_lamp" + | "celebrate" + | "cellphone" + | "cellphone_vibration" + | "celsius" + | "certificate" + | "certificate_2" + | "champagne" + | "charging_pile" + | "chart_bar" + | "chart_bar_2" + | "chart_decrease" + | "chart_horizontal" + | "chart_line" + | "chart_pie" + | "chart_pie_2" + | "chart_vertical" + | "chat_1" + | "chat_2" + | "chat_3" + | "chat_4" + | "check" + | "check_2" + | "check_circle" + | "checkbox" + | "checks" + | "chess" + | "chicken" + | "chines_knot" + | "chip" + | "choice" + | "chopsticks" + | "christ_the_redeemer" + | "christmas_ball" + | "christmas_hat" + | "chrome" + | "church" + | "clapperboard" + | "classify" + | "classify_2" + | "classify_3" + | "classify_add" + | "classify_add_2" + | "clipboard" + | "clock" + | "clock_2" + | "clockwise" + | "clockwise_alt" + | "close" + | "close_circle" + | "cloud" + | "cloud_2" + | "cloud_lightning" + | "cloud_snow" + | "cloud_windy" + | "clouds" + | "clubs" + | "coat" + | "coathanger" + | "code" + | "codepen" + | "coin" + | "coin_2" + | "coin_3" + | "color_filter" + | "color_picker" + | "column" + | "columns_2" + | "columns_3" + | "command" + | "comment" + | "comment_2" + | "compass" + | "compass_2" + | "computer" + | "computer_camera" + | "computer_camera_off" + | "confused" + | "contacts" + | "contacts_2" + | "contacts_3" + | "cookie" + | "cookie_man" + | "copper_coin" + | "copy" + | "copy_2" + | "copy_3" + | "copyright" + | "counter" + | "counter_2" + | "coupon" + | "cross" + | "cross_2" + | "crutch" + | "cube_3d" + | "cupcake" + | "currency_baht" + | "currency_baht_2" + | "currency_bitcoin" + | "currency_bitcoin_2" + | "currency_cny" + | "currency_cny_2" + | "currency_dollar" + | "currency_dollar_2" + | "currency_euro" + | "currency_euro_2" + | "currency_lira" + | "currency_lira_2" + | "currency_pound" + | "currency_pound_2" + | "currency_rubel" + | "currency_rubel_2" + | "currency_rupee" + | "currency_rupee_2" + | "currency_shekel" + | "currency_shekel_2" + | "currency_won" + | "currency_won_2" + | "cursor" + | "cursor_text" + | "curtain" + | "dandelion" + | "dashboard" + | "dashboard_2" + | "dashboard_3" + | "dashboard_4" + | "deer" + | "delete" + | "delete_2" + | "delete_3" + | "delete_back" + | "dental" + | "department" + | "desk" + | "desk_lamp" + | "device" + | "diamond" + | "diamond_2" + | "diamond_square" + | "diary" + | "dingtalk" + | "direction_arrow" + | "direction_dot" + | "directions" + | "directions_2" + | "directory" + | "disc" + | "discord" + | "display" + | "distribute_spacing_horizontal" + | "distribute_spacing_vertical" + | "dividing_line" + | "doc" + | "document" + | "document_2" + | "document_3" + | "documents" + | "dog" + | "dogecoin_DOGE" + | "door" + | "dot_grid" + | "dots" + | "dots_vertical" + | "down" + | "down_small" + | "download" + | "download_2" + | "download_3" + | "dragonfly" + | "drawer" + | "drawer_2" + | "drawing_board" + | "dress" + | "dribbble" + | "drink" + | "drive" + | "drizzle" + | "drone" + | "drop" + | "dropbox" + | "drum" + | "dry" + | "dutch_windmill" + | "ear" + | "earth" + | "earth_2" + | "earth_latitude" + | "earth_longitude" + | "ebike" + | "edge" + | "edit" + | "edit_2" + | "edit_3" + | "edit_4" + | "egg" + | "egg_crack" + | "egyptian_pyramids" + | "eiffel_tower" + | "emergency_flashers" + | "emoji" + | "emoji_2" + | "engine" + | "enter_door" + | "entrance" + | "eraser" + | "escalator_down" + | "escalator_up" + | "ethereum" + | "exchange_baht" + | "exchange_bitcoin" + | "exchange_cny" + | "exchange_dollar" + | "exchange_euro" + | "exit" + | "exit_door" + | "expand_player" + | "exposure" + | "external_link" + | "eye" + | "eye_2" + | "eye_close" + | "eyebrow" + | "eyeglass" + | "face" + | "face_mask" + | "facebook" + | "faceid" + | "factory" + | "fahrenheit" + | "fan" + | "fan_2" + | "fan_direction_down" + | "fan_direction_front" + | "fan_direction_up" + | "fast_forward" + | "fast_rewind" + | "father_christmas" + | "female" + | "ferris_wheel" + | "figma" + | "file" + | "file_certificate" + | "file_check" + | "file_code" + | "file_download" + | "file_export" + | "file_forbid" + | "file_import" + | "file_info" + | "file_locked" + | "file_more" + | "file_music" + | "file_new" + | "file_search" + | "file_security" + | "file_star" + | "file_unknown" + | "file_upload" + | "file_warning" + | "file_zip" + | "film" + | "filter" + | "filter_2" + | "filter_3" + | "finger_press" + | "finger_rock" + | "finger_swipe" + | "finger_tap" + | "fingerprint" + | "fire" + | "firecracker" + | "firefox" + | "firework" + | "fish" + | "fitness" + | "flag_1" + | "flag_2" + | "flag_3" + | "flag_4" + | "flame" + | "flash" + | "flashlight" + | "flask" + | "flask_2" + | "flight_inflight" + | "flight_land" + | "flight_takeoff" + | "flip_horizontal" + | "flip_vertical" + | "floating_dust" + | "flower" + | "flower_2" + | "flower_3" + | "flower_4" + | "flowerpot" + | "fog" + | "fold_horizontal" + | "fold_vertical" + | "folder" + | "folder_2" + | "folder_3" + | "folder_check" + | "folder_delete" + | "folder_download" + | "folder_forbid" + | "folder_info" + | "folder_locked" + | "folder_locked_2" + | "folder_minus" + | "folder_more" + | "folder_open" + | "folder_open_2" + | "folder_security" + | "folder_star" + | "folder_upload" + | "folder_warning" + | "folders" + | "folding_fan" + | "font" + | "font_size" + | "foot" + | "football" + | "forbid_circle" + | "fork" + | "fork_knife" + | "fork_spoon" + | "formula" + | "forward" + | "forward_2" + | "four_wheel_drive" + | "frame" + | "fridge" + | "front_fog_lights" + | "front_windshield_defroster" + | "full_moon" + | "fullscreen" + | "fullscreen_2" + | "fullscreen_exit" + | "fullscreen_exit_2" + | "game_1" + | "game_2" + | "gas_station" + | "gesture_unlock" + | "ghost" + | "gift" + | "gift_2" + | "gift_card" + | "git_branch" + | "git_commit" + | "git_compare" + | "git_lab" + | "git_merge" + | "git_pull_request" + | "git_pull_request_close" + | "github" + | "glass_cup" + | "globe" + | "glove" + | "google" + | "google_play" + | "government" + | "gradienter" + | "grass" + | "greatwall" + | "grid" + | "grid_2" + | "group" + | "guitar" + | "hail" + | "hair" + | "hair_2" + | "hammer" + | "hand" + | "hand_card" + | "hand_finger" + | "hand_finger_2" + | "hand_grab" + | "hand_heart" + | "hand_two_fingers" + | "hands_clapping" + | "happy" + | "hashtag" + | "hat" + | "hat_2" + | "haze" + | "head" + | "headphone" + | "headphone_2" + | "heart" + | "heart_crack" + | "heart_half" + | "heartbeat" + | "heartbeat_2" + | "heavy_rain" + | "heavy_rainstorm" + | "heavy_snow" + | "heavy_snowstorm" + | "hexagon" + | "high_temperature" + | "high_voltage_power" + | "hight_beam_headlights" + | "history" + | "history_2" + | "history_anticlockwise" + | "hoe" + | "home_1" + | "home_2" + | "home_3" + | "home_4" + | "home_5" + | "home_6" + | "home_wifi" + | "homepod" + | "homepod_mini" + | "hood" + | "horn" + | "horn_2" + | "hospital" + | "hotkey" + | "hours" + | "iMac" + | "ice_cream" + | "ice_cream_2" + | "inbox" + | "inbox_2" + | "incognito_mode" + | "indent_decrease" + | "indent_increase" + | "information" + | "ins" + | "inspect" + | "instrument" + | "inventory" + | "invite" + | "italic" + | "jeep" + | "kakao_talk" + | "key_1" + | "key_2" + | "keyboard" + | "keyboard_2" + | "keyhole" + | "kingkey_100_tower" + | "kite" + | "knife" + | "ladder" + | "lantern" + | "lantern_2" + | "laptop" + | "laptop_2" + | "large_arrow_down" + | "large_arrow_left" + | "large_arrow_right" + | "large_arrow_up" + | "layer" + | "layout" + | "layout_10" + | "layout_11" + | "layout_2" + | "layout_3" + | "layout_4" + | "layout_5" + | "layout_6" + | "layout_7" + | "layout_8" + | "layout_9" + | "layout_bottom" + | "layout_bottom_close" + | "layout_bottom_open" + | "layout_grid" + | "layout_left" + | "layout_leftbar_close" + | "layout_leftbar_open" + | "layout_right" + | "layout_rightbar_close" + | "layout_rightbar_open" + | "layout_top" + | "layout_top_close" + | "layout_top_open" + | "leaf" + | "leaf_2" + | "leaf_3" + | "left" + | "left_small" + | "letter_spacing" + | "lifebuoy" + | "light" + | "light_snow" + | "lighthouse" + | "lightning" + | "line_app" + | "line_height" + | "linear" + | "link" + | "link_2" + | "link_3" + | "linkedin" + | "linux" + | "list_check" + | "list_check_2" + | "list_check_3" + | "list_collapse" + | "list_expansion" + | "list_ordered" + | "list_search" + | "live_location" + | "live_photo" + | "loading" + | "loading_2" + | "loading_3" + | "loading_4" + | "location" + | "location_2" + | "location_3" + | "lock" + | "lollipop" + | "look_down" + | "look_left" + | "look_right" + | "look_up" + | "lotus" + | "love" + | "low_beam_headlights" + | "low_temperature" + | "luggage" + | "magic_1" + | "magic_2" + | "magic_3" + | "magic_hat" + | "magic_hat_2" + | "magnet" + | "mail" + | "mail_open" + | "mail_send" + | "mailbox" + | "male" + | "map" + | "map_2" + | "map_pin" + | "maple_leaf" + | "marina_bay_sand" + | "mark_pen" + | "markdown" + | "markup" + | "mastercard" + | "mastodon" + | "maya_pyramids" + | "medal" + | "medium" + | "menu" + | "message_1" + | "message_2" + | "message_3" + | "message_4" + | "messenger" + | "meta" + | "mic" + | "mic_2" + | "mic_off" + | "mickeymouse" + | "microphone" + | "microscope" + | "middle_finger" + | "midi" + | "mingcute" + | "minimize" + | "miniplayer" + | "minus_circle" + | "mirror" + | "miyajima_torii" + | "moai" + | "moderate_snow" + | "moment" + | "monero" + | "monument" + | "moon" + | "moon_cloudy" + | "moon_fog" + | "moon_stars" + | "moonlight" + | "more_1" + | "more_2" + | "more_3" + | "more_4" + | "mortarboard" + | "mosaic" + | "mouse" + | "mouth" + | "move" + | "movie" + | "multiselect" + | "mushroom" + | "music" + | "music_2" + | "music_3" + | "na" + | "navigation" + | "necktie" + | "new_folder" + | "newdot" + | "news" + | "nintendo_switch" + | "nose" + | "notebook" + | "notebook_2" + | "notification" + | "notification_off" + | "notion" + | "numbers_09_sort_ascending" + | "numbers_09_sort_descending" + | "numbers_90_sort_ascending" + | "numbers_90_sort_descending" + | "octagon" + | "oil" + | "omega" + | "omg" + | "open_door" + | "openai" + | "package" + | "package_2" + | "pad" + | "paint" + | "paint_2" + | "paint_brush" + | "palace" + | "palette" + | "palette_2" + | "panoramas" + | "paper" + | "parachute" + | "paragraph" + | "parentheses" + | "park" + | "parking" + | "parking_lights" + | "partly_cloud_daytime" + | "partly_cloud_night" + | "passport" + | "paster" + | "pause" + | "pause_circle" + | "pavilion" + | "paw" + | "paypal" + | "pdf" + | "pen" + | "pen_2" + | "pencil" + | "pencil_2" + | "pencil_ruler" + | "pentagon" + | "performance" + | "phone" + | "phone_add" + | "phone_block" + | "phone_call" + | "phone_incoming" + | "phone_off" + | "phone_outgoing" + | "phone_success" + | "photo_album" + | "photo_album_2" + | "pic" + | "pic_2" + | "pickax" + | "pig" + | "pig_money" + | "pin" + | "pin_2" + | "pingpong" + | "pinterest" + | "pinwheel" + | "pinwheel_2" + | "pisa_tower" + | "planet" + | "play" + | "play_circle" + | "playground" + | "playlist" + | "playlist_2" + | "plugin" + | "plugin_2" + | "plus" + | "polkadot_DOT" + | "polygon" + | "pot" + | "power" + | "ppt" + | "pray" + | "presentation_1" + | "presentation_2" + | "print" + | "process" + | "profile" + | "pumpkin" + | "pumpkin_lantern" + | "puzzled" + | "qq" + | "qrcode" + | "qrcode_2" + | "question" + | "quill_pen" + | "quote_left" + | "quote_right" + | "rabbit" + | "radar" + | "radar_2" + | "radio" + | "rain" + | "rainbow" + | "rainstorm" + | "rake" + | "rare_fog_lights" + | "react" + | "rear_windshield_defroster" + | "receive_money" + | "record_mail" + | "recycle" + | "red_packet" + | "red_packet_open" + | "reddit" + | "refresh_1" + | "refresh_2" + | "refresh_3" + | "refresh_4" + | "refresh_anticlockwise_1" + | "refund_cny" + | "refund_dollar" + | "registered" + | "remote" + | "repeat" + | "repeat_one" + | "report" + | "report_forms" + | "rest_area" + | "restore" + | "riding" + | "right" + | "right_small" + | "road" + | "rocket" + | "rocket_2" + | "rotate_to_horizontal" + | "rotate_to_vertical" + | "rotate_x" + | "rotate_y" + | "round" + | "route" + | "router_modem" + | "rows_2" + | "rows_3" + | "rows_4" + | "rss" + | "rss_2" + | "rudder" + | "ruler" + | "run" + | "sad" + | "safari" + | "safe_alert" + | "safe_box" + | "safe_flash" + | "safe_lock" + | "safe_shield" + | "safe_shield_2" + | "safety_certificate" + | "sailboat" + | "sale" + | "sandglass" + | "sandstorm" + | "save" + | "save_2" + | "scale" + | "scan" + | "scan_2" + | "scarf" + | "schedule" + | "school" + | "science" + | "scissors" + | "scissors_2" + | "scissors_3" + | "scooter" + | "screenshot" + | "seal" + | "search" + | "search_2" + | "search_3" + | "seat" + | "seat_heated" + | "selector_horizontal" + | "selector_vertical" + | "send" + | "send_plane" + | "server" + | "server_2" + | "service" + | "settings_1" + | "settings_2" + | "settings_3" + | "settings_4" + | "settings_5" + | "settings_6" + | "settings_7" + | "shadow" + | "share_2" + | "share_3" + | "share_forward" + | "shield" + | "shield_shape" + | "ship" + | "shirt" + | "shoe" + | "shoe_2" + | "shopping_bag_1" + | "shopping_bag_2" + | "shopping_bag_3" + | "shopping_cart_1" + | "shopping_cart_2" + | "shorts" + | "shovel" + | "showers" + | "shuffle" + | "shuffle_2" + | "sick" + | "signal" + | "signature" + | "silent" + | "sitemap" + | "skateboard" + | "skip_forward" + | "skip_previous" + | "skirt" + | "skull" + | "sleep" + | "sleigh" + | "snapchat" + | "snow" + | "snowflake" + | "snowman" + | "snowstorm" + | "snowstorm_2" + | "sob" + | "social_x" + | "sock" + | "sofa" + | "solana_SOL" + | "sort_ascending" + | "sort_descending" + | "space" + | "spacing_horizontal" + | "spacing_vertical" + | "spade" + | "sparkles" + | "sparkles_2" + | "speaker" + | "speech" + | "spoon" + | "spotify" + | "square" + | "square_arrow_down" + | "square_arrow_left" + | "square_arrow_right" + | "square_arrow_up" + | "star" + | "star_2" + | "star_half" + | "statue_of_liberty" + | "steering_wheel" + | "sticker" + | "stock" + | "stop" + | "stop_circle" + | "stopwatch" + | "store" + | "store_2" + | "strikethrough" + | "stripe" + | "sugar_coated_haws" + | "suitcase" + | "suitcase_2" + | "sun" + | "sun_2" + | "sun_cloudy" + | "sun_fog" + | "sunrise" + | "sunset" + | "surfboard" + | "surprise" + | "sweats" + | "swimming_pool" + | "switch" + | "sword" + | "sydney_opera_house" + | "t_shirt" + | "t_shirt_2" + | "table" + | "table_2" + | "table_3" + | "tag" + | "tag_2" + | "tag_chevron" + | "taipei101" + | "taj_mahal" + | "tank" + | "target" + | "task" + | "task_2" + | "teacup" + | "telegram" + | "telescope" + | "telescope_2" + | "temple_of_heaven" + | "tent" + | "terminal" + | "terminal_box" + | "terror" + | "tether_USDT" + | "text" + | "text_2" + | "text_color" + | "textbox" + | "thermometer" + | "thought" + | "threads" + | "thumb_down" + | "thumb_down_2" + | "thumb_up" + | "thumb_up_2" + | "thunderstorm" + | "ticket" + | "tiktok" + | "time" + | "to_do" + | "toggle_left" + | "toggle_left_2" + | "toggle_right" + | "toggle_right_2" + | "toilet_paper" + | "tongue" + | "tool" + | "tornado" + | "tornado_2" + | "tower" + | "tower_crane" + | "toxophily" + | "toy_horse" + | "traffic_cone" + | "traffic_lights" + | "train" + | "train_2" + | "train_3" + | "train_4" + | "transfer" + | "transfer_2" + | "transfer_3" + | "transfer_4" + | "transfer_horizontal" + | "transfer_vertical" + | "transformation" + | "translate" + | "translate_2" + | "tree" + | "tree_2" + | "tree_3" + | "tree_4" + | "trello_board" + | "trending_down" + | "trending_up" + | "triangle" + | "triumphal_arch" + | "trophy" + | "trouser" + | "truck" + | "trunk" + | "tunnel" + | "tv_1" + | "tv_2" + | "twitter" + | "typhoon" + | "tyre" + | "umbrella" + | "umbrella_2" + | "unarchive" + | "underline" + | "unfold_horizontal" + | "unfold_vertical" + | "unhappy" + | "unhappy_dizzy" + | "unlink" + | "unlink_2" + | "unlock" + | "up" + | "up_small" + | "upload" + | "upload_2" + | "upload_3" + | "usb" + | "usb_flash_disk" + | "usd_coin_USDC" + | "user_1" + | "user_2" + | "user_3" + | "user_4" + | "user_5" + | "user_add" + | "user_add_2" + | "user_edit" + | "user_follow" + | "user_follow_2" + | "user_forbid" + | "user_heart" + | "user_hide" + | "user_info" + | "user_lock" + | "user_pin" + | "user_question" + | "user_remove" + | "user_remove_2" + | "user_search" + | "user_security" + | "user_setting" + | "user_star" + | "user_visible" + | "user_warning" + | "user_x" + | "vector_bezier" + | "vector_bezier_2" + | "vector_bezier_3" + | "vector_group" + | "version" + | "vest" + | "viber_messenger" + | "video" + | "virus" + | "visa" + | "vison_pro" + | "vkontakte" + | "voice" + | "voice_2" + | "volleyball" + | "volume" + | "volume_mute" + | "volume_off" + | "vue" + | "walk" + | "wallet" + | "wallet_2" + | "wallet_3" + | "wallet_4" + | "wallet_5" + | "wardrobe" + | "wardrobe_2" + | "warning" + | "wash_machine" + | "wastebasket" + | "watch" + | "watch_2" + | "wave" + | "web" + | "wechat" + | "wechat_miniprogram" + | "wechat_pay" + | "weibo" + | "wet" + | "whatsapp" + | "wheel" + | "wifi" + | "wifi_off" + | "wind" + | "windows" + | "wine" + | "wineglass" + | "wineglass_2" + | "wiper" + | "world" + | "world_2" + | "wreath" + | "x_skew" + | "xbox" + | "xls" + | "y_skew" + | "yinyang" + | "youtube" + | "yuanbao" + | "zoom_in" + | "zoom_out" diff --git a/apps/zui/src/components/input-button.tsx b/apps/zui/src/components/input-button.tsx index 9aaffa0ad9..5be7ae3d0d 100644 --- a/apps/zui/src/components/input-button.tsx +++ b/apps/zui/src/components/input-button.tsx @@ -1,6 +1,6 @@ import classNames from "classnames" import React, {ReactNode} from "react" -import Icon, {IconName} from "src/app/core/icon-temp" +import {Icon, IconName} from "src/components/icon" import styled from "styled-components" const Button = styled.button` @@ -53,7 +53,7 @@ export function InputButton( })} {...(buttonProps as any)} > - {icon && } + {icon && } {children} ) diff --git a/apps/zui/src/components/list-item.tsx b/apps/zui/src/components/list-item.tsx index a37315b01e..5ab00b779d 100644 --- a/apps/zui/src/components/list-item.tsx +++ b/apps/zui/src/components/list-item.tsx @@ -1,9 +1,9 @@ import classNames from "classnames" import React from "react" import {ReactNode} from "react-markdown" -import Icon, {IconName} from "src/app/core/icon-temp" -import {BuiltMenu} from "src/core/menu" +import {Icon, IconName} from "src/components/icon" import {IconButton} from "./icon-button" +import {MenuItem} from "src/core/menu" export function ListItem(props: { className?: string @@ -19,7 +19,7 @@ export function ListItem(props: { isSelected?: boolean isDragging?: boolean isOverFolder?: boolean - menu?: BuiltMenu + menu?: MenuItem[] }) { const indentation = 16 let left = (props.indent ?? 0) * indentation @@ -43,7 +43,7 @@ export function ListItem(props: { "list-item__toggle--open": props.isOpen, })} click={() => props.onToggle()} - iconName="chevron-right" + iconName="chevron_right" iconSize={14} /> )} @@ -51,12 +51,12 @@ export function ListItem(props: { )}
{props.children}
- {props.menu.items.map((item, i) => { + {props.menu.map((item, i) => { if (!item.visible) return null return ( diff --git a/apps/zui/src/components/modals.module.css b/apps/zui/src/components/modals.module.css index 919d83613f..55c4f45e58 100644 --- a/apps/zui/src/components/modals.module.css +++ b/apps/zui/src/components/modals.module.css @@ -1,18 +1,29 @@ .modal { - background: white; + background: var(--bg-color); box-shadow: 0 20px 50px 10px rgb(0 0 0 /0.25); border-radius: 8px; border: none; padding: 0; will-change: opacity, transform; + color: var(--fg-color); } .modal::backdrop { background-color: black; - opacity: 0.4; + opacity: 0.25; will-change: opacity; } +@media (prefers-color-scheme: dark) { + .modal::backdrop { + opacity: 0.8; + } + + .modal { + border: 1px solid var(--border-color); + } +} + .modal .form { padding: 0 30px 30px 30px; width: 360px; diff --git a/apps/zui/src/components/more-items-button.tsx b/apps/zui/src/components/more-items-button.tsx index c8cf47fb78..27f28813c8 100644 --- a/apps/zui/src/components/more-items-button.tsx +++ b/apps/zui/src/components/more-items-button.tsx @@ -1,5 +1,5 @@ import React, {forwardRef} from "react" -import {BuiltMenu, MenuItem} from "src/core/menu" +import {MenuItem, showMenu} from "src/core/menu" import {IconButton} from "./icon-button" export const MoreItemsButton = forwardRef( @@ -7,13 +7,9 @@ export const MoreItemsButton = forwardRef( return ( { - new BuiltMenu({id: "more-items"}, props.items).showUnder( - e.currentTarget - ) - }} + onClick={(e) => showMenu(props.items, e.currentTarget)} /> ) } diff --git a/apps/zui/src/components/section-tabs.tsx b/apps/zui/src/components/section-tabs.tsx index 93763305c4..f429677a1a 100644 --- a/apps/zui/src/components/section-tabs.tsx +++ b/apps/zui/src/components/section-tabs.tsx @@ -31,7 +31,7 @@ const Nav = styled.nav` text-transform: uppercase; font-weight: 500; - font-size: 11px; + font-size: 12px; opacity: 0.5; &:hover:not([aria-pressed="true"]) { diff --git a/apps/zui/src/components/toolbar-tabs.module.css b/apps/zui/src/components/toolbar-tabs.module.css index 13cda2b9ae..41c18a2a70 100644 --- a/apps/zui/src/components/toolbar-tabs.module.css +++ b/apps/zui/src/components/toolbar-tabs.module.css @@ -13,9 +13,11 @@ min-width: 0; padding: 2px; height: 100%; + gap: 0.25rem; } .button { + white-space: nowrap; background: none; border: none; user-select: none; @@ -29,22 +31,22 @@ font-size: 11px; letter-spacing: 0.1px; z-index: 1; - color: var(--foreground-color-light); + color: var(--fg-color-less); transition: all 200ms; height: 100%; } .button:hover:not([aria-pressed="true"]):not(:disabled) { - background: var(--hover-dark); - color: var(--foreground-color); + background: var(--emphasis-bg-less); + color: var(--fg-color); } .button:active:not([aria-pressed="true"]):not(:disabled) { - background: var(--active-dark); + background: var(--emphasis-bg); } .button[aria-pressed="true"] { - color: var(--foreground-color); + color: var(--fg-color); } .button:disabled { @@ -58,7 +60,7 @@ } .selection { - background: white; + background: var(--selected-bg); border-radius: 5px; position: absolute; top: 2px; diff --git a/apps/zui/src/components/toolbar-tabs.tsx b/apps/zui/src/components/toolbar-tabs.tsx index 321ac0f798..440f265fef 100644 --- a/apps/zui/src/components/toolbar-tabs.tsx +++ b/apps/zui/src/components/toolbar-tabs.tsx @@ -1,9 +1,14 @@ import React, {useLayoutEffect, useRef, useState} from "react" import {MenuItem} from "src/core/menu" import styles from "./toolbar-tabs.module.css" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" +import {call} from "src/util/call" -export function ToolbarTabs(props: {onlyIcon: boolean; options: MenuItem[]}) { +export function ToolbarTabs(props: { + onlyIcon?: boolean + labelClassName?: string + options: MenuItem[] +}) { const changeCount = useRef(0) const ref = useRef() const [pos, setPos] = useState({x: 0, width: 10}) @@ -30,18 +35,22 @@ export function ToolbarTabs(props: {onlyIcon: boolean; options: MenuItem[]}) { diff --git a/apps/zui/src/components/toolbar.tsx b/apps/zui/src/components/toolbar.tsx index 49de29f9a7..72a9562f90 100644 --- a/apps/zui/src/components/toolbar.tsx +++ b/apps/zui/src/components/toolbar.tsx @@ -1,8 +1,7 @@ import styled from "styled-components" export const Toolbar = styled.div<{reverse?: boolean}>` - background: var(--chrome-color); - border-bottom: 1px solid var(--border-color); + border-bottom: 1px solid var(--border-color-more); display: flex; flex-direction: ${(props) => (props.reverse ? "row-reverse" : "row")}; align-items: center; diff --git a/apps/zui/src/components/tooltip.module.css b/apps/zui/src/components/tooltip.module.css new file mode 100644 index 0000000000..458ab5dce3 --- /dev/null +++ b/apps/zui/src/components/tooltip.module.css @@ -0,0 +1,17 @@ +.tooltip { + position: fixed; + top: 0; + right: 0; + padding-inline: 0.5rem; + padding-block: 0.1rem; + background: var(--bg-color); + border-radius: 3px; + width: fit-content; + z-index: 999; + pointer-events: none; + max-inline-size: var(--measure); + border: 1px solid var(--border-color-more); + box-shadow: + hsl(212 20% 10% / 0.25) 0 1px 3px -1px, + hsl(0 0% 0% / 0.21) 0 2px 10px -1px; +} diff --git a/apps/zui/src/components/tooltip.tsx b/apps/zui/src/components/tooltip.tsx new file mode 100644 index 0000000000..c3263360df --- /dev/null +++ b/apps/zui/src/components/tooltip.tsx @@ -0,0 +1,55 @@ +import {useRef, useState} from "react" +import useListener from "../js/components/hooks/useListener" +import {Debut, useDebut} from "./debut" +import styles from "./tooltip.module.css" +import {useFixedPosition} from "src/util/hooks/use-fixed-position" +import {findAncestor} from "src/util/find-ancestor" + +const attr = "data-tooltip" + +export function Tooltip() { + const [title, setTitle] = useState(null) + const [anchor, setAnchor] = useState(null) + const ref = useRef() + + function set(node: Element) { + debut.cancelExit() + setAnchor(node) + setTitle(node.getAttribute(attr)) + } + + function reset() { + setAnchor(null) + setTitle(null) + } + + function needsTooltip(node: Element) { + return node.matches(`[${attr}]`) + } + + const debut = useDebut({afterExit: reset}) + + useListener(document.body, "mouseover", (e: any) => { + const node = findAncestor(e.target, needsTooltip) + if (node) set(node) + else debut.exit() + }) + + const style = useFixedPosition({ + targetRef: ref, + anchor: anchor, + anchorPoint: "bottom center", + targetPoint: "top center", + targetMargin: "3px", + overflow: "flip", + }) + + if (!anchor) return null + return ( + +
+ {title} +
+
+ ) +} diff --git a/apps/zui/src/app/query-home/search-area/zed-editor.tsx b/apps/zui/src/components/zed-editor.tsx similarity index 88% rename from apps/zui/src/app/query-home/search-area/zed-editor.tsx rename to apps/zui/src/components/zed-editor.tsx index 81d07cb621..d04bcde4a8 100644 --- a/apps/zui/src/app/query-home/search-area/zed-editor.tsx +++ b/apps/zui/src/components/zed-editor.tsx @@ -3,6 +3,7 @@ import {useEffect, useRef} from "react" import {useSelector} from "react-redux" import {cmdOrCtrl} from "src/app/core/utils/keyboard" import Config from "src/js/state/Config" +import {useColorScheme} from "src/util/hooks/use-color-scheme" /** * @@ -31,6 +32,7 @@ export function ZedEditor(props: { autoFocus?: boolean }) { const ref = useRef() + const {isDark} = useColorScheme() // Keep this thing in focus as much as possible. // Probably want to move this into parent. @@ -52,13 +54,15 @@ export function ZedEditor(props: { value={props.value} onChange={props.onChange} language="zed" + theme={isDark ? "vs-dark" : "vs-light"} options={{ minimap: {enabled: false}, - renderLineHighlightOnlyWhenFocus: true, + renderLineHighlight: "none", renderControlCharacters: false, fontSize: "14px", fontFamily: "var(--mono-font)", fontVariations: "inherit", + lineNumbersMinChars: 4, }} onMount={(editor) => { ref.current = editor diff --git a/apps/zui/src/components/zed-table/cell-component.tsx b/apps/zui/src/components/zed-table/cell-component.tsx index f6f062889c..1da2dc57d3 100644 --- a/apps/zui/src/components/zed-table/cell-component.tsx +++ b/apps/zui/src/components/zed-table/cell-component.tsx @@ -44,6 +44,7 @@ export const Cell = React.memo(function Cell({ return (
{}, - onContextMenu: (...args) => - api.args.cellProps.onContextMenu(...args, this), + onContextMenu: (...args) => { + args[0].stopPropagation() + api.args.cellProps.onContextMenu(...args, this) + }, viewIdPrefix: `${this.id}_val:`, onDidChange: () => { api.cellChanged(this) diff --git a/apps/zui/src/components/zed-table/column.ts b/apps/zui/src/components/zed-table/column.ts index e7686f42e7..51f648422f 100644 --- a/apps/zui/src/components/zed-table/column.ts +++ b/apps/zui/src/components/zed-table/column.ts @@ -12,7 +12,7 @@ type Args = { parent?: ZedColumn } -const helper = createColumnHelper() +const helper = createColumnHelper() export class ZedColumn { children: null | ZedColumn[] @@ -66,7 +66,7 @@ export class ZedColumn { get leafDef() { return helper.accessor( - (row: zed.Any) => { + (row: zed.Type) => { if (row instanceof zed.Record) return row.fieldAt(this.args.indexPath) else { return row diff --git a/apps/zui/src/components/zed-table/config.ts b/apps/zui/src/components/zed-table/config.ts index aa48777f81..50b853cf9a 100644 --- a/apps/zui/src/components/zed-table/config.ts +++ b/apps/zui/src/components/zed-table/config.ts @@ -4,5 +4,4 @@ export const config = { headerHeight: 34, defaultCellWidth: 80, maxCellAutoWidth: 700, - placeholderHeaderHeight: 28, } diff --git a/apps/zui/src/components/zed-table/header-cell.tsx b/apps/zui/src/components/zed-table/header-cell.tsx index e6d1e4d9d7..01a0ffd4de 100644 --- a/apps/zui/src/components/zed-table/header-cell.tsx +++ b/apps/zui/src/components/zed-table/header-cell.tsx @@ -1,7 +1,7 @@ import {Header} from "@tanstack/react-table" import classNames from "classnames" import React from "react" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import {ZedColumn} from "./column" import {useZedTable} from "./context" import {HeaderResizeArea} from "./header-resize-area" @@ -35,10 +35,10 @@ export function HeaderCell({header}: {header: Header}) { {column.isSortedAsc && width > 75 && ( - + )} {column.isSortedDesc && width > 75 && ( - + )}
@@ -53,7 +53,7 @@ export function HeaderCell({header}: {header: Header}) { ) } > - + )} diff --git a/apps/zui/src/components/zed-table/types.ts b/apps/zui/src/components/zed-table/types.ts index 112ddef84f..37181f0053 100644 --- a/apps/zui/src/components/zed-table/types.ts +++ b/apps/zui/src/components/zed-table/types.ts @@ -31,7 +31,6 @@ export type ZedTableProps = { } & ZedTableHandlers export type ZedTableHandlers = { - onStateChange: (nextState: ZedTableState) => void onScrollNearBottom: () => void onHeaderContextMenu: (e: React.MouseEvent, column: ZedColumn) => void onValueContextMenu: ( diff --git a/apps/zui/src/core/command.ts b/apps/zui/src/core/command.ts deleted file mode 100644 index 005535af5f..0000000000 --- a/apps/zui/src/core/command.ts +++ /dev/null @@ -1,53 +0,0 @@ -type CommandMeta = { - id: string -} - -type CommandExecutor = ( - ...args: Args -) => Return | Promise - -export class CommandCenter { - private map = new Map>() - - add(command: Command) { - this.map.set(command.id, command) - return command - } - - get(id: string) { - const c = this.map.get(id) - if (!c) throw new Error("Command Not Found: " + id) - return c - } - - create(id: string, exec: (...args: Args) => any) { - this.add(new Command({id}, exec)) - } -} - -export const commands = new CommandCenter() - -export class Command { - constructor( - private meta: CommandMeta, - private exec: CommandExecutor - ) {} - - get id() { - return this.meta.id - } - - run(...args: Args) { - return this.exec(...args) - } -} - -export const createCommand = ( - meta: CommandMeta | string, - exec: CommandExecutor -) => { - const cmdMeta = typeof meta === "string" ? {id: meta} : meta - const cmd = new Command(cmdMeta, exec) - commands.add(cmd) - return cmd -} diff --git a/apps/zui/src/core/handlers.ts b/apps/zui/src/core/handlers.ts index 94d9ffe17a..7ea7de99bf 100644 --- a/apps/zui/src/core/handlers.ts +++ b/apps/zui/src/core/handlers.ts @@ -3,12 +3,16 @@ import {HandlerName} from "src/domain/messages" import {invoke} from "./invoke" import toast from "react-hot-toast" import {isFunction, isString} from "lodash" +import ZuiApi from "src/js/api/zui-api" +import {startTransition} from "react" export type HandlerContext = { dispatch: AppDispatch select any>(selector: Fn): ReturnType invoke: typeof invoke toast: typeof toast + oldApi: ZuiApi + transition: typeof startTransition } let context: HandlerContext | null = null diff --git a/apps/zui/src/core/menu/built-menu.ts b/apps/zui/src/core/menu/built-menu.ts deleted file mode 100644 index 7ffbd562df..0000000000 --- a/apps/zui/src/core/menu/built-menu.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {MenuItemConstructorOptions} from "electron" -import {menus} from "./global-menus" -import {Menu} from "./menu" -import {popupPosition} from "./popup-position" -import {showContextMenu} from "./show-context-menu" -import {MenuInfo, MenuItem} from "./types" - -export class BuiltMenu { - constructor(public info: MenuInfo, public template: MenuItem[]) {} - - get items() { - return this.template - } - - get label() { - return this.info.label ?? this.info.id - } - - show() { - showContextMenu(this.toElectron()) - } - - showUnder(target: HTMLElement) { - showContextMenu(this.toElectron(), popupPosition(target)) - } - - toElectron(): MenuItemConstructorOptions[] { - return this.template.map((opt) => { - const {nestedMenu, checked, ...rest} = opt - let option: MenuItemConstructorOptions = {...(rest as any)} - if (nestedMenu) { - if (nestedMenu instanceof Menu) { - option.submenu = menus.build(nestedMenu.id) - } - } - if (checked !== undefined) { - option.type = "checkbox" - option.checked = checked - } - return option - }) - } -} diff --git a/apps/zui/src/core/menu/create-menu.ts b/apps/zui/src/core/menu/create-menu.ts index 786fa1e47b..f133f10c2d 100644 --- a/apps/zui/src/core/menu/create-menu.ts +++ b/apps/zui/src/core/menu/create-menu.ts @@ -1,12 +1,25 @@ -import {menus} from "./global-menus" -import {Menu} from "./menu" -import {MenuBuilder} from "./types" - -export function createMenu( - id: string, - builder: MenuBuilder -) { - const menu = new Menu(id, builder) - menus.add(menu) - return menu +import ZuiApi from "src/js/api/zui-api" +import {MenuItem} from "./types" + +export type MenuContext = { + api: ZuiApi // deprecated + select any>(selector: Fn): ReturnType +} + +let context: MenuContext | null = null + +export function setMenuContext(ctx: MenuContext) { + context = ctx +} + +type Builder = ( + context: MenuContext, + ...args: Args +) => MenuItem[] + +export function createMenu(builder: Builder) { + function build(...args: Args) { + return builder(context, ...args) + } + return build } diff --git a/apps/zui/src/core/menu/global-menus.ts b/apps/zui/src/core/menu/global-menus.ts deleted file mode 100644 index 38ca19dc0c..0000000000 --- a/apps/zui/src/core/menu/global-menus.ts +++ /dev/null @@ -1,4 +0,0 @@ -import ZuiApi from "src/js/api/zui-api" -import {MenuManager} from "./menu-manager" - -export const menus = new MenuManager<{api: ZuiApi}>() diff --git a/apps/zui/src/core/menu/handle-click.ts b/apps/zui/src/core/menu/handle-click.ts new file mode 100644 index 0000000000..fa359c0453 --- /dev/null +++ b/apps/zui/src/core/menu/handle-click.ts @@ -0,0 +1,15 @@ +import {invoke} from "../invoke" +import {showMenu} from "./show-context-menu" +import {MenuItem} from "./types" + +export function handleClick(item: MenuItem, anchor?: HTMLElement) { + if (item.command) { + const name = item.command + const args = item.args || [] + invoke("commands.run", name, ...args) + } else if (item.click) { + item.click() + } else if (item.nestedMenu) { + showMenu(item.nestedMenu, anchor) + } +} diff --git a/apps/zui/src/core/menu/index.ts b/apps/zui/src/core/menu/index.ts index 2168af6396..b3c18f18c8 100644 --- a/apps/zui/src/core/menu/index.ts +++ b/apps/zui/src/core/menu/index.ts @@ -1,5 +1,4 @@ export * from "./types" export * from "./create-menu" -export * from "./menu" -export * from "./built-menu" -export * from "./global-menus" +export * from "./show-context-menu" +export * from "./use-menu-extension" diff --git a/apps/zui/src/core/menu/menu-manager.ts b/apps/zui/src/core/menu/menu-manager.ts deleted file mode 100644 index c064780728..0000000000 --- a/apps/zui/src/core/menu/menu-manager.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {Menu} from "./menu" - -export class MenuManager { - map = new Map>() - ctx: Context | null = null - - get context() { - if (this.ctx) return this.ctx - throw new Error("First provide a context before building a menu") - } - - setContext(ctx: Context) { - this.ctx = ctx - } - - add(menu: Menu) { - this.map.set(menu.id, menu) - } - - get(id: string) { - return this.map.get(id) - } - - build(id: string, ...args: any[]) { - const menu = this.map.get(id) - if (menu) { - return menu.build(...args).toElectron() - } else { - throw new Error("No menu with id: " + id) - } - } -} diff --git a/apps/zui/src/core/menu/menu-node.ts b/apps/zui/src/core/menu/menu-node.ts deleted file mode 100644 index e903796170..0000000000 --- a/apps/zui/src/core/menu/menu-node.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {sendToFocusedWindow} from "../ipc" -import {MenuItem} from "./types" - -class MenusApi { - private menus: Map - - constructor() { - this.menus = new Map() - } - - get(name: string) { - const menu = this.menus.get(name) - if (!menu) throw new Error("Could not find menu with name: " + name) - return menu - } - - add(menu: MenuApi) { - this.menus.set(menu.name, menu) - } - - extend(name: string, items: MenuItem[]) { - this.get(name).concat(items) - } -} -class MenuApi { - constructor(public name: string, public template: MenuItem[]) {} - - update(id: string, props: Partial) { - sendToFocusedWindow("menus.update", this.name, id, props) - } - - concat(items: MenuItem[]) { - this.template = this.template.concat(items) - } -} - -export const menus = new MenusApi() - -export function createMenu(id: string, template: MenuItem[]) { - const menu = new MenuApi(id, template) - menus.add(menu) - return menus -} diff --git a/apps/zui/src/core/menu/menu.ts b/apps/zui/src/core/menu/menu.ts deleted file mode 100644 index c4a953e81f..0000000000 --- a/apps/zui/src/core/menu/menu.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {BuiltMenu} from "./built-menu" -import {menus as globalMenus} from "./global-menus" -import {MenuBuilder} from "./types" - -export class Menu { - constructor(public id: string, private builder: MenuBuilder) {} - - build(...args: Args) { - return new BuiltMenu( - {id: this.id}, - this.builder(globalMenus.context, ...args) - ) - } -} diff --git a/apps/zui/src/core/menu/show-context-menu.ts b/apps/zui/src/core/menu/show-context-menu.ts index 1a68875402..0411e0a739 100644 --- a/apps/zui/src/core/menu/show-context-menu.ts +++ b/apps/zui/src/core/menu/show-context-menu.ts @@ -2,11 +2,23 @@ import {MenuItemConstructorOptions} from "electron" import {BoundCommand} from "src/app/commands/command" import {invoke} from "src/core/invoke" import {MenuItem} from "./types" +import {toElectron} from "./to-electron" +import {popupPosition} from "./popup-position" +import {handleClick} from "./handle-click" + +export function showMenu(menu: MenuItem[], target?: HTMLElement) { + if (target) { + showContextMenu(menu, popupPosition(target)) + } else { + showContextMenu(menu) + } +} export function showContextMenu( - template: MenuItemConstructorOptions[], + items: MenuItem[], opts: {x?: number; y?: number; callback?: () => void} = {} ) { + const template = toElectron(items) if (global.env.isIntegrationTest) { document.dispatchEvent( new CustomEvent("nativeContextMenu", {detail: template}) @@ -49,17 +61,8 @@ function findItem(id: string, template: MenuItemConstructorOptions[]) { function setupListener(template, callback) { global.zui.once("contextMenuResult", (e, id: string) => { const item = findItem(id, template) as unknown as MenuItem - if (item && "click" in item) { - // @ts-ignore - item.click() - } else if ( - item && - "command" in item && - item.command instanceof BoundCommand - ) { - item.command.run() - } else if (item && "command" in item && typeof item.command === "string") { - invoke("invokeCommandOp", item.command, item.args) + if (item) { + handleClick(item) } callback && callback() }) diff --git a/apps/zui/src/core/menu/to-electron.ts b/apps/zui/src/core/menu/to-electron.ts new file mode 100644 index 0000000000..2f8a7fa64f --- /dev/null +++ b/apps/zui/src/core/menu/to-electron.ts @@ -0,0 +1,18 @@ +import {MenuItemConstructorOptions} from "electron" +import {MenuItem} from "./types" + +export function toElectron(menu: MenuItem[]) { + return menu.map((opt) => { + const {nestedMenu, checked, ...rest} = opt + // add items here + let option: MenuItemConstructorOptions = {...(rest as any)} + if (nestedMenu) { + option.submenu = toElectron(nestedMenu) + } + if (checked !== undefined) { + option.type = "checkbox" + option.checked = checked + } + return option + }) +} diff --git a/apps/zui/src/core/menu/types.ts b/apps/zui/src/core/menu/types.ts index 3ede642b8b..3f88f8957c 100644 --- a/apps/zui/src/core/menu/types.ts +++ b/apps/zui/src/core/menu/types.ts @@ -1,10 +1,10 @@ -import {IconName} from "src/app/core/icon-temp" -import ZuiApi from "src/js/api/zui-api" -import {Menu} from "./menu" -import {BoundCommand} from "src/app/commands/command" +import {IconName} from "src/components/icon" import {MenuItemConstructorOptions} from "electron" +import {HandlerName} from "src/domain/messages" export type MenuItem = { + role?: string + type?: string id?: string display?: "icon" | "icon-label" label?: string @@ -13,10 +13,9 @@ export type MenuItem = { visible?: boolean iconName?: IconName iconSize?: number - // Moving away from the bound command pattern - command?: string | BoundCommand + command?: HandlerName args?: any[] - nestedMenu?: Menu + nestedMenu?: MenuItem[] checked?: boolean htmlAttrs?: any when?: string @@ -25,15 +24,3 @@ export type MenuItem = { accelerator?: MenuItemConstructorOptions["accelerator"] click?: () => void } - -export type MenuContext = {api: ZuiApi} - -export type MenuBuilder = ( - ctx: MenuContext, - ...args: Args -) => MenuItem[] - -export type MenuInfo = { - id: string - label?: string -} diff --git a/apps/zui/src/core/menu/use-menu-extension.ts b/apps/zui/src/core/menu/use-menu-extension.ts new file mode 100644 index 0000000000..cb686de20a --- /dev/null +++ b/apps/zui/src/core/menu/use-menu-extension.ts @@ -0,0 +1,49 @@ +import {useEffect, useLayoutEffect, useState} from "react" +import {MenuItem} from "src/core/menu" +import {compile} from "../when/compile" +import {invoke} from "../invoke" +import {useTabId} from "src/app/core/hooks/use-tab-id" + +export function useMenuExtension( + name: string, + menuItems: MenuItem[], + whenContext: object +) { + const [items, setItems] = useState(menuItems) + const tabId = useTabId() + + useLayoutEffect(() => { + invoke("menus.extend", name, menuItems) + .then((extended) => compileMenuItems(extended, whenContext)) + .then((compiled) => setItems(compiled)) + }, [name, menuItems, whenContext, tabId]) + + useEffect(() => { + return global.zui.on("menus.update", (e, menu, id, update) => { + if (menu !== name) return + setItems( + items.map((item: MenuItem) => { + return item.id === id ? {...item, ...update} : item + }) + ) + }) + }, [items, name]) + + return items +} + +function compileMenuItems(items: MenuItem[], context: Record) { + return items + .map((item) => { + return { + ...item, + whenResult: compile(item.when, context), + priority: item.priority ?? 0, + } + }) + .sort((a, b) => { + if (a.priority > b.priority) return -1 + if (a.priority < b.priority) return 1 + return 0 + }) +} diff --git a/apps/zui/src/core/menu/use-menu-instance.ts b/apps/zui/src/core/menu/use-menu-instance.ts deleted file mode 100644 index 96660bc18d..0000000000 --- a/apps/zui/src/core/menu/use-menu-instance.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {useLayoutEffect, useMemo} from "react" -import {useSelector} from "react-redux" -import {useDispatch} from "src/app/core/state" -import ResultsToolbarMenu from "src/js/state/ResultsToolbar" -import {BuiltMenu, MenuItem} from "src/core/menu" -import {createSelector} from "@reduxjs/toolkit" -import Layout from "src/js/state/Layout" -import {compile} from "../when/compile" -import {invoke} from "../invoke" -import {useTabId} from "src/app/core/hooks/use-tab-id" - -/** - * 1. get the items from redux - * 2. get the template from main - * 3. set redux to match the template - * 4. return a new build menu with the items from redux - */ - -function setMenu(name: string, items: MenuItem[]) { - switch (name) { - case "results.toolbarMenu": - return ResultsToolbarMenu.set(items) - } -} - -export function useMenuInstance(name: string) { - const dispatch = useDispatch() - const items = useSelector(ResultsToolbarMenu.get) - const whenContext = useSelector(getWhenContext) - const tabId = useTabId() - - useLayoutEffect(() => { - invoke("getMenuTemplateOp", name).then((template) => { - const items = compileMenuItems(template, whenContext) - dispatch(setMenu(name, items)) - }) - }, [whenContext, tabId]) - - return useMemo(() => new BuiltMenu({id: name}, items), [items]) -} - -const getWhenContext = createSelector(Layout.getResultsView, (resultsView) => { - return { - "results.view": resultsView.toLowerCase(), - } -}) - -function compileMenuItems(items: MenuItem[], context: Record) { - return items - .map((item) => { - return { - ...item, - whenResult: compile(item.when, context), - priority: item.priority ?? 0, - } - }) - .sort((a, b) => { - if (a.priority > b.priority) return -1 - if (a.priority < b.priority) return 1 - return 0 - }) -} diff --git a/apps/zui/src/css/_about-window.scss b/apps/zui/src/css/_about-window.scss index ab29b0dd58..6746e3eeca 100644 --- a/apps/zui/src/css/_about-window.scss +++ b/apps/zui/src/css/_about-window.scss @@ -27,7 +27,7 @@ } a { - color: var(--havelock); + color: var(--primary-color); cursor: pointer; } diff --git a/apps/zui/src/css/_buttons.scss b/apps/zui/src/css/_buttons.scss index 04ab336698..1e5c881a50 100644 --- a/apps/zui/src/css/_buttons.scss +++ b/apps/zui/src/css/_buttons.scss @@ -10,7 +10,7 @@ border-radius: 3px; svg { - fill: var(--slate); + fill: var(--fg-color-less); height: 100%; width: 100%; } @@ -27,11 +27,13 @@ &:disabled { svg { - fill: var(--cloudy); + opacity: 0.5; } + &:hover { background: none; } + &:active { box-shadow: none; transform: none; @@ -59,19 +61,19 @@ height: 10px; width: 10px; stroke: none; - fill: var(--slate); + fill: var(--fg-color-less); transition: fill 50ms; } &:hover { svg { - fill: var(--aqua); + fill: var(--fg-color); } } &:active { svg { - fill: var(--slate); + fill: var(--fg-color); } } } diff --git a/apps/zui/src/css/_chart-elements.scss b/apps/zui/src/css/_chart-elements.scss deleted file mode 100644 index d2d6f66450..0000000000 --- a/apps/zui/src/css/_chart-elements.scss +++ /dev/null @@ -1,3 +0,0 @@ -.hover-line { - fill: var(--slate); -} diff --git a/apps/zui/src/css/_chart.scss b/apps/zui/src/css/_chart.scss index df53730ace..e9c65ec0dd 100644 --- a/apps/zui/src/css/_chart.scss +++ b/apps/zui/src/css/_chart.scss @@ -3,8 +3,8 @@ position: relative; .selection { - fill: var(--havelock); - stroke: var(--havelock); + fill: var(--primary-color); + stroke: var(--primary-color); stroke-dasharray: 3px; } @@ -19,10 +19,10 @@ left: 50%; top: 47%; transform: translate(-50%, -50%); - color: var(--lead); + color: var(--fg-color-less); .burst { - background-color: var(--lead); + background-color: var(--chrome-color-more); } } @@ -64,7 +64,7 @@ display: block; .tick line { - stroke: var(--cloudy); + stroke: var(--border-color); } .tick text { @@ -77,12 +77,12 @@ } .domain { - stroke: var(--cloudy); + stroke: var(--border-color); } text { font-family: var(--mono-font); - fill: var(--lead); + fill: var(--fg-less); font-size: 9px; } } diff --git a/apps/zui/src/css/_circle-chevron.scss b/apps/zui/src/css/_circle-chevron.scss deleted file mode 100644 index 2f2ba7fca5..0000000000 --- a/apps/zui/src/css/_circle-chevron.scss +++ /dev/null @@ -1,71 +0,0 @@ -.circle-chevron { - background: none; - border: none; - margin: 0; - padding: 0; - outline: none; - - .circle { - @include shadow-flat; - height: 36px; - width: 36px; - border-radius: 50%; - display: flex; - align-items: center; - transition: transform 150ms, box-shadow 150ms, background-color 150ms; - } - - svg { - width: 11px; - margin-left: 11px; - transition: transform 150ms; - } - - &:hover { - .circle { - transform: scale(1.05); - @include shadow-medium; - } - } - - &:active { - .circle { - transform: scale(1); - @include shadow-flat; - } - - svg { - transform: translateX(-2px); - } - } - - .circle { - background-color: white; - - &:hover { - background-color: darken(white, 3%); - } - - &:active { - background-color: white; - } - } - - svg { - fill: var(--slate); - } - - &.left { - transform: rotateY(0); - } - - &.right { - transform: rotateY(180deg); - } - - &.expand { - svg { - margin-left: 8px; - } - } -} diff --git a/apps/zui/src/css/_click-feedback.scss b/apps/zui/src/css/_click-feedback.scss deleted file mode 100644 index a42c9560c8..0000000000 --- a/apps/zui/src/css/_click-feedback.scss +++ /dev/null @@ -1,21 +0,0 @@ -.click-feedback { - background: var(--havelock); - color: white; - font-size: $font-size-2; - border-radius: 5px; - padding: 2px 4px; - user-select: none; - text-align: center; - - &:before { - content: ""; - background: var(--havelock); - position: absolute; - top: calc(100% - 2px); - left: calc(50% - 2px); - width: 4px; - height: 4px; - border-radius: 0px; - transform: rotate(45deg); - } -} diff --git a/apps/zui/src/css/_column-chooser.scss b/apps/zui/src/css/_column-chooser.scss deleted file mode 100644 index fc4d217f04..0000000000 --- a/apps/zui/src/css/_column-chooser.scss +++ /dev/null @@ -1,81 +0,0 @@ -.column-chooser-menu { - background-color: white; - min-width: 280px; - position: absolute; - top: 48px; - right: 12px; - bottom: 48px; - border-radius: 4px; - display: flex; - flex-direction: column; - - .fieldset { - margin: 24px auto; - text-align: center; - @include heading-section; - } - - hr { - border: none; - min-height: 1px; - width: calc(100% - (24px + 24px)); - margin: 0 auto; - background-color: #dfe0e6; - } - - .subscript { - color: #c5c7d1; - } - - .close-button { - position: absolute; - right: 6px; - top: 6px; - } - - .count { - top: 18px; - left: 24px; - width: 24px; - height: 24px; - background-color: var(--havelock); - color: white; - border-radius: 50%; - position: absolute; - display: flex; - justify-content: center; - align-items: center; - cursor: default; - .label { - cursor: default; - } - &:hover { - text-decoration: line-through; - } - } - - ul { - list-style-type: none; - margin: 0; - padding: 0; - overflow-y: scroll; - padding-top: 18px; - padding-bottom: 12px; - height: 100%; - } - - .search-input { - width: 100%; - align-content: center; - margin-bottom: 12px; - } -} - -.slide-in-right-appear { - transform: translate(100%); -} - -.slide-in-right-appear-active { - transition: transform 150ms; - transform: translate(0, 0); -} diff --git a/apps/zui/src/css/_column-description.scss b/apps/zui/src/css/_column-description.scss deleted file mode 100644 index 6712799340..0000000000 --- a/apps/zui/src/css/_column-description.scss +++ /dev/null @@ -1,52 +0,0 @@ -.column-description { - width: 180px; - color: white; - font-size: 11px; - border-radius: 8px; - font-family: system-ui; - white-space: normal; - - .tip-title { - display: flex; - justify-content: space-between; - height: 22px; - line-height: 22px; - border-radius: 8px 8px 0 0; - padding: 0 10px; - text-align: center; - - p { - margin: 0; - } - p:first-child { - font-weight: bold; - } - p:last-child { - font-style: italic; - } - } - - .tip-body { - overflow-y: auto; - max-height: 260px; - word-wrap: break-word; - padding: 0 10px; - - ul, - ol { - padding: 0 16px; - } - } - - .tip-footer { - border-top: 1px solid rgba(255, 255, 255, 0.2); - padding: 10px; - border-radius: 0 0 8px 8px; - - a { - text-decoration: underline; - cursor: pointer; - color: var(--havelock); - } - } -} diff --git a/apps/zui/src/css/_conn-versation.scss b/apps/zui/src/css/_conn-versation.scss index 8de380053d..cdaaf35ba7 100644 --- a/apps/zui/src/css/_conn-versation.scss +++ b/apps/zui/src/css/_conn-versation.scss @@ -3,6 +3,7 @@ display: flex; justify-content: space-between; user-select: none; + td, th { white-space: nowrap; @@ -10,7 +11,7 @@ } .host { - border: 1px solid var(--cloudy); + border: 1px solid var(--fg-color-less); border-radius: 3px; } @@ -23,7 +24,7 @@ .port { margin: 0; color: white; - background: var(--havelock); + background: var(--primary-color); font-size: 12px; text-align: center; line-height: 20px; @@ -43,6 +44,7 @@ .ip { background: var(--green); } + .port { background: #5ec4a8; } @@ -87,13 +89,16 @@ .history-packet.arrow-left { padding-left: $space-s*0.5; + .triangle { order: 1; transform: rotate(180deg); } + hr { order: 2; } + span { order: 3; } diff --git a/apps/zui/src/css/_download-progress.scss b/apps/zui/src/css/_download-progress.scss deleted file mode 100644 index c7db8722b2..0000000000 --- a/apps/zui/src/css/_download-progress.scss +++ /dev/null @@ -1,34 +0,0 @@ -.download-progress { - position: relative; - background: var(--cello); - - &.complete .progress-value { - background-color: var(--green); - } - - .progress-bar { - width: 100%; - height: 5px; - } - - .progress-value { - background-color: var(--yellow); - height: 100%; - border-radius: 0 8px 8px 0; - width: 0%; - transition: width 200ms linear; - } - - .message-wrapper { - display: flex; - justify-content: space-between; - align-items: center; - } - - .message { - font-size: 12px; - padding: 12px; - white-space: nowrap; - color: white; - } -} diff --git a/apps/zui/src/css/_editor.scss b/apps/zui/src/css/_editor.scss new file mode 100644 index 0000000000..56ed63f9d2 --- /dev/null +++ b/apps/zui/src/css/_editor.scss @@ -0,0 +1,5 @@ +.monaco-editor.monaco-editor { + --vscode-editor-background: var(--bg-color); + --vscode-editor-foreground: var(--fg-color); + --vscode-editorGutter-background: var(--bg-color); +} diff --git a/apps/zui/src/css/_error-boundary.scss b/apps/zui/src/css/_error-boundary.scss index 563357207e..d2e7461b9e 100644 --- a/apps/zui/src/css/_error-boundary.scss +++ b/apps/zui/src/css/_error-boundary.scss @@ -1,7 +1,6 @@ .error-boundary { overflow: auto; height: 100%; - background-color: var(--ivory); background: linear-gradient(to bottom right, #f8eee3, #fae1e0); padding: 24px; line-height: 1.5; diff --git a/apps/zui/src/css/_filter-node.scss b/apps/zui/src/css/_filter-node.scss deleted file mode 100644 index 9e2b97a664..0000000000 --- a/apps/zui/src/css/_filter-node.scss +++ /dev/null @@ -1,44 +0,0 @@ -.filter-node { - display: inline-flex; - align-items: center; - background: var(--green); - border-radius: 3px; - margin-bottom: 3px; - position: relative; - box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.5); - border: 1px solid transparent; - transition: all 50ms; - - p { - font-family: var(--mono-font); - color: white; - font-size: 9px; - line-height: 13px; - padding: 0 4px; - border-radius: 3px; - margin: 0; - } - - .remove-button { - display: none; - } - - &:hover .remove-button { - display: flex; - .circle { - fill: var(--wet-cement); - opacity: 0.5; - } - &:hover .circle { - opacity: 0.8; - } - &:active .circle { - opacity: 1; - } - } - - &.focused { - border: 1px solid var(--yellow); - background: #5ec4a8; - } -} diff --git a/apps/zui/src/css/_filter-tree.scss b/apps/zui/src/css/_filter-tree.scss deleted file mode 100644 index 71c8c85461..0000000000 --- a/apps/zui/src/css/_filter-tree.scss +++ /dev/null @@ -1,95 +0,0 @@ -$filter-tree-line-color: var(--cloudy); - -.filter-tree { - height: 100%; - color: white; - margin-top: 10px; - user-select: none; - - .filter-tree-parent { - display: flex; - align-items: center; - margin: 0; - height: 24px; - } -} - -.filter-tree-parent:hover { - background: var(--hover-light-bg); -} - -.filter-tree-node { - position: relative; - margin-left: $space-m; - padding: 2px 0; - - .filter-tree-parent::before { - content: ""; - width: 1px; - height: 27px; - position: absolute; - background: $filter-tree-line-color; - top: -3px; - left: 0; - } - - &:last-of-type > .filter-tree-parent::before { - height: 17px; - } - - .filter-tree-children::before { - content: ""; - width: 1px; - height: 100%; - position: absolute; - background: $filter-tree-line-color; - top: 0; - left: 0; - } - - &:last-of-type > .filter-tree-children::before { - display: none; - } - - .filter-node { - background: transparent; - position: relative; - margin: 0 0 0 6px; - box-shadow: none; - height: 16px; - - p { - @include label-small; - line-height: 16px; - color: var(--aqua); - padding: 2px; - margin: 0 2px; - overflow-x: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - &:before { - content: ""; - position: absolute; - background: $filter-tree-line-color; - width: 6px; - height: 1px; - right: calc(100% + 1px); - } - } - - &.pinned > .filter-tree-parent > .filter-node { - background: var(--green); - p { - color: white; - } - } - - &.active > .filter-tree-parent > .filter-node { - background: var(--slate); - p { - color: white; - } - } -} diff --git a/apps/zui/src/css/_global.scss b/apps/zui/src/css/_global.scss index 22c7b05c74..1d17a9345e 100644 --- a/apps/zui/src/css/_global.scss +++ b/apps/zui/src/css/_global.scss @@ -18,15 +18,19 @@ body { line-height: 1.5; -webkit-font-smoothing: antialiased; font-family: var(--body-font); - color: var(--foreground-color); - background-color: var(--background-color); + color: var(--fg-color); font-size: 14px; + + &:not(.is-mac) { + background-color: var(--window-color); + } } input, button, textarea, select { + color: var(--fg-color); font: inherit; } @@ -61,3 +65,31 @@ body.no-select { body.col-resize { cursor: col-resize; } + +a { + color: var(--primary-color); +} + +button { + user-select: none; +} + +/* Works on Chrome, Edge, and Safari */ +*::-webkit-scrollbar { + width: 0.75rem; + height: 0.75rem; +} + +*::-webkit-scrollbar-track { + background-color: var(--emphasis-bg-less); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--emphasis-bg); + border-radius: 6px; + border: 1px solid var(--border-color); +} + +*::-webkit-scrollbar-corner { + background-color: var(--emphasis-bg-less); +} diff --git a/apps/zui/src/css/_header-cell.scss b/apps/zui/src/css/_header-cell.scss deleted file mode 100644 index 6eb3a4cc8c..0000000000 --- a/apps/zui/src/css/_header-cell.scss +++ /dev/null @@ -1,75 +0,0 @@ -.viewer header { - white-space: nowrap; - height: $bro-log-row-height; - display: flex; - box-shadow: 0 1px 3px -2px rgba(0, 0, 0, 0.7); - padding-left: 12px; -} - -.viewer .header-cell { - @include label-normal; - height: $bro-log-row-height; - line-height: $bro-log-row-height; - padding: 0 12px; - color: var(--aqua); - user-select: none; - transition: border 150ms; - position: relative; - display: flex; - align-items: center; - overflow: hidden; - - &.count, - &.interval { - justify-content: flex-end; - } - - &:before, - &:after { - content: ""; - position: absolute; - height: 60%; - width: 1px; - background: var(--cloudy); - top: 20%; - } - - &:before { - left: -1px; - } - - &:after { - right: 0px; - } - - &.active, - &:hover { - &:before, - &:after { - content: ""; - } - } - - &:active, - &.active { - background: var(--coconut); - } - - &.sorted { - font-weight: bold; - - svg { - margin-left: $space-xs; - } - } -} - -.viewer .col-resizer { - width: 12px; - height: 100%; - background: transparent; - position: absolute; - right: -2px; - top: 0; - cursor: col-resize; -} diff --git a/apps/zui/src/css/_histogram-tooltip.scss b/apps/zui/src/css/_histogram-tooltip.scss index b5d701592e..10c19033a2 100644 --- a/apps/zui/src/css/_histogram-tooltip.scss +++ b/apps/zui/src/css/_histogram-tooltip.scss @@ -5,13 +5,15 @@ pointer-events: none; transition: opacity 200ms 50ms, right 75ms, left 75ms; opacity: 1; - font-family: var(--mono-font); + } .histogram-tooltip { pointer-events: none; - color: white; - background: var(--cello-transparent); + color: var(--fg-color); + background: var(--bg-color); + box-shadow: var(--shadow-small); + font-family: var(--mono-font); font-size: 11px; border-radius: 8px; @@ -28,19 +30,18 @@ white-space: nowrap; height: 22px; line-height: 22px; - background: var(--cello); border-radius: 8px 8px 0 0; padding: 0 10px; text-align: center; } .total-row { - border-top: 1px solid white; + border-top: 1px solid var(--border-color); text-align: right; font-weight: bold; } - .path-tag { + td .path-tag { border-radius: 3px; padding: 0 6px; } diff --git a/apps/zui/src/css/_history-pane.scss b/apps/zui/src/css/_history-pane.scss deleted file mode 100644 index dded81bf14..0000000000 --- a/apps/zui/src/css/_history-pane.scss +++ /dev/null @@ -1,4 +0,0 @@ -.history-pane { - background: var(--snow); - overflow-x: unset; -} diff --git a/apps/zui/src/css/_icons.scss b/apps/zui/src/css/_icons.scss deleted file mode 100644 index 2b5720313c..0000000000 --- a/apps/zui/src/css/_icons.scss +++ /dev/null @@ -1,5 +0,0 @@ -svg.icon { - width: 1rem; - height: 1rem; - fill: var(--slate); -} diff --git a/apps/zui/src/css/_info-notice.scss b/apps/zui/src/css/_info-notice.scss deleted file mode 100644 index abb43f1399..0000000000 --- a/apps/zui/src/css/_info-notice.scss +++ /dev/null @@ -1,69 +0,0 @@ -.info-notice-wrapper { - position: fixed; - bottom: 0; - right: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - padding-bottom: 24px; -} - -.info-notice { - white-space: nowrap; - user-select: none; - background: var(--cello); - color: white; - border-radius: 8px; - height: 32px; - box-shadow: 0 2px 3px 0px rgba(0, 0, 0, 0.4), - inset 0 0 0 0.5px rgba(0, 0, 0, 0.3); - display: flex; - align-items: center; - @include label-normal; - margin-bottom: 12px; - animation: popup 2s; - - .x-button { - margin-right: 6px; - } - - p { - margin: 0 12px; - } -} - -@keyframes popup { - from { - transform: translateY(100px); - } - - 20% { - transform: translateY(0px); - } - - to { - transform: translateY(0px); - } -} - -@mixin bevel-button($color, $text-color: white) { - color: $text-color; - @include label-normal; - background: linear-gradient($color, darken($color, 4%)); - border: none; - border-radius: 4px; - box-shadow: inset 0 0 0 0.5px darken($color, 10%), - inset 0 1px 0 0 rgba(255, 255, 255, 0.5), 0 0.5px 1px 0 rgba(0, 0, 0, 0.15); - - letter-spacing: 0.5px; - &:active { - background: darken($color, 8%); - box-shadow: none; - } -} - -.bevel-button { - @include bevel-button(#1ca0f2); -} diff --git a/apps/zui/src/css/_inline-table-loading.scss b/apps/zui/src/css/_inline-table-loading.scss index becf8bee8c..44f0b3babf 100644 --- a/apps/zui/src/css/_inline-table-loading.scss +++ b/apps/zui/src/css/_inline-table-loading.scss @@ -1,6 +1,7 @@ .inline-table-loading { tr { height: 20px; + &:hover { background: initial !important; } @@ -37,7 +38,7 @@ 60% { transform: scaleX(0.85); - background-color: var(--hover-light-bg); + background-color: var(--emphasis-bg-less); } 70% { diff --git a/apps/zui/src/css/_inline-table.scss b/apps/zui/src/css/_inline-table.scss index 71e1bc7460..f14cc91507 100644 --- a/apps/zui/src/css/_inline-table.scss +++ b/apps/zui/src/css/_inline-table.scss @@ -8,6 +8,7 @@ &:first-child { border-radius: 3px 0 0 3px; } + &:last-child { border-radius: 0 3px 3px 0; } @@ -18,12 +19,13 @@ } tbody tr:hover { - background: var(--hover-light-bg); + background: var(--emphasis-bg-less); } th, td { padding: 3px 6px; + &.count { text-align: right; } @@ -34,6 +36,6 @@ @extend .label; font-size: 9px; font-weight: bold; - color: var(--slate); + color: var(--fg-color-less); } } diff --git a/apps/zui/src/css/_input-suggestions.scss b/apps/zui/src/css/_input-suggestions.scss deleted file mode 100644 index 46647fad14..0000000000 --- a/apps/zui/src/css/_input-suggestions.scss +++ /dev/null @@ -1,40 +0,0 @@ -.input-suggestions { - min-width: 100%; - position: absolute; - box-shadow: $high-box-shadow; - top: calc(100%); - left: 0; - border-radius: 3px; - background: white; - font-size: 11px; - user-select: none; - - .suggestion { - font-family: var(--mono-font); - padding: 6px 8px; - margin: 0; - white-space: nowrap; - height: 25px; - cursor: default; - - &:hover { - background: var(--hover-light-bg); - } - - &.active, - &:active { - &:first-child { - border-radius: 3px 3px 0 0; - } - &:last-child { - border-radius: 0 0 3px 3px; - } - background: var(--havelock); - color: white; - } - - &.error { - color: var(--lead); - } - } -} diff --git a/apps/zui/src/css/_list-item.scss b/apps/zui/src/css/_list-item.scss index 1e9695eda9..7a04dd5c91 100644 --- a/apps/zui/src/css/_list-item.scss +++ b/apps/zui/src/css/_list-item.scss @@ -1,5 +1,5 @@ .list-item { - height: 28px; + height: 100%; display: flex; align-items: center; cursor: default; @@ -28,7 +28,7 @@ width: 100%; height: 100%; border-radius: 6px; - font-size: 13px; + font-size: 15px; &:hover:not(.dragging) { background: rgb(0 0 0 / 0.03); @@ -89,7 +89,6 @@ .list-item__icon { width: 22px; - height: 28px; display: flex; align-items: center; justify-content: center; @@ -119,6 +118,7 @@ } .list-item__menu-item { + &:hover, &:active { background: none !important; diff --git a/apps/zui/src/css/_log-cell.scss b/apps/zui/src/css/_log-cell.scss deleted file mode 100644 index cf5217ad98..0000000000 --- a/apps/zui/src/css/_log-cell.scss +++ /dev/null @@ -1,48 +0,0 @@ -.log-cell { - padding: 0 4px; - position: relative; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - height: 25px; - display: flex; - align-items: flex-start; - - &.hover, - &.active { - position: relative; - } -} - -.cell-value-item { - position: relative; - padding: 0 1px; - border: 1px solid transparent; - height: 25px; - - &.selected { - background: rgba(255, 255, 255, 0.25); - } - - &:hover { - z-index: 1; - border: 1px dashed var(--lead); - } -} - -.cell-value-item:last-child { - width: 100%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.compound-field-extra { - height: 25px; - border: 1px solid transparent; - color: var(--lead); - - &.separator { - margin-right: 6px; - } -} diff --git a/apps/zui/src/css/_log-detail-window.scss b/apps/zui/src/css/_log-detail-window.scss index 1cb9a16456..210aef777b 100644 --- a/apps/zui/src/css/_log-detail-window.scss +++ b/apps/zui/src/css/_log-detail-window.scss @@ -8,16 +8,16 @@ width: 100%; height: 100%; flex-direction: column; - background: var(--snow); .pane-header { - background: var(--ivory); + background: var(--chrome-color); border-bottom: 1px solid #dbdbdb; } .detail-pane-content { display: flex; justify-content: space-between; + .column { width: 50%; margin: 12px; diff --git a/apps/zui/src/css/_log-detail.scss b/apps/zui/src/css/_log-detail.scss index 56a6fb460a..864a120187 100644 --- a/apps/zui/src/css/_log-detail.scss +++ b/apps/zui/src/css/_log-detail.scss @@ -1,5 +1,6 @@ .log-detail { padding: 12px; + section { margin-bottom: 24px; } @@ -13,7 +14,7 @@ .empty-message { text-align: center; - color: var(--slate); + color: var(--fg-color-less); font-size: 12px; } } diff --git a/apps/zui/src/css/_log-viewer.scss b/apps/zui/src/css/_log-viewer.scss deleted file mode 100644 index 9e6b24f954..0000000000 --- a/apps/zui/src/css/_log-viewer.scss +++ /dev/null @@ -1,82 +0,0 @@ -.viewer { - overflow: visible; - height: 0; - width: 0; - - *::selection { - background: transparent; - } - - .using-keyboard &:focus { - outline: none; - } -} - -.viewer .view { - overflow: scroll; - display: flex; -} - -.viewer .list { - position: relative; -} - -.viewer .chunk { - position: absolute; -} - -.viewer .log-row { - white-space: nowrap; - contain: layout style; - display: flex; - font-family: var(--mono-font); - font-size: 12px; - white-space: nowrap; - min-height: 25px; - line-height: 25px; - align-items: center; - opacity: 1; - padding-left: 16px; - - &.even { - background: var(--table-stripe-bg); - } - - &:hover { - background: var(--hover-light-bg); - } - - &.highlight { - background: var(--havelock); - - span { - color: white; - } - } -} - -.viewer .end-message { - text-align: center; - font-size: 12px; - color: var(--lead); - line-height: 100px; -} - -.viewer { - .count, - .duration, - .uint8, - .uint16, - .uint32, - .uint64, - .int8, - .int16, - .int32, - .int64 { - text-align: right; - } - - .path-tag { - @include path-tag; - } -} diff --git a/apps/zui/src/css/_mac-spinner.scss b/apps/zui/src/css/_mac-spinner.scss index 2bfa1e2a9a..705cdb834d 100644 --- a/apps/zui/src/css/_mac-spinner.scss +++ b/apps/zui/src/css/_mac-spinner.scss @@ -1,7 +1,7 @@ @use "sass:math"; $mac-spinner-duration: 800ms; -$mac-spinner-color: var(--aqua); +$mac-spinner-color: var(--fg-color); $mac-spinner-size: 24px; .mac-spinner { diff --git a/apps/zui/src/css/_notice-banner.scss b/apps/zui/src/css/_notice-banner.scss index f193627a45..72f817df05 100644 --- a/apps/zui/src/css/_notice-banner.scss +++ b/apps/zui/src/css/_notice-banner.scss @@ -17,7 +17,7 @@ font-weight: 400; &:hover { - color: var(--slate); + color: var(--fg-color-less); } &:active { @@ -27,6 +27,7 @@ .error-details { margin-top: 12px; + p { font-size: 12px; font-weight: 400; diff --git a/apps/zui/src/css/_packet-post-progress.scss b/apps/zui/src/css/_packet-post-progress.scss deleted file mode 100644 index 7ed8ed4da8..0000000000 --- a/apps/zui/src/css/_packet-post-progress.scss +++ /dev/null @@ -1,61 +0,0 @@ -.packet-post-progress { - width: 100%; - height: 100%; - display: flex; - justify-content: space-between; - align-items: center; - padding: 0 6px; - - label { - @include label-small; - line-height: 24px; - white-space: nowrap; - } - - .progress-indicator { - max-width: 220px; - padding: 0 12px; - width: 220px; - } - - .group { - display: flex; - align-items: center; - height: 100%; - } - - .warnings { - height: 100%; - padding: 0 12px; - display: flex; - fill: #f37406; - align-items: center; - svg { - width: 14px; - } - label { - min-width: 15px; - margin-left: 5px; - text-align: center; - color: #f37406; - @include label-small-bold; - font-weight: 800; - } - &:not(.disabled):hover { - background: rgba(0, 0, 0, 0.05); - } - &:not(.disabled):active { - background: rgba(0, 0, 0, 0.1); - } - } - - .warnings.disabled { - pointer-events: none; - svg { - fill: var(--cloudy); - } - label { - color: var(--cloudy); - } - } -} diff --git a/apps/zui/src/css/_pane.scss b/apps/zui/src/css/_pane.scss index 49083d1526..2f0db14c16 100644 --- a/apps/zui/src/css/_pane.scss +++ b/apps/zui/src/css/_pane.scss @@ -9,7 +9,7 @@ position: relative; svg { - fill: var(--slate); + fill: var(--fg-color-less); } flex-shrink: 0; diff --git a/apps/zui/src/css/_pop-menu.scss b/apps/zui/src/css/_pop-menu.scss deleted file mode 100644 index 5e007a87bf..0000000000 --- a/apps/zui/src/css/_pop-menu.scss +++ /dev/null @@ -1,104 +0,0 @@ -$pop-menu-padding: $space-s; - -.pop-menu-overlay { - position: fixed; - background: transparent; - left: 0; - right: 0; - top: 0; - bottom: 0; - z-index: 2; -} - -.pop-menu-wrapper { - filter: drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5)); - z-index: 1; - margin: 0; - text-align: left; - background-color: white; - position: relative; - border-radius: 5px; - display: inline-block; - pointer-events: all; - - ul { - padding: 8px 0; - margin: 0; - } - - li { - @include label-normal; - padding: $space-xxs 36px; - list-style-type: none; - display: block; - white-space: nowrap; - margin: 0; - user-select: none; - - &:hover { - background-color: var(--havelock); - color: white; - } - } - - .disabled { - cursor: auto; - color: var(--lead); - &:hover { - background-color: inherit; - color: var(--lead); - } - } - - hr { - border: none; - border-top: 1px solid var(--cloudy); - margin: 8px 0; - } - - .pop-menu-pointer { - margin: 0; - padding: 0; - fill: white; - position: absolute; - height: 16px; - } -} - -.test-anchor { - position: fixed; - background-color: var(--havelock); - height: 100px; - width: 100px; - border-radius: 50%; -} - -.a { - top: 10px; - left: 10px; -} - -.b { - top: 10px; - right: 10px; -} - -.c { - bottom: 10px; - right: 10px; -} - -.d { - bottom: 10px; - left: 10px; -} - -.e { - top: 30%; - left: 50%; -} - -.f { - top: 60%; - left: 50%; -} diff --git a/apps/zui/src/css/_progress-indicator.scss b/apps/zui/src/css/_progress-indicator.scss index 6f67815ef7..f46e662237 100644 --- a/apps/zui/src/css/_progress-indicator.scss +++ b/apps/zui/src/css/_progress-indicator.scss @@ -7,6 +7,7 @@ margin-left: 8px; width: 12px; height: 12px; + svg { width: 8px; height: 8px; @@ -26,7 +27,7 @@ .progress-fill { width: 0%; - background: var(--havelock); + background: var(--primary-color); height: 100%; transition: width 1000ms; } @@ -35,33 +36,43 @@ from { width: 5%; } + 10% { width: 8%; } + 20% { width: 30%; } + 30% { width: 32%; } + 40% { width: 38%; } + 50% { width: 45%; } + 60% { width: 55%; } + 70% { width: 89%; } + 80% { width: 90%; } + 90% { width: 98%; } + to { width: 100%; } diff --git a/apps/zui/src/css/_saved-pools-list.scss b/apps/zui/src/css/_saved-pools-list.scss deleted file mode 100644 index 3c89e52a26..0000000000 --- a/apps/zui/src/css/_saved-pools-list.scss +++ /dev/null @@ -1,107 +0,0 @@ -.saved-pools-list { - user-select: none; - overflow-x: hidden; - overflow-y: auto; - min-height: 0px; - position: relative; - margin: 0; - padding: 0; - - &:before { - content: ""; - position: sticky; - top: 0; - left: 0; - width: 100%; - height: 22px; - background: orange; - } - - a { - -webkit-user-drag: none; - } - - li { - list-style-type: none; - display: flex; - align-items: center; - - &:hover { - background-color: rgba(0, 0, 0, 0.03); - } - - &:active { - background-color: rgba(0, 0, 0, 0.08); - } - } - - .pool-link { - @include label-small; - line-height: 18px; - color: var(--aqua); - display: flex; - align-items: center; - justify-content: space-between; - text-decoration: none; - flex: 1; - height: 24px; - width: 100%; - padding-left: 22px; - cursor: default; - - .using-keyboard &:focus { - outline: none; - background: var(--havelock); - color: white; - svg { - fill: white; - } - } - } - - .current-pool-link { - outline: none; - background: var(--havelock); - color: white; - - .pool-icon { - fill: white; - stroke: white; - .chunk { - fill: white; - } - } - - .small-progress-bar { - .progress-track { - background-color: rgba(0, 0, 0, 0.15); - } - .progress-fill { - background-color: white; - } - } - - &:hover { - background: var(--havelock); - } - } - - .pool-icon { - width: 13px; - height: 13px; - flex-shrink: 0; - } - - .name { - display: block; - padding-left: 6px; - overflow-x: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - .small-progress-bar { - flex: 1; - margin: 0px 5px; - } -} diff --git a/apps/zui/src/css/_search-results.scss b/apps/zui/src/css/_search-results.scss deleted file mode 100644 index 2ab757e15a..0000000000 --- a/apps/zui/src/css/_search-results.scss +++ /dev/null @@ -1,8 +0,0 @@ -.no-results { - text-align: center; - width: 100%; - margin-top: 100px; - color: var(--lead); - display: inline-block; - @include label-small; -} diff --git a/apps/zui/src/css/_settings-modal.scss b/apps/zui/src/css/_settings-modal.scss deleted file mode 100644 index 65cacce03c..0000000000 --- a/apps/zui/src/css/_settings-modal.scss +++ /dev/null @@ -1,70 +0,0 @@ -.settings-modal { - z-index: 99; - min-width: 500px; - - .settings-form { - border-radius: 3px; - - a { - text-decoration: underline; - cursor: pointer; - @include label-small; - } - - input, - select { - width: 240px; - } - - .setting-panel { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 12px; - height: 48px; - border-bottom: 1px solid var(--ivory); - position: relative; - - &:last-child { - border: none; - } - } - } - - .errors { - h4 { - margin-bottom: 0.25rem; - } - - ul { - margin-top: 1rem; - line-height: 1.5; - } - - a { - color: var(--red); - cursor: pointer; - text-decoration: underline; - } - - p { - margin: 0; - @include label-small; - } - } - - .feedback { - position: absolute; - right: 12px; - top: 1px; - margin: 0; - @include label-small; - line-height: 14px; - background: var(--havelock); - color: white; - padding: 0 6px; - border-radius: 4px; - animation: fadein 300ms; - z-index: 1; - } -} diff --git a/apps/zui/src/css/_tab.scss b/apps/zui/src/css/_tab.scss index 39f0bac531..c7245258c9 100644 --- a/apps/zui/src/css/_tab.scss +++ b/apps/zui/src/css/_tab.scss @@ -1,24 +1,16 @@ -$tab-inactive-color: var(--foreground-color); -$tab-inactive-bg: rgba(0, 0, 0, 0.06); -$tab-hover-color: var(--foreground-color); -$tab-hover-bg: var(--tab-background-hover); -$tab-active-color: var(--foreground-color); -$tab-active-bg: white; -$tab-transition-duration: 200ms; - .tab { position: absolute; left: 0; user-select: none; -webkit-app-region: no-drag; height: 32px; - border-radius: 8px; - background: $tab-inactive-bg; + border-radius: 6px; + background: var(--emphasis-bg-less); cursor: default; will-change: transform; transition: none; margin-top: 1px; - border: 1px solid var(--tab-background); + color: var(--fg-color); .tab-content { overflow: hidden; @@ -28,11 +20,12 @@ $tab-transition-duration: 200ms; height: 100%; position: relative; opacity: 0.75; + padding-inline-start: 8px; + gap: 4px; } .icon { - margin-left: 16px; - margin-right: 8px; + display: flex; } // Title @@ -42,33 +35,23 @@ $tab-transition-duration: 200ms; line-height: 16px; margin: 0; font-weight: 400; - color: $tab-inactive-color; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; - } - - // Close x icon - .close-button { - margin-right: 10px; - position: relative; - - &:hover { - background: rgba(0, 0, 0, 0.3); - } + opacity: 0.7; } // The hover state &:hover { - background-color: $tab-hover-bg; + background-color: var(--emphasis-bg); .title { - color: $tab-hover-color; + opacity: 1; } - .close-button svg { - fill: $tab-hover-color; + .close-button { + opacity: 1 } .tab-content { @@ -78,12 +61,12 @@ $tab-transition-duration: 200ms; // The active state &.active { - background: $tab-active-bg; + background: var(--selected-bg); box-shadow: none; z-index: 1; .title { - color: $tab-active-color; + opacity: 1; } .tab-content { @@ -91,9 +74,7 @@ $tab-transition-duration: 200ms; } .close-button { - svg { - fill: $tab-active-color; - } + opacity: 1; &:after { background: rgba(0, 0, 0, 0.1); diff --git a/apps/zui/src/css/_table.scss b/apps/zui/src/css/_table.scss index 40ae502d3c..c59971f4e1 100644 --- a/apps/zui/src/css/_table.scss +++ b/apps/zui/src/css/_table.scss @@ -8,7 +8,7 @@ } tbody tr:hover { - background: var(--hover-light-bg); + background: var(--emphasis-bg-less); } th, @@ -38,6 +38,7 @@ } .vertical-table { + th, td { word-break: break-word; diff --git a/apps/zui/src/css/_time-span-pickers.scss b/apps/zui/src/css/_time-span-pickers.scss deleted file mode 100644 index 21cb484393..0000000000 --- a/apps/zui/src/css/_time-span-pickers.scss +++ /dev/null @@ -1,122 +0,0 @@ -.time-span-pickers { - -webkit-app-region: no-drag; - z-index: 1; - position: relative; - display: flex; - align-items: flex-start; - - .time-span-menu { - @include toolbar-button-style; - justify-content: center; - min-width: 0px; - margin-left: 3px; - } - - .span-duration { - margin-top: 5px; - } -} - -.time-picker-button-input { - position: relative; - display: flex; - align-items: flex-start; - - input { - @include label-small; - @include input-focus; - margin: 0; - width: 135px; - height: 22px; - border-radius: 3px; - border: none; - padding-left: 8px; - line-height: 22px; - } -} - -.time-picker-button { - position: relative; - .toolbar-button { - position: relative; - min-width: 60px; - } - - .hover-zone { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - } - - & > .hover-zone { - z-index: -1; - } - - &.hovering .hover-zone { - top: -20px; - bottom: -20px; - } - - .changed-dot { - position: absolute; - width: 8px; - height: 8px; - background: var(--havelock); - top: calc(50% - 4px); - left: -4px; - border-radius: 50%; - border: 1px solid white; - cursor: pointer; - transition: all 150ms; - } -} - -.time-piece { - padding: 0 3px; - position: relative; - - &[data-unit="hour"], - &[data-unit="minute"], - &[data-unit="second"] { - font-weight: normal; - padding-right: 0; - } - - .hover-zone { - z-index: -1; - } -} - -.steppers { - position: fixed; - left: 0; - top: 0; - transition: all 25ms; -} - -.stepper { - width: 20px; - height: 18px; - background: rgba(0, 0, 0, 0.2); - display: flex; - align-items: center; - justify-content: center; - position: absolute; - transition: background-color 100ms; - - &:hover { - background: rgba(0, 0, 0, 0.3); - } - - &:active { - background: rgba(0, 0, 0, 0.4); - } - &.step-up { - border-radius: 4px 4px 0 0; - } - &.step-down { - border-radius: 0 0 4px 4px; - } -} diff --git a/apps/zui/src/css/_toaster.scss b/apps/zui/src/css/_toaster.scss index 8cb190ba7a..7761397c2e 100644 --- a/apps/zui/src/css/_toaster.scss +++ b/apps/zui/src/css/_toaster.scss @@ -1,5 +1,5 @@ .toaster.toaster { - background: var(--wet-cement); + background: #4c5661; color: white; border-radius: 8px; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.25), 0 3px 3px rgba(0, 0, 0, 0.05); diff --git a/apps/zui/src/css/_toolbar-button.scss b/apps/zui/src/css/_toolbar-button.scss deleted file mode 100644 index 110ea821a2..0000000000 --- a/apps/zui/src/css/_toolbar-button.scss +++ /dev/null @@ -1,77 +0,0 @@ -.toolbar-button { - @include toolbar-button-style; - user-select: none; - min-width: 48px; - -webkit-app-region: no-drag; - height: 22px; - padding: 0 4px; - display: flex; - align-items: center; - justify-content: center; - - & > * { - pointer-events: none; - } - - .icon { - display: flex; - margin: 0 4px; - - svg { - fill: var(--slate); - height: 16px; - width: 16px; - } - } - - .text { - @include label-small; - white-space: nowrap; - color: var(--aqua); - display: flex; - line-height: 16px; - height: 16px; - padding: 0 4px; - white-space: nowrap; - } - - &:disabled { - .icon { - opacity: 0.25; - } - - .text { - opacity: 0.5; - } - - & + label { - opacity: 0.5; - } - - cursor: not-allowed; - } - - &.dragging { - background: var(--havelock); - - .text { - color: white; - } - - .icon { - fill: white; - } - } -} - -.toolbar-button-primary { - background: linear-gradient(#4b91e2, #3a87df); - - .text { - color: white; - } - - &:active:not(:disabled) { - background: var(--azure); - } -} diff --git a/apps/zui/src/css/_tooltip-animation.scss b/apps/zui/src/css/_tooltip-animation.scss new file mode 100644 index 0000000000..8d28417997 --- /dev/null +++ b/apps/zui/src/css/_tooltip-animation.scss @@ -0,0 +1,22 @@ +.tooltip-enter, +.tooltip-appear { + transition: opacity 450ms var(--pop-easing); + opacity: 0; +} + +.tooltip-enter-active, +.tooltip-appear-active { + transition: opacity 450ms var(--pop-easing); + opacity: 1; +} + +.tooltip-exit { + transition: opacity 450ms var(--pop-easing); + opacity: 1; +} + +.tooltip-exit-active { + opacity: 0; + transition: all 250ms var(--pop-easing); + transition-delay: 150ms; +} diff --git a/apps/zui/src/css/_tooltip.scss b/apps/zui/src/css/_tooltip.scss deleted file mode 100644 index 60b068fd42..0000000000 --- a/apps/zui/src/css/_tooltip.scss +++ /dev/null @@ -1,34 +0,0 @@ -.tool-tip { - position: fixed; - background: var(--cello-transparent); - font-family: var(--mono-font); - color: white; - font-size: 12px; - line-height: 18px; - padding: 0 3px; - border-radius: 3px; - z-index: 1; - pointer-events: none; - user-select: none; - box-shadow: $box-shadow; - - .secondary { - font-size: 10px; - opacity: 0.7; - } -} - -.__react_component_tooltip.tooltip { - @include label-small; - transition: opacity 150ms; - padding: 3px 8px; -} - -.zui-tooltip-show-hover { - pointer-events: auto !important; - - &:hover { - visibility: visible !important; - opacity: 1 !important; - } -} diff --git a/apps/zui/src/css/_zed-table.scss b/apps/zui/src/css/_zed-table.scss index cbec480cf5..e4b5f42c94 100644 --- a/apps/zui/src/css/_zed-table.scss +++ b/apps/zui/src/css/_zed-table.scss @@ -15,7 +15,7 @@ position: sticky; top: 0; left: 0; - background: white; + background: var(--bg-color); z-index: 1; } @@ -49,7 +49,7 @@ justify-content: space-between; padding: 0 10px; border-right: 1px solid transparent; - color: var(--foreground-color-light); + color: var(--fg-color-less); background: var(--chrome-color); border-right-color: var(--border-color); @@ -103,13 +103,10 @@ } .zed-table__cell { - --background-color: #f9f9f9; - &.even { - --background-color: white; + background-color: var(--emphasis-bg-less); } - background-color: var(--background-color); overflow: hidden; white-space: nowrap; padding: 0 10px; @@ -154,7 +151,7 @@ border: 1px solid var(--border-color); &:active { - background: var(--chrome-color-dark); + background: var(--chrome-color-more); } .zed-table__header-cell:hover & { diff --git a/apps/zui/src/css/_zed-view.scss b/apps/zui/src/css/_zed-view.scss index be3c50fc22..3fd5f84dc9 100644 --- a/apps/zui/src/css/_zed-view.scss +++ b/apps/zui/src/css/_zed-view.scss @@ -33,7 +33,7 @@ margin-right: 2px; svg { - fill: var(--aqua); + fill: var(--fg-color); width: 14px; height: 14px; } @@ -46,7 +46,7 @@ &:hover { background: var(--button-background-hover); - color: var(--foreground-color); + color: var(--fg-color); } &:active { diff --git a/apps/zui/src/css/forms/_file-input.scss b/apps/zui/src/css/forms/_file-input.scss deleted file mode 100644 index c5bc2ae56c..0000000000 --- a/apps/zui/src/css/forms/_file-input.scss +++ /dev/null @@ -1,20 +0,0 @@ -.file-input { - @include input-border; - display: flex; - align-items: stretch; - border-radius: 4px; - - button { - @include white-button-bg; - margin: 1px 0 1px 1px; - border-radius: 4px 0 0 4px; - border: none; - &:focus { - z-index: 1; - } - } - - .text-input { - border-radius: 0 4px 4px 0; - } -} diff --git a/apps/zui/src/css/forms/_global.scss b/apps/zui/src/css/forms/_global.scss deleted file mode 100644 index 09396fbdee..0000000000 --- a/apps/zui/src/css/forms/_global.scss +++ /dev/null @@ -1,3 +0,0 @@ -::placeholder { - color: var(--lead); -} diff --git a/apps/zui/src/css/forms/_main.scss b/apps/zui/src/css/forms/_main.scss deleted file mode 100644 index 5fde83786c..0000000000 --- a/apps/zui/src/css/forms/_main.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import "mixins"; -@import "global"; -@import "text-input"; -@import "select-input"; -@import "file-input"; diff --git a/apps/zui/src/css/forms/_mixins.scss b/apps/zui/src/css/forms/_mixins.scss deleted file mode 100644 index e5618f2d1e..0000000000 --- a/apps/zui/src/css/forms/_mixins.scss +++ /dev/null @@ -1,12 +0,0 @@ -@mixin input-focus { - &:focus, - &:active { - z-index: 1; - box-shadow: 0 0 0 2px var(--havelock); - outline: none !important; - } -} - -@mixin input-border { - box-shadow: inset 0 0 0 0.5px var(--lead), inset 0 0 0 1px white; -} diff --git a/apps/zui/src/css/forms/_select-input.scss b/apps/zui/src/css/forms/_select-input.scss deleted file mode 100644 index bcc6de3541..0000000000 --- a/apps/zui/src/css/forms/_select-input.scss +++ /dev/null @@ -1,10 +0,0 @@ -.select-input { - height: 24px; - width: 100%; - @include label-normal; - @include input-border; - @include input-focus; - color: var(--aqua); - background: var(--ivory); - border: none; -} diff --git a/apps/zui/src/css/forms/_text-input.scss b/apps/zui/src/css/forms/_text-input.scss deleted file mode 100644 index b74a1fbff4..0000000000 --- a/apps/zui/src/css/forms/_text-input.scss +++ /dev/null @@ -1,11 +0,0 @@ -.text-input { - @include label-normal; - @include input-border; - @include input-focus; - width: 100%; - color: var(--aqua); - background: var(--ivory); - padding: 3px 8px; - border-radius: 4px; - border: none; -} diff --git a/apps/zui/src/css/main.scss b/apps/zui/src/css/main.scss index a0adb304f8..f792fa04b6 100644 --- a/apps/zui/src/css/main.scss +++ b/apps/zui/src/css/main.scss @@ -12,44 +12,29 @@ @import "shared/typography"; @import "shared/effects"; -/* Forms */ -@import "forms/main"; - /* Specific */ @import "global"; @import "buttons"; -@import "icons"; @import "tags"; @import "text-content"; @import "layout"; @import "modal"; @import "conn-versation"; @import "chart"; -@import "filter-node"; -@import "filter-tree"; @import "arrows"; -@import "log-viewer"; @import "log-detail"; @import "control-bar"; @import "pins"; @import "search-page"; -@import "settings-modal"; @import "pool-modal"; @import "pane"; -@import "history-pane"; -@import "download-progress"; @import "error-boundary"; -@import "tooltip"; -@import "log-cell"; -@import "search-results"; -@import "column-chooser"; +@import "tooltip-animation"; @import "histogram-tooltip"; -@import "chart-elements"; @import "whois-modal"; @import "portal"; @import "message-box"; @import "notice-banner"; -@import "circle-chevron"; @import "pane-toggle-buttons"; @import "flash-animation"; @import "loading-message"; @@ -61,31 +46,20 @@ @import "table"; @import "span-duration"; @import "expand-button"; -@import "pop-menu"; @import "button-row"; @import "debug-modal"; -@import "click-feedback"; -@import "header-cell"; -@import "time-span-pickers"; -@import "input-suggestions"; @import "tab"; -@import "column-description"; @import "brand"; @import "empty-search-page"; @import "mac-spinner"; -@import "saved-pools-list"; @import "progress-indicator"; -@import "packet-post-progress"; @import "about-window"; @import "tab-search-loading"; -@import "toolbar-button"; -@import "../ppl/css/load-files-input"; @import "ingest-warnings-modal"; @import "log-detail-window"; @import "sidebar"; /* Common */ @import "history-buttons"; -@import "info-notice"; @import "x-button"; @import "html-context-menu"; @import "toaster"; @@ -97,3 +71,4 @@ @import "results-pane"; @import "zed-view"; @import "modal-animation"; +@import "editor" diff --git a/apps/zui/src/css/settings/_colors.scss b/apps/zui/src/css/settings/_colors.scss index b7dbb26eb7..66cfeac140 100644 --- a/apps/zui/src/css/settings/_colors.scss +++ b/apps/zui/src/css/settings/_colors.scss @@ -1,93 +1,169 @@ +/** + * Constants + */ :root { - // colors + /* Colors */ --red: #F13737; - --green: #399c81; - --green-bright: #4ef567; + --green: #1ADB91; --orange: #ff7f00; --yellow: #ffc933; - --azure: #2f629c; - --cello: hsl(212, 100%, 14%); - --cello-transparent: hsla(212, 100%, 14%, 0.92); - --havelock: #4b91e2; - --hawkes-blue: rgba(206, 228, 253, 0.5); - --pecan: #9c692f; --blue: hsl(212, 72%, 59%); + /* Forms */ + --form-font-size: 14px; + --form-line-height: 20px; + --form-border-radius: 6px; + --form-padding: 3px 10px; + --form-height: 2rem; + --form-field-gap: 12px; - // shades of gray - --snow: #fcfcfd; - --coconut: #f7f7f8; - --ivory: #f3f3f4; - --cloudy: #e2e6e9; - --lead: #abadaf; - --slate: #717375; - --wet-cement: #4c5661; - --aqua: #0f1e2e; - --aqua-transparent: rgba(15, 30, 46, 0.2); - - // alert severities - --alert-3: #fbc00e; - --alert-2: #f4912f; - --alert-1: #d0250b; - - // backgrounds - --hover-dark: rgba(0, 0, 0, 0.06); - --active-dark: rgba(0, 0, 0, 0.09); - - --hover-light-bg: var(--hover-dark); - --table-stripe-bg: rgba(0, 0, 0, 0.02); - - // borders - - // Colors by name + /* Easings */ + --pop-easing: cubic-bezier(0.16, 1, 0.3, 1); + --quick: 150ms; + --medium: 300ms; + --slow: 450ms; - --success-color: #1ADB91; - --error-color: #F13737; + --measure: 45ch; +} - --input-background: hsl(240, 15%, 92%); +/** + * Foregrounds & Backgrounds + */ +:root { + --fg-color: #0f1e2e; + --fg-color-less: hsl(210, 4%, 40%); + --bg-color: white; + --window-color: #F3F3F3; + + + @media (prefers-color-scheme: dark) { + --fg-color: white; + --fg-color-less: rgba(255, 255, 255, 0.7); + --bg-color: hsl(44deg 8% 10%); + --window-color: #303231; + } +} - --sidebar-background: hsl(212, 8%, 85%); - --sidebar-item-hover: hsl(200deg 6% 80%); - --sidebar-item-active: hsl(200deg 6% 76%); - --sidebar-item-active-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2); +/** + * Chrome / Grays + */ +:root { + --chrome-color: hsl(212, 10%, 97%); + --chrome-color-more: #E9EAEB; - --tab-background: var(--sidebar-background); - --tab-background-hover: rgba(0, 0, 0, 0.1); + @media (prefers-color-scheme: dark) { + --chrome-color: rgba(255, 255, 255, 0.15); + --chrome-color-more: rgba(255, 255, 255, 0.4); + } +} +/** + * Primary Color Variations + */ +:root { --primary-color-lighter: hsl(212, 89%, 82%); --primary-color-light: hsl(212, 72%, 69%); --primary-color: hsl(212, 72%, 59%); --primary-color-dark: hsl(212, 78%, 50%); --primary-color-darker: hsl(212, 88%, 35%); +} - --foreground-color-dark: #000811; - --foreground-color: #0f1e2e; - --foreground-color-light: hsl(210, 4%, 40%); +/** + * Emphasis + */ +:root { + --emphasis-bg-less: rgba(0, 0, 0, 0.03); + --emphasis-bg: rgba(0, 0, 0, 0.06); + --emphasis-bg-more: rgba(0, 0, 0, 0.09); + --emphasis-bg-most: rgba(0, 0, 0, 0.11); + + @media (prefers-color-scheme: dark) { + --emphasis-bg-less: rgba(255, 255, 255, 0.05); + --emphasis-bg: rgba(255, 255, 255, 0.15); + --emphasis-bg-more: rgba(255, 255, 255, 0.2); + --emphasis-bg-most: rgba(255, 255, 255, 0.3); + } +} + +/** + * Borders + */ +:root { + --border-color: hsl(216, 10%, 87%); + --border-color-more: hsl(216, 10%, 80%); + + @media (prefers-color-scheme: dark) { + --border-color: rgba(255, 255, 255, 0.3); + --border-color-more: rgba(255, 255, 255, 0.5); + } +} + +/** + * Statuses + */ +:root { + --success-color: var(--green); + --error-color: var(--red); + --info-color: var(--blue); +} +/** + * Buttons + */ +:root { --button-background: hsl(212, 5%, 92%); --button-background-hover: hsl(212, 5%, 90%); --button-background-active: hsl(212, 5%, 87%); +} +/** + * Form Inputs + */ +:root { --editor-background: white; - - --border-color: hsl(216, 10%, 87%); - --border-color-dark: hsl(216, 10%, 80%); - - --chrome-color: hsl(212, 10%, 97%); - --chrome-color-dark: #E9EAEB; - - // Form stuff + --input-background: hsl(240, 15%, 92%); --form-bg-color: white; --form-bg-color-dark: #f8f8f8; --form-bg-color-darker: #e6e6e6; - --form-border: 1px solid #c0c0c0; - --form-font-size: 14px; - --form-line-height: 20px; - --form-border-radius: 6px; - --form-padding: 3px 10px; - --form-height: 2rem; - --form-field-gap: 12px; + --form-border: 1px solid var(--border-color); - // Easing - --pop-easing: cubic-bezier(0.16, 1, 0.3, 1); + @media (prefers-color-scheme: dark) { + --form-bg-color: var(--emphasis-bg); + --form-bg-color-dark: var(--emphasis-bg-more); + --form-bg-color-darker: var(--emphasis-bg-more); + } +} + +/** + * Shadows + */ +:root { + --shadow-small: 0px 0px 3px 0px rgb(0 0 0 / 30%); + --shadow-medium: 0px 3px 3px 6px rgb(0 0 0 / 30%); +} + + + +/** + * Selection + */ +:root { + --selected-bg: white; + --selected-bg-active: hsl(0deg, 0%, 95%); + + @media (prefers-color-scheme: dark) { + --selected-bg: rgba(255, 255, 255, 0.2); + --selected-bg-active: rgba(255, 255, 255, 0.25); + } +} + +/** + * Tables + */ +:root { + --table-stripe-bg: rgba(0, 0, 0, 0.02); + + @media (prefers-color-scheme: dark) { + --table-stripe-bg: rgba(255, 255, 255, 0.01); + } } diff --git a/apps/zui/src/css/shared/_type-colors.scss b/apps/zui/src/css/shared/_type-colors.scss index d90614207e..dc87d7a3d9 100644 --- a/apps/zui/src/css/shared/_type-colors.scss +++ b/apps/zui/src/css/shared/_type-colors.scss @@ -1,17 +1,22 @@ :root { // type colors - --zed-null: var(--lead); + --zed-null: #abadaf; --zed-time: hsl(275, 55%, 50%); --zed-symbol: hsl(212, 95%, 55%); --zed-type: hsla(212, 70%, 50%); --interval: #544aa6; --bool: #3eaef4; - --zed-string: var(--foreground-color); + --zed-string: var(--fg-color); --zed-key: hsl(212, 20%, 40%); --zed-number: #e65835; --zed-syntax: hsl(212, 17%, 55%); --zed-note: hsl(212, 17%, 80%); - --zed-container: var(--foreground-color); + --zed-container: var(--fg-color); + + // Suricata Alerts + --alert-3: #fbc00e; + --alert-2: #f4912f; + --alert-1: #d0250b; } .zed-syntax { diff --git a/apps/zui/src/css/shared/_typography.scss b/apps/zui/src/css/shared/_typography.scss index 2ca4dfc2f6..60e0a738b7 100644 --- a/apps/zui/src/css/shared/_typography.scss +++ b/apps/zui/src/css/shared/_typography.scss @@ -121,17 +121,6 @@ margin: 0; } -.link { - font-family: $body-font; - font-weight: normal; - font-size: 14px; - line-height: 20px; - margin: 0; - text-decoration: underline; - cursor: pointer; - color: var(--havelock); -} - .bold { font-weight: bold; } diff --git a/apps/zui/src/domain/commands.ts b/apps/zui/src/domain/commands.ts deleted file mode 100644 index 929d16691f..0000000000 --- a/apps/zui/src/domain/commands.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./session/commands" diff --git a/apps/zui/src/domain/commands/messages.ts b/apps/zui/src/domain/commands/messages.ts new file mode 100644 index 0000000000..0ff98946bc --- /dev/null +++ b/apps/zui/src/domain/commands/messages.ts @@ -0,0 +1,5 @@ +import * as ops from "./operations" + +export type CommandsOperations = { + "commands.run": typeof ops.run +} diff --git a/apps/zui/src/domain/commands/operations.ts b/apps/zui/src/domain/commands/operations.ts new file mode 100644 index 0000000000..626570021f --- /dev/null +++ b/apps/zui/src/domain/commands/operations.ts @@ -0,0 +1,15 @@ +import {sendToFocusedWindow} from "src/core/ipc" +import {createOperation} from "src/core/operations" +import {commands} from "src/zui" + +export const run = createOperation( + "commands.run", + (ctx, name: string, ...args: any[]) => { + if (commands.has(name)) { + const run = commands.get(name) + run(...args) + } else { + sendToFocusedWindow(name as any, ...(args as any[])) + } + } +) diff --git a/apps/zui/src/domain/commands/plugin-api.ts b/apps/zui/src/domain/commands/plugin-api.ts new file mode 100644 index 0000000000..40f25bc9df --- /dev/null +++ b/apps/zui/src/domain/commands/plugin-api.ts @@ -0,0 +1,25 @@ +export class CommandsApi { + cmds = new Map() + + create(name: string, handler: (...args: any[]) => any) { + if (this.has(name)) { + throw new Error("Command already exists named: " + name) + } + this.cmds.set(name, handler) + } + + has(name: string) { + return this.cmds.has(name) + } + + get(name: string) { + if (!this.has(name)) { + throw new Error("Command not found: " + name) + } + return this.cmds.get(name) + } + + _teardown() { + this.cmds = new Map() + } +} diff --git a/apps/zui/src/domain/editor/handlers.ts b/apps/zui/src/domain/editor/handlers.ts new file mode 100644 index 0000000000..b4c19f5690 --- /dev/null +++ b/apps/zui/src/domain/editor/handlers.ts @@ -0,0 +1,127 @@ +import * as zed from "@brimdata/zed-js" +import program from "src/js/models/program" +import { + appendQueryCountBy, + appendQueryExclude, + appendQueryIn, + appendQueryInclude, + appendQueryNotIn, + appendQuerySortBy, +} from "src/js/flows/searchBar/actions" +import {copyToClipboard} from "src/js/lib/doc" +import Editor from "src/js/state/Editor" +import {toZedScript} from "src/js/zed-script/toZedScript" +import {submitSearch} from "src/domain/session/handlers" +import {createHandler} from "src/core/handlers" +import Selection from "src/js/state/Selection" + +export const copyValueToClipboard = createHandler( + "editor.copyValueToClipboard", + ({select}) => { + const value = select(Selection.getValue) + const selection = document.getSelection() + copyToClipboard( + selection.isCollapsed ? value.toString() : selection.toString() + ) + } +) + +export const countByField = createHandler( + "editor.countByField", + ({select, dispatch}) => { + const field = select(Selection.getField) + dispatch(appendQueryCountBy(field.path)) + submitSearch() + } +) + +export const filterEqualsValue = createHandler( + "editor.filterEqualsValue", + ({select, dispatch}) => { + const field = select(Selection.getField) + dispatch(appendQueryInclude(field)) + submitSearch() + } +) + +export const filterNotEqualsValue = createHandler( + "editor.filterNotEqualsValue", + ({select, dispatch}) => { + const field = select(Selection.getField) + dispatch(appendQueryExclude(field)) + submitSearch() + } +) + +export const filterInField = createHandler( + "editor.filterInField", + ({select, dispatch}) => { + const value = select(Selection.getValue) + const field = select(Selection.getField) + if (value) { + dispatch(appendQueryIn(field, value as zed.Value)) + submitSearch() + } + } +) + +export const filterNotInField = createHandler( + "editor.filterNotInField", + ({select, dispatch}) => { + const value = select(Selection.getValue) + const field = select(Selection.getField) + if (value) { + dispatch(appendQueryNotIn(field, value)) + submitSearch() + } + } +) + +export const newSearchWithValue = createHandler( + "editor.newSearchWithValue", + ({select, dispatch}) => { + const field = select(Selection.getField) + dispatch(Editor.setValue(toZedScript(field.data))) + submitSearch() + } +) + +export const pivotToValues = createHandler( + "editor.pivotToValues", + ({select, dispatch}) => { + const field = select(Selection.getField) + const query = select(Editor.getValue) + // So this only works if the count() by field is in the editor, not in a pin. + const record = field.rootRecord + const newProgram = program(query) + .drillDown(record as zed.Record) + .string() + + if (newProgram) { + dispatch(Editor.setValue(newProgram)) + submitSearch() + } + } +) + +export const sortAsc = createHandler("editor.sortAsc", ({dispatch, select}) => { + const field = select(Selection.getField) + dispatch(appendQuerySortBy(field.path, "asc")) + submitSearch() +}) + +export const sortDesc = createHandler( + "editor.sortDesc", + ({dispatch, select}) => { + const field = select(Selection.getField) + dispatch(appendQuerySortBy(field.path, "desc")) + submitSearch() + } +) + +export const fuse = createHandler("editor.fuse", ({oldApi}) => { + oldApi.editor.append( + oldApi.editor.value.trim().length === 0 ? "fuse" : " | fuse" + ) + submitSearch() +}) diff --git a/apps/zui/src/domain/editor/messages.ts b/apps/zui/src/domain/editor/messages.ts new file mode 100644 index 0000000000..9dbb3e61a6 --- /dev/null +++ b/apps/zui/src/domain/editor/messages.ts @@ -0,0 +1,15 @@ +import * as hds from "./handlers" + +export type EditorHandlers = { + "editor.copyValueToClipboard": typeof hds.copyValueToClipboard + "editor.countByField": typeof hds.countByField + "editor.filterEqualsValue": typeof hds.filterEqualsValue + "editor.filterNotEqualsValue": typeof hds.filterNotEqualsValue + "editor.filterInField": typeof hds.filterInField + "editor.filterNotInField": typeof hds.filterNotInField + "editor.newSearchWithValue": typeof hds.newSearchWithValue + "editor.pivotToValues": typeof hds.pivotToValues + "editor.sortAsc": typeof hds.sortAsc + "editor.sortDesc": typeof hds.sortDesc + "editor.fuse": typeof hds.fuse +} diff --git a/apps/zui/src/domain/handlers.ts b/apps/zui/src/domain/handlers.ts index 62c7f4fceb..33add04859 100644 --- a/apps/zui/src/domain/handlers.ts +++ b/apps/zui/src/domain/handlers.ts @@ -2,9 +2,8 @@ // This gets imported in an initializer import "./results/handlers" -import "./menus/handlers" import "./panes/handlers" import "./window/handlers" -import "./session/handlers" +import "./session/handlers/navigation" import "./loads/handlers" import "./pools/handlers" diff --git a/apps/zui/src/domain/menus.ts b/apps/zui/src/domain/menus.ts deleted file mode 100644 index 979eb0885d..0000000000 --- a/apps/zui/src/domain/menus.ts +++ /dev/null @@ -1 +0,0 @@ -import "./results/toolbar-menu" diff --git a/apps/zui/src/domain/menus/handlers.ts b/apps/zui/src/domain/menus/handlers.ts deleted file mode 100644 index 47d7a1e7b1..0000000000 --- a/apps/zui/src/domain/menus/handlers.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {createHandler} from "src/core/handlers" -import ResultsToolbar from "src/js/state/ResultsToolbar" - -createHandler("menus.update", ({dispatch}, name, id, props) => { - switch (name) { - case "results.toolbarMenu": - return dispatch(ResultsToolbar.update({id, changes: props})) - } -}) diff --git a/apps/zui/src/domain/menus/messages.ts b/apps/zui/src/domain/menus/messages.ts index 862d3a1d16..0733ca9e59 100644 --- a/apps/zui/src/domain/menus/messages.ts +++ b/apps/zui/src/domain/menus/messages.ts @@ -1,5 +1,14 @@ import {MenuItem} from "src/core/menu" +import * as ops from "./operations" export type MenusHandlers = { - "menus.update": (name: string, id: string, props: Partial) => void + "menus.update": ( + menuId: string, + itemId: string, + update: Partial + ) => void +} + +export type MenusOperations = { + "menus.extend": typeof ops.extendMenu } diff --git a/apps/zui/src/domain/menus/operations.ts b/apps/zui/src/domain/menus/operations.ts new file mode 100644 index 0000000000..bb772f9456 --- /dev/null +++ b/apps/zui/src/domain/menus/operations.ts @@ -0,0 +1,12 @@ +import {createOperation} from "src/core/operations" +import {MenuItem, menus} from "src/zui" + +export const extendMenu = createOperation( + "menus.extend", + (_ctx, id: string, items: MenuItem[]) => { + for (let ext of menus.extensions) { + if (ext.id === id) ext.callback(items) + } + return items + } +) diff --git a/apps/zui/src/domain/menus/plugin-api.ts b/apps/zui/src/domain/menus/plugin-api.ts new file mode 100644 index 0000000000..c7d306c2a3 --- /dev/null +++ b/apps/zui/src/domain/menus/plugin-api.ts @@ -0,0 +1,14 @@ +import {sendToFocusedWindow} from "src/core/ipc" +import {MenuItem} from "src/core/menu" + +export class MenusApi { + extensions = [] + + extend(id: string, callback: (items: MenuItem[]) => void) { + this.extensions.push({id, callback}) + } + + updateItem(menuId: string, itemId: string, update: Partial) { + sendToFocusedWindow("menus.update", menuId, itemId, update) + } +} diff --git a/apps/zui/src/domain/messages.ts b/apps/zui/src/domain/messages.ts index 648a67a660..6a25ab059a 100644 --- a/apps/zui/src/domain/messages.ts +++ b/apps/zui/src/domain/messages.ts @@ -1,4 +1,4 @@ -import {MenusHandlers} from "./menus/messages" +import {MenusHandlers, MenusOperations} from "./menus/messages" import {PanesHandlers} from "./panes/messages" import {PoolsHandlers, PoolsOperations} from "./pools/messages" import {ResultsHandlers, ResultsOperations} from "./results/messages" @@ -9,6 +9,8 @@ import {E2EOperations} from "./e2e/messages" import {EnvOperations} from "./env/messages" import {UpdatesOperations} from "./updates/messages" import {LoadsHandlers, LoadsOperations} from "./loads/messages" +import {CommandsOperations} from "./commands/messages" +import {EditorHandlers} from "./editor/messages" export type Handlers = ResultsHandlers & MenusHandlers & @@ -16,7 +18,8 @@ export type Handlers = ResultsHandlers & WindowHandlers & SessionHandlers & LoadsHandlers & - PoolsHandlers + PoolsHandlers & + EditorHandlers export type Operations = PoolsOperations & LegacyOperations & @@ -26,7 +29,9 @@ export type Operations = PoolsOperations & WindowOperations & UpdatesOperations & LoadsOperations & - WindowOperations + WindowOperations & + MenusOperations & + CommandsOperations export type OperationName = keyof Operations export type HandlerName = keyof Handlers diff --git a/apps/zui/src/domain/operations.ts b/apps/zui/src/domain/operations.ts index e118680d78..c2361e1b73 100644 --- a/apps/zui/src/domain/operations.ts +++ b/apps/zui/src/domain/operations.ts @@ -4,3 +4,5 @@ export * as resultsOperations from "./results/operations" export * as envOperations from "./env/operations" export * as loadersOperations from "./loads/operations" export * as windowOperations from "./window/operations" +export * as menusOperations from "./menus/operations" +export * as commandsOperations from "./commands/operations" diff --git a/apps/zui/src/domain/panes/commands.ts b/apps/zui/src/domain/panes/commands.ts deleted file mode 100644 index d12cc420dd..0000000000 --- a/apps/zui/src/domain/panes/commands.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {createCommand} from "src/core/command" -import {PaneName} from "src/js/state/Layout/types" -import {panes} from "src/zui" - -export const activate = createCommand("panes.activate", (name: PaneName) => { - panes.activate(name) -}) diff --git a/apps/zui/src/domain/plugin-api.ts b/apps/zui/src/domain/plugin-api.ts index ea6d965a77..443aae9cf6 100644 --- a/apps/zui/src/domain/plugin-api.ts +++ b/apps/zui/src/domain/plugin-api.ts @@ -1,8 +1,10 @@ +import {CommandsApi} from "./commands/plugin-api" import {AppApi} from "./app/plugin-api" import {ConfigurationsApi} from "./configurations/plugin-api" import {CorrelationsApi} from "./correlations/plugin-api" import {EnvApi} from "./env/plugin-api" import {LoadsApi} from "./loads/plugin-api" +import {MenusApi} from "./menus/plugin-api" import {PanesApi} from "./panes/plugin-api" import {PoolsApi} from "./pools/plugin-api" import {ResultsApi} from "./results/plugin-api" @@ -20,4 +22,6 @@ export const session = new SessionApi() export const correlations = new CorrelationsApi() export const configurations = new ConfigurationsApi() export const pools = new PoolsApi() +export const menus = new MenusApi() export const app = new AppApi() +export const commands = new CommandsApi() diff --git a/apps/zui/src/domain/results/commands.ts b/apps/zui/src/domain/results/commands.ts deleted file mode 100644 index b376820c25..0000000000 --- a/apps/zui/src/domain/results/commands.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {createCommand} from "src/core/command" -import {results} from "src/zui" - -export const expandAll = createCommand("results.expandAll", () => { - results.expandAll() -}) - -export const collapseAll = createCommand("results.collapseAll", () => { - results.collapseAll() -}) - -export const showExportDialog = createCommand( - "results.showExportDialog", - () => { - results.showExportDialog() - } -) - -export const toggleHistogram = createCommand("results.toggleHistogram", () => { - results.toggleHistogram() -}) diff --git a/apps/zui/src/domain/results/handlers.ts b/apps/zui/src/domain/results/handlers.ts index 5143234704..94364680e1 100644 --- a/apps/zui/src/domain/results/handlers.ts +++ b/apps/zui/src/domain/results/handlers.ts @@ -3,6 +3,9 @@ import Inspector from "src/js/state/Inspector" import Layout from "src/js/state/Layout" import Modal from "src/js/state/Modal" import Table from "src/js/state/Table" +import {objectify} from "src/util/objectify" +import {find, getDecendentIds, walk} from "src/util/tree" +import {runHistogramQuery} from "src/views/histogram-pane/run-query" export const expandAllHandler = createHandler( "results.expandAll", @@ -15,10 +18,8 @@ export const expandAllHandler = createHandler( export const collapseAllHandler = createHandler( "results.collapseAll", ({dispatch, select}) => { - console.log("collapseAllHandler") const view = select(Layout.getEffectiveResultsView) - console.log(view) if (view === "INSPECTOR") { dispatch(Inspector.setExpanded({})) dispatch(Inspector.setExpandedDefault(false)) @@ -28,7 +29,7 @@ export const collapseAllHandler = createHandler( } ) -export const showExportDialogHandler = createHandler( +export const showExportDialog = createHandler( "results.showExportDialog", ({dispatch}) => { dispatch(Modal.show("export")) @@ -37,5 +38,91 @@ export const showExportDialogHandler = createHandler( export const toggleHistogram = createHandler( "results.toggleHistogram", - ({dispatch}) => dispatch(Layout.toggleHistogram()) + ({dispatch, select, oldApi}) => { + const isShown = select(Layout.getShowHistogram) + if (!isShown) runHistogramQuery(oldApi) + dispatch(Layout.toggleHistogram()) + } ) + +export const showTableView = createHandler((ctx) => { + ctx.transition(() => { + ctx.dispatch(Layout.setResultsView("TABLE")) + }) +}) + +export const showInspectorView = createHandler((ctx) => { + ctx.transition(() => { + ctx.dispatch(Layout.setResultsView("INSPECTOR")) + }) +}) + +export const showChartView = createHandler((ctx) => { + ctx.transition(() => { + ctx.dispatch(Layout.setResultsView("CHART")) + }) +}) + +export const expandColumn = createHandler((ctx, id: string) => { + ctx.dispatch(Table.expandColumn(id)) +}) + +export const collapseColumn = createHandler((ctx, id: string) => { + ctx.dispatch(Table.collapseColumn(id)) +}) + +export const showColumn = createHandler(({select, dispatch}, id: string) => { + const all = select(Table.getNestedColumns) + const prev = select(Table.getColumnVisible) + const column = find(all, id) + if (!column) throw new Error("No Column Found with id " + id) + const ids = getDecendentIds(column) + const state = objectify(ids, true) + dispatch(Table.setColumnVisible({...prev, ...state})) +}) + +export const hideColumn = createHandler(({select, dispatch}, id: string) => { + const all = select(Table.getNestedColumns) + const prev = select(Table.getColumnVisible) + const column = find(all, id) + if (!column) throw new Error("No Column Found with id " + id) + const ids = getDecendentIds(column) + const state = objectify(ids, false) + dispatch(Table.setColumnVisible({...prev, ...state})) +}) + +export const showAllColumns = createHandler(({select, dispatch}) => { + const cols = select(Table.getNestedColumns) + let ids = [] + for (let col of cols) ids = ids.concat(getDecendentIds(col)) + let state = objectify(ids, true) + dispatch(Table.setColumnVisible(state)) +}) + +export const hideAllColumns = createHandler(({select, dispatch}) => { + const cols = select(Table.getNestedColumns) + let ids = [] + for (let col of cols) ids = ids.concat(getDecendentIds(col)) + let state = objectify(ids, false) + dispatch(Table.setColumnVisible(state)) +}) + +export const expandAllColumns = createHandler(({select, dispatch}) => { + const cols = select(Table.getNestedColumns) + const ids = [] + walk(cols, (col) => { + if (col.children) ids.push(col.id) + }) + let state = objectify(ids, true) + dispatch(Table.setColumnExpanded(state)) +}) + +export const collapseAllColumns = createHandler(({select, dispatch}) => { + const cols = select(Table.getNestedColumns) + const ids = [] + walk(cols, (col) => { + if (col.children) ids.push(col.id) + }) + let state = objectify(ids, false) + dispatch(Table.setColumnExpanded(state)) +}) diff --git a/apps/zui/src/domain/results/toolbar-menu.ts b/apps/zui/src/domain/results/toolbar-menu.ts deleted file mode 100644 index 23c21d9aeb..0000000000 --- a/apps/zui/src/domain/results/toolbar-menu.ts +++ /dev/null @@ -1,39 +0,0 @@ -import {createMenu} from "src/core/menu/menu-node" -import * as results from "./commands" -import * as panes from "../panes/commands" -import {PaneName} from "src/js/state/Layout/types" - -createMenu("results.toolbarMenu", [ - { - label: "Expand", - description: "Expand all container values", - iconName: "expand", - command: results.expandAll.id, - when: "results.view == inspector", - }, - { - label: "Collapse", - description: "Collapse all container values", - iconName: "collapse", - command: results.collapseAll.id, - }, - { - label: "Export", - description: "Export search results to file", - iconName: "export", - command: results.showExportDialog.id, - }, - { - label: "Columns", - description: "Show or hide columns in the table", - iconName: "columns", - command: panes.activate.id, - args: ["columns" as PaneName], - }, - { - label: "Histogram", - iconName: "chart", - description: "Toggle the histogram", - command: results.toggleHistogram.id, - }, -]) diff --git a/apps/zui/src/domain/session/commands.ts b/apps/zui/src/domain/session/commands.ts deleted file mode 100644 index e6a30a227e..0000000000 --- a/apps/zui/src/domain/session/commands.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {createCommand} from "src/core/command" -import {session} from "src/zui" - -export const goBack = createCommand("session.goBack", () => { - session.goBack() -}) - -export const goForward = createCommand("session.goForward", () => { - session.goForward() -}) diff --git a/apps/zui/src/domain/session/handlers.ts b/apps/zui/src/domain/session/handlers.ts deleted file mode 100644 index 424c2809f3..0000000000 --- a/apps/zui/src/domain/session/handlers.ts +++ /dev/null @@ -1,10 +0,0 @@ -import tabHistory from "src/app/router/tab-history" -import {createHandler} from "src/core/handlers" - -createHandler("session.goBack", ({dispatch}) => { - dispatch(tabHistory.goBack()) -}) - -createHandler("session.goForward", ({dispatch}) => { - dispatch(tabHistory.goForward()) -}) diff --git a/apps/zui/src/domain/session/handlers/index.ts b/apps/zui/src/domain/session/handlers/index.ts new file mode 100644 index 0000000000..86b3ed9712 --- /dev/null +++ b/apps/zui/src/domain/session/handlers/index.ts @@ -0,0 +1,4 @@ +export * from "./navigation" +export * from "./queries" +export * from "./submit-search" +export * from "./pins" diff --git a/apps/zui/src/domain/session/handlers/navigation.ts b/apps/zui/src/domain/session/handlers/navigation.ts new file mode 100644 index 0000000000..9156e3afc8 --- /dev/null +++ b/apps/zui/src/domain/session/handlers/navigation.ts @@ -0,0 +1,63 @@ +import tabHistory from "src/app/router/tab-history" +import {createHandler} from "src/core/handlers" +import Current from "src/js/state/Current" +import * as zed from "@brimdata/zed-js" +import virusTotal from "src/js/services/virusTotal" +import Modal from "src/js/state/Modal" +import {invoke} from "src/core/invoke" +import {activatePane} from "src/domain/window/handlers" +import Selection from "src/js/state/Selection" +import LogDetails from "src/js/state/LogDetails" + +export const goBack = createHandler("session.goBack", ({dispatch}) => { + dispatch(tabHistory.goBack()) +}) + +export const goForward = createHandler("session.goForward", ({dispatch}) => { + dispatch(tabHistory.goForward()) +}) + +export const canGoBack = createHandler("session.canGoBack", ({select}) => { + return select(Current.getHistory).canGo(-1) +}) + +export const canGoForward = createHandler( + "session.canGoForward", + ({select}) => { + return select(Current.getHistory).canGo(1) + } +) + +export const toggleHistoryPane = createHandler( + "session.toggleHistoryPane", + () => activatePane("history") +) + +export const showValueDetails = createHandler( + "session.showValueDetails", + ({dispatch, select}) => { + const value = select(Selection.getRootValue) + dispatch(LogDetails.push(value as any)) + activatePane("detail") + } +) + +export const showWhoIs = createHandler( + "session.showWhoIs", + ({dispatch, select}) => { + const value = select(Selection.getValue) + dispatch(Modal.show("whois", {addr: value.toString()})) + } +) + +export const openVirusTotal = createHandler( + "session.openVirusTotal", + ({select}) => { + const value = select(Selection.getValue) + if (value instanceof zed.Primitive && !value.isUnset()) { + invoke("openLinkOp", virusTotal.url(value.toString())) + } else { + console.error("Could not open this value with virus total") + } + } +) diff --git a/apps/zui/src/domain/session/handlers/pins.ts b/apps/zui/src/domain/session/handlers/pins.ts new file mode 100644 index 0000000000..0b9c4135dd --- /dev/null +++ b/apps/zui/src/domain/session/handlers/pins.ts @@ -0,0 +1,165 @@ +import * as zed from "@brimdata/zed-js" +import {DateTuple} from "src/js/lib/TimeWindow" +import Editor from "src/js/state/Editor" +import {TimeRangeQueryPin} from "src/js/state/Editor/types" +import Pools from "src/js/state/Pools" +import Current from "src/js/state/Current" +import PoolSettings from "src/js/state/PoolSettings" +import Tabs from "src/js/state/Tabs" +import {submitSearch} from "src/domain/session/handlers" +import {createHandler} from "src/core/handlers" +import ZuiApi from "src/js/api/zui-api" +import Selection from "src/js/state/Selection" + +export const createPinFromEditor = createHandler( + "session.createPinFromEditor", + ({dispatch, oldApi}) => { + if (oldApi.editor.value.trim() === "") return + dispatch(Editor.pinValue()) + submitSearch() + } +) + +export const createPin = createHandler( + "session.createPin", + ({dispatch, oldApi}) => { + dispatch(Editor.addPin({type: "generic", value: ""})) + dispatch(Editor.editPin(oldApi.editor.pins.length - 1)) + } +) + +export const createFromPin = createHandler( + "session.createFromPin", + ({dispatch, oldApi}, value = "") => { + dispatch(Editor.addPin({type: "from", value})) + if (value.length === 0) { + dispatch(Editor.editPin(oldApi.editor.pins.length - 1)) + } else { + submitSearch() + } + } +) + +export const setFromPin = createHandler( + "session.setFromPin", + ({dispatch, select, oldApi}, value: string) => { + if (select(Tabs.none)) { + oldApi.queries.open({pins: [{type: "from", value}], value: ""}) + } else { + dispatch(Editor.setFrom(value)) + submitSearch() + } + } +) + +function defaultFrom(now: Date) { + return new Date( + Date.UTC(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0) + ) +} + +function defaultTo(now: Date) { + return new Date( + Date.UTC(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0, 0) + ) +} + +async function defaultRange(oldApi: ZuiApi): Promise { + const range = await oldApi.dispatch( + Pools.getTimeRange(oldApi.current.poolName) + ) + const now = new Date() + const from = (range && range[0]) || defaultFrom(now) + const to = (range && range[1]) || defaultTo(now) + return [from, to] +} + +export const createTimeRangePin = createHandler( + "session.createTimeRangePin", + async ({dispatch, oldApi, select}) => { + const pins = select(Editor.getPins) + const [from, to] = await defaultRange(oldApi) + const poolId = select(Current.getPoolFromQuery)?.id + const {timeField} = select((s) => PoolSettings.findWithDefaults(s, poolId)) + dispatch( + Editor.addPin({ + type: "time-range", + field: timeField, + from: from.toISOString(), + to: to.toISOString(), + }) + ) + dispatch(Editor.editPin(pins.length)) + } +) + +function currentRange(oldApi: ZuiApi) { + const pin = oldApi.editor.pins.find( + (p) => p.type === "time-range" + ) as TimeRangeQueryPin + if (pin) return [new Date(pin.from), new Date(pin.to)] as const + else return null +} + +export const setTimeRangeFrom = createHandler( + "session.setTimeRangeFrom", + async ({oldApi, select}) => { + const value = select(Selection.getValue) + if (!(value instanceof zed.Time)) return + const current = currentRange(oldApi) + const defaults = await defaultRange(oldApi) + const from = value.toDate() + const to = current ? current[1] : defaults[1] + oldApi.dispatch(Editor.setTimeRange({from, to})) + submitSearch() + } +) + +export const setTimeRangeTo = createHandler( + "session.setTimeRangeTo", + async ({oldApi, select}) => { + const value = select(Selection.getValue) + if (!(value instanceof zed.Time)) return + const current = currentRange(oldApi) + const defaults = await defaultRange(oldApi) + const from = current ? current[0] : defaults[0] + const to = value.toDate() + oldApi.dispatch(Editor.setTimeRange({from, to})) + submitSearch() + } +) + +export const disablePin = createHandler(({dispatch}, index: number) => { + dispatch(Editor.disablePin(index)) + submitSearch() +}) + +export const disableOthers = createHandler(({dispatch}, index: number) => { + dispatch(Editor.disableOtherPins(index)) + submitSearch() +}) + +export const enablePin = createHandler(({dispatch}, index: number) => { + dispatch(Editor.enablePin(index)) + submitSearch() +}) + +export const enableOthers = createHandler(({dispatch}, index: number) => { + dispatch(Editor.enableOtherPins(index)) + submitSearch() +}) + +export const deletePin = createHandler(({dispatch}, index: number) => { + dispatch(Editor.deletePin(index)) + submitSearch() +}) + +export const deleteToTheRight = createHandler(({dispatch}, index: number) => { + dispatch(Editor.deletePinsToTheRight(index)) + submitSearch() +}) + +export const deleteAll = createHandler(({dispatch}) => { + dispatch(Editor.deleteAllPins()) + submitSearch() +}) diff --git a/apps/zui/src/domain/session/handlers/queries.ts b/apps/zui/src/domain/session/handlers/queries.ts new file mode 100644 index 0000000000..b1ec16040c --- /dev/null +++ b/apps/zui/src/domain/session/handlers/queries.ts @@ -0,0 +1,50 @@ +import {createHandler} from "src/core/handlers" +import Current from "src/js/state/Current" +import Editor from "src/js/state/Editor" +import Layout from "src/js/state/Layout" +import {plusOne} from "src/util/plus-one" +import {submitSearch} from "./submit-search" + +export const editQuery = createHandler("session.editQuery", ({dispatch}) => { + dispatch(Layout.showTitleForm()) +}) + +export const updateQuery = createHandler( + "session.updateQuery", + ({select, oldApi}) => { + const snapshot = select(Editor.getSnapshot) + const active = select(Current.getActiveQuery) + const id = active.query.id + oldApi.queries.addVersion(id, snapshot) + oldApi.queries.open(id, {history: "replace"}) + } +) + +export const runQuery = createHandler("session.runQuery", () => { + submitSearch() +}) + +export const saveAsNewQuery = createHandler( + "session.saveAsNewQuery", + async ({select, oldApi, dispatch}) => { + const name = select(Current.getActiveQuery).name() + const attrs = select(Editor.getSnapshot) + const newName = plusOne(name) + const query = await oldApi.queries.create({ + name: newName, + versions: [attrs], + }) + oldApi.queries.open(query.id) + setTimeout(() => { + dispatch(Layout.showTitleForm()) + }) + } +) + +export const resetQuery = createHandler( + "session.resetQuery", + ({select, oldApi}) => { + const snapshot = select(Editor.getSnapshot) + oldApi.queries.open(snapshot) + } +) diff --git a/apps/zui/src/domain/session/handlers/submit-search.ts b/apps/zui/src/domain/session/handlers/submit-search.ts new file mode 100644 index 0000000000..fbb2e57bbf --- /dev/null +++ b/apps/zui/src/domain/session/handlers/submit-search.ts @@ -0,0 +1,42 @@ +import Current from "src/js/state/Current" +import Editor from "src/js/state/Editor" +import Results from "src/js/state/Results" +import QueryVersions from "../../../js/state/QueryVersions" +import {QueryModel} from "../../../js/models/query-model" +import {RESULTS_QUERY} from "src/views/results-pane/run-results-query" +import Table from "src/js/state/Table" +import Inspector from "src/js/state/Inspector" +import {createHandler} from "src/core/handlers" +import Selection from "src/js/state/Selection" + +export const submitSearch = createHandler((ctx) => { + const {dispatch, select, oldApi} = ctx + const api = oldApi + + dispatch(Selection.reset()) + dispatch(Table.setScrollPosition({top: 0, left: 0})) + dispatch(Inspector.setScrollPosition({top: 0, left: 0})) + + const nextVersion = select(Editor.getSnapshot) + const active = select(Current.getActiveQuery) + const error = QueryModel.checkSyntax(nextVersion) + + // An error with the syntax + if (error) { + const tabId = select(Current.getTabId) + dispatch(Results.error({id: RESULTS_QUERY, error, tabId})) + return + } + + // Reuse the version url if the next version is the same as the latest + // of this query, either session or saved. + if (QueryVersions.areEqual(active.version, nextVersion)) { + api.queries.open(active.id(), {version: active.versionId()}) + return + } + + // This is a new query, add a new version to the session, + // And open the current active query with the version set to the new one. + api.queries.addVersion(active.session.id, nextVersion) + api.queries.open(active.id(), {version: nextVersion.version}) +}) diff --git a/apps/zui/src/domain/session/menus/choose-pool-menu.ts b/apps/zui/src/domain/session/menus/choose-pool-menu.ts new file mode 100644 index 0000000000..3e473535d7 --- /dev/null +++ b/apps/zui/src/domain/session/menus/choose-pool-menu.ts @@ -0,0 +1,17 @@ +import Current from "src/js/state/Current" +import Pools from "src/js/state/Pools" +import {setFromPin} from "../handlers" +import {createMenu} from "src/core/menu" + +export const choosePoolMenu = createMenu(({select}) => { + const lakeId = select(Current.getLakeId) + const pools = select(Pools.getPools(lakeId)).sort() + if (!pools.length) { + return [{label: "No Pools", enabled: false}] + } else { + return pools.map((pool) => ({ + label: pool.name, + click: () => setFromPin(pool.name), + })) + } +}) diff --git a/apps/zui/src/domain/session/menus/edit-pin.menu.ts b/apps/zui/src/domain/session/menus/edit-pin.menu.ts new file mode 100644 index 0000000000..b011b8e8db --- /dev/null +++ b/apps/zui/src/domain/session/menus/edit-pin.menu.ts @@ -0,0 +1,44 @@ +import Editor from "src/js/state/Editor" +import * as handlers from "../handlers/pins" +import {createMenu} from "src/core/menu" + +export const editPinMenu = createMenu(({select}, index: number) => { + const pins = select(Editor.getPins) + const pin = pins[index] + return [ + { + label: "Disable", + enabled: !pin.disabled, + click: () => handlers.disablePin(index), + }, + { + label: "Disable Others", + enabled: pins.some((p) => !p.disabled), + click: () => handlers.disableOthers(index), + }, + {type: "separator"}, + { + label: "Enable", + enabled: !!pin.disabled, + click: () => handlers.enablePin(index), + }, + { + label: "Enable Others", + enabled: pins.some((p) => p.disabled), + click: () => handlers.enableOthers(index), + }, + {type: "separator"}, + { + label: "Delete", + click: () => handlers.deletePin(index), + }, + { + label: "Delete to the Right", + click: () => handlers.deleteToTheRight(index), + }, + { + label: "Delete All", + click: () => handlers.deleteAll(), + }, + ] +}) diff --git a/apps/zui/src/domain/session/menus/toolbar-menu.ts b/apps/zui/src/domain/session/menus/toolbar-menu.ts new file mode 100644 index 0000000000..564df25372 --- /dev/null +++ b/apps/zui/src/domain/session/menus/toolbar-menu.ts @@ -0,0 +1,58 @@ +import {createMenu} from "src/core/menu" +import {ActiveQuery} from "src/app/core/models/active-query" + +export const sessionToolbarMenu = createMenu((_, query: ActiveQuery) => { + return [ + { + label: "Update Query", + command: "session.updateQuery", + iconName: "check", + visible: query.isModified(), + }, + { + label: "Detach from Query", + command: "session.resetQuery", + iconName: "close_circle", + visible: query.isSaved(), + }, + { + label: "Save as New Query", + command: "session.saveAsNewQuery", + iconName: "add", + }, + { + label: "New Pin", + iconName: "pin", + nestedMenu: [ + { + label: "New 'From' Pin", + command: "session.createFromPin", + }, + { + label: "New 'Time Range' Pin", + command: "session.createTimeRangePin", + }, + { + label: "New Zed Snippet Pin", + command: "session.createPin", + }, + {type: "separator"}, + { + label: "Pin Editor Value", + command: "session.createPinFromEditor", + }, + ], + }, + { + id: "export-results", + label: "Export Results", + iconName: "export", + command: "results.showExportDialog", + }, + { + label: "Run Query", + iconName: "run", + command: "session.runQuery", + }, + ] +}) diff --git a/apps/zui/src/domain/session/messages.ts b/apps/zui/src/domain/session/messages.ts index 5f3e7daad0..bd59b57eba 100644 --- a/apps/zui/src/domain/session/messages.ts +++ b/apps/zui/src/domain/session/messages.ts @@ -1,4 +1,24 @@ +import * as handlers from "./handlers" + export type SessionHandlers = { - "session.goBack": () => void - "session.goForward": () => void + "session.goBack": typeof handlers.goBack + "session.goForward": typeof handlers.goForward + "session.canGoBack": typeof handlers.canGoBack + "session.canGoForward": typeof handlers.canGoForward + "session.createPinFromEditor": typeof handlers.createPinFromEditor + "session.editQuery": typeof handlers.editQuery + "session.updateQuery": typeof handlers.updateQuery + "session.runQuery": typeof handlers.runQuery + "session.saveAsNewQuery": typeof handlers.saveAsNewQuery + "session.resetQuery": typeof handlers.resetQuery + "session.toggleHistoryPane": typeof handlers.toggleHistoryPane + "session.createFromPin": typeof handlers.createFromPin + "session.createPin": typeof handlers.createPin + "session.setFromPin": typeof handlers.setFromPin + "session.createTimeRangePin": typeof handlers.createTimeRangePin + "session.setTimeRangeFrom": typeof handlers.setTimeRangeFrom + "session.setTimeRangeTo": typeof handlers.setTimeRangeTo + "session.showWhoIs": typeof handlers.showWhoIs + "session.openVirusTotal": typeof handlers.openVirusTotal + "session.showValueDetails": typeof handlers.showValueDetails } diff --git a/apps/zui/src/domain/window/handlers.ts b/apps/zui/src/domain/window/handlers.ts index 5e86d713e1..0e199d6766 100644 --- a/apps/zui/src/domain/window/handlers.ts +++ b/apps/zui/src/domain/window/handlers.ts @@ -3,6 +3,9 @@ import toast from "react-hot-toast" import Tabs from "src/js/state/Tabs" import {welcomePath} from "src/app/router/utils/paths" import {QueryParams} from "src/js/api/queries/types" +import {PaneName} from "src/js/state/Layout/types" +import Appearance from "src/js/state/Appearance" +import Layout from "src/js/state/Layout" export const showErrorMessage = createHandler( "window.showErrorMessage", @@ -47,3 +50,22 @@ export const openTab = createHandler( dispatch(Tabs.activateUrl(path)) } ) + +export const activatePane = createHandler(({dispatch}, name: PaneName) => { + dispatch(Appearance.showSecondarySidebar()) + dispatch(Layout.setCurrentPaneName(name)) +}) + +export const togglePane = createHandler( + ({select, dispatch}, name: PaneName) => { + if ( + select(Appearance.secondarySidebarIsOpen) && + select(Layout.getCurrentPaneName) === name + ) { + dispatch(Appearance.toggleSecondarySidebar()) + } else { + dispatch(Appearance.showSecondarySidebar()) + dispatch(Layout.setCurrentPaneName(name)) + } + } +) diff --git a/apps/zui/src/electron/html-dialog/dialog.html b/apps/zui/src/electron/html-dialog/dialog.html deleted file mode 100644 index 976440e223..0000000000 --- a/apps/zui/src/electron/html-dialog/dialog.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Zui - - - - - -
- - - diff --git a/apps/zui/src/electron/html-dialog/dialog.style.tsx b/apps/zui/src/electron/html-dialog/dialog.style.tsx deleted file mode 100644 index 214f75d8b6..0000000000 --- a/apps/zui/src/electron/html-dialog/dialog.style.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import styled from "styled-components" - -export const BG = styled.div` - padding: 22px; - font-family: system-ui; - height: 100%; - width: 100%; - overflow: hidden; - - .icon { - padding: 0 22px; - opacity: 0.33; - svg { - width: 60px; - height: 60px; - } - } - - main { - font-size: 14px; - letter-spacing: 0.2px; - display: flex; - } - - h1 { - font-size: 16px; - font-weight: 700; - letter-spacing: 0.2px; - } - - footer { - display: flex; - justify-content: flex-end; - margin-top: 22px; - text-align: right; - } -` diff --git a/apps/zui/src/electron/html-dialog/dialog.tsx b/apps/zui/src/electron/html-dialog/dialog.tsx deleted file mode 100644 index af6b9ca1d6..0000000000 --- a/apps/zui/src/electron/html-dialog/dialog.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import Markdown from "src/app/core/components/markdown" -import useKeybinding from "src/app/core/hooks/use-keybinding" -import Icon from "src/app/core/icon-temp" -import parseSearchParams from "src/app/core/utils/parse-search-params" -import ToolbarButton from "src/app/query-home/toolbar/actions/button" -import {ipcRenderer} from "electron" -import React, {useEffect} from "react" -import theme from "src/js/style-theme" -import {ThemeProvider} from "styled-components" -import {BG} from "./dialog.style" -import {closeChannel, readyChannel} from "./index" -import {createRoot} from "react-dom/client" - -const ROOT_ID = "root" -/** - * These come from the main process - */ -const {title, content, id} = parseSearchParams() - -/** - * This can expand and can offer custom buttons, but for now it just lets - * you render markdown in a simple error dialog window. - */ -function ErrorDialog() { - const close = () => ipcRenderer.send(closeChannel(id)) - const ready = (height: number) => ipcRenderer.send(readyChannel(id), height) - - useEffect(() => { - ready(document.getElementById(ROOT_ID).clientHeight) - }, []) - - useKeybinding(["meta+.", "esc", "enter"], close) - - return ( - - -
- -
-

{title}

- {content} -
-
-
- close()} isPrimary /> -
-
-
- ) -} - -createRoot(document.getElementById(ROOT_ID)).render() diff --git a/apps/zui/src/electron/html-dialog/index.ts b/apps/zui/src/electron/html-dialog/index.ts deleted file mode 100644 index ec0396c722..0000000000 --- a/apps/zui/src/electron/html-dialog/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {nanoid} from "@reduxjs/toolkit" -import {BrowserWindow, ipcMain, Menu} from "electron" -import {join} from "path" - -const makeChannel = (name) => (id) => [`__html-dialog__`, id, name].join(":") -export const readyChannel = makeChannel("ready") -export const closeChannel = makeChannel("close") - -class HTMLDialog { - showErrorBox(title: string, content: string) { - const id = nanoid() - let win: BrowserWindow - return new Promise((resolve) => { - win = new BrowserWindow({ - width: 500, - height: 300, - resizable: false, - useContentSize: true, - minimizable: false, - maximizable: false, - modal: true, - show: false, - backgroundColor: "#F5F5F5", - webPreferences: { - nodeIntegration: true, - contextIsolation: false, - }, - }) - // This will remove the menu bar on windows and linux from the top of the window. - Menu.setApplicationMenu(null) - - win.loadFile(join(__dirname, "dialog.html"), { - query: {title, content, id}, - }) - - ipcMain.once(closeChannel(id), () => { - win.close() - }) - - ipcMain.once(readyChannel(id), (e, height) => { - win.setContentSize(500, height) - win.show() - }) - - win.on("close", () => resolve()) - }) - } -} - -export default new HTMLDialog() diff --git a/apps/zui/src/electron/ops/get-menu-template-op.ts b/apps/zui/src/electron/ops/get-menu-template-op.ts deleted file mode 100644 index 64c9cc300c..0000000000 --- a/apps/zui/src/electron/ops/get-menu-template-op.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {menus} from "src/zui" -import {createOperation} from "../../core/operations" - -export const getMenuTemplateOp = createOperation( - "getMenuTemplateOp", - (_, name: string) => { - return menus.get(name).template - } -) -export type GetMenuTemplateOp = typeof getMenuTemplateOp diff --git a/apps/zui/src/electron/ops/import-queries-op.test.ts b/apps/zui/src/electron/ops/import-queries-op.test.ts index ca1f8d1935..2b2e8d719c 100644 --- a/apps/zui/src/electron/ops/import-queries-op.test.ts +++ b/apps/zui/src/electron/ops/import-queries-op.test.ts @@ -1,15 +1,14 @@ +/** + * @jest-environment jsdom + */ + import "src/test/system/real-paths" import {getPath} from "zui-test-data" -import {main} from "../run-main/run-main" import {importQueriesOp} from "./import-queries-op" +import initTestStore from "src/test/unit/helpers/initTestStore" beforeEach(async () => { - await main({ - lake: false, - devtools: false, - releaseNotes: false, - autoUpdater: false, - }) + await initTestStore() }) test("import valid queries", () => { diff --git a/apps/zui/src/electron/ops/index.ts b/apps/zui/src/electron/ops/index.ts index 3b01e55e07..bc88ec09d9 100644 --- a/apps/zui/src/electron/ops/index.ts +++ b/apps/zui/src/electron/ops/index.ts @@ -8,11 +8,9 @@ export * as getAppMetaOp from "./get-app-meta-op" export * as getConfigurationsOp from "./get-configurations-op" export * as getCorrelationsOp from "./get-correlations-op" export * as getGlobalStateOp from "./get-global-state-op" -export * as getMenuTemplateOp from "./get-menu-template-op" export * as getWindowStateOp from "./get-window-state-op" export * as globalDispatchOp from "./global-dispatch-op" export * as importQueriesOp from "./import-queries-op" -export * as invokeCommandOp from "./invoke-command-op" export * as mainArgsOp from "./main-args-op" export * as moveToCurrentDisplayOp from "./move-to-current-display-op" export * as openAboutWindowOp from "./open-about-window-op" diff --git a/apps/zui/src/electron/ops/invoke-command-op.ts b/apps/zui/src/electron/ops/invoke-command-op.ts deleted file mode 100644 index b7f2337f33..0000000000 --- a/apps/zui/src/electron/ops/invoke-command-op.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {commands} from "src/core/command" -import {createOperation} from "../../core/operations" - -export const invokeCommandOp = createOperation( - "invokeCommandOp", - (_, id: string, args?: any[]) => { - return commands.get(id).run(...(args ?? [])) - } -) - -export type InvokeCommandOp = typeof invokeCommandOp diff --git a/apps/zui/src/electron/run-main/run-protocol-handlers.ts b/apps/zui/src/electron/run-main/run-protocol-handlers.ts index 8acd856987..d7d18037f6 100644 --- a/apps/zui/src/electron/run-main/run-protocol-handlers.ts +++ b/apps/zui/src/electron/run-main/run-protocol-handlers.ts @@ -4,8 +4,9 @@ import path from "path" export function runProtocolHandlers() { app.whenReady().then(() => { protocol.interceptFileProtocol("file", (request, callback) => { + const url = new URL(request.url) const rootPath = path.join(__dirname, "..", "out") - const relPath = request.url.slice("file://".length).split("?")[0] + const relPath = url.pathname const absPath = path.join(rootPath, relPath) callback(absPath) }) diff --git a/apps/zui/src/electron/windows-pre-25.ts b/apps/zui/src/electron/windows-pre-25.ts index d1af2f7f9c..ffe82244d6 100644 --- a/apps/zui/src/electron/windows-pre-25.ts +++ b/apps/zui/src/electron/windows-pre-25.ts @@ -1,8 +1,7 @@ -import {app} from "electron" +import {app, dialog} from "electron" import fs from "fs-extra" import os from "os" import {join} from "path" -import htmlDialog from "./html-dialog" const VAR = "LocalAppData" @@ -35,11 +34,12 @@ export async function windowsPre25Exists() { if (!fs.existsSync(exe)) return false await app.whenReady() - await htmlDialog.showErrorBox( + dialog.showErrorBox( "Previous Version Detected", `Please uninstall it before before launching the new version. -[Show me how...](https://github.com/brimdata/brim/wiki/Installation#windows-installation-v0250)` +Show me how... +https://github.com/brimdata/brim/wiki/Installation#windows-installation-v0250` ) return true } diff --git a/apps/zui/src/electron/windows/search/app-menu.ts b/apps/zui/src/electron/windows/search/app-menu.ts index 8d0d28f53d..22a1661b00 100644 --- a/apps/zui/src/electron/windows/search/app-menu.ts +++ b/apps/zui/src/electron/windows/search/app-menu.ts @@ -1,5 +1,4 @@ import {app, MenuItemConstructorOptions, shell, Menu} from "electron" -import {createFromEditor} from "src/app/commands/pins" import env from "src/app/core/env" import links from "src/app/core/links" import pkg from "src/electron/pkg" @@ -8,7 +7,6 @@ import {moveToCurrentDisplayOp} from "../../ops/move-to-current-display-op" import {openAboutWindowOp} from "../../ops/open-about-window-op" import {openSearchWindowOp} from "../../ops/open-search-window-op" import {resetStateOp} from "../../ops/reset-state-op" -import {runCommandOp} from "../../ops/run-command-op" import {showPreferencesOp} from "../../ops/show-preferences-op" import {showReleaseNotesOp} from "../../ops/show-release-notes-op" import {SearchWindow} from "./search-window" @@ -191,7 +189,7 @@ export function compileTemplate( { label: "Pin Search", accelerator: "CmdOrCtrl+K", - click: () => runCommandOp(createFromEditor), + click: () => sendToFocusedWindow("session.createPinFromEditor"), }, { label: "Clear Pins", diff --git a/apps/zui/src/electron/windows/search/search-window.ts b/apps/zui/src/electron/windows/search/search-window.ts index 38901c4f98..1809df16b8 100644 --- a/apps/zui/src/electron/windows/search/search-window.ts +++ b/apps/zui/src/electron/windows/search/search-window.ts @@ -10,6 +10,8 @@ export class SearchWindow extends ZuiWindow { path = "/search" options: BrowserWindowConstructorOptions = { titleBarStyle: env.isMac ? "hidden" : undefined, + vibrancy: "sidebar", + backgroundColor: env.isMac ? undefined : "#F3F3F3", trafficLightPosition: {x: 16, y: 13}, resizable: true, minWidth: 480, diff --git a/apps/zui/src/initializers/commands.ts b/apps/zui/src/initializers/commands.ts deleted file mode 100644 index 78aa19d5e7..0000000000 --- a/apps/zui/src/initializers/commands.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Import all the commands so that they get registered in the command center - -import "src/domain/commands" - -export function initialize() { - // No op -} diff --git a/apps/zui/src/initializers/index.ts b/apps/zui/src/initializers/index.ts index 93dfda7a00..8230ecb997 100644 --- a/apps/zui/src/initializers/index.ts +++ b/apps/zui/src/initializers/index.ts @@ -1,8 +1,6 @@ export * as autoUpdate from "./auto-update" -export * as commands from "./commands" export * as customProtocol from "./custom-protocol" export * as logFilters from "./log-filters" -export * as menus from "./menus" export * as secureWebContents from "./secure-web-contents" export * as shortcuts from "./shortcuts" export * as userTasks from "./user-tasks" diff --git a/apps/zui/src/initializers/menus.ts b/apps/zui/src/initializers/menus.ts deleted file mode 100644 index 9a7b5a29b3..0000000000 --- a/apps/zui/src/initializers/menus.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Import all menus here to register them - -import "src/domain/menus" - -export function initialize() { - // No op -} diff --git a/apps/zui/src/js/api/layout-api.ts b/apps/zui/src/js/api/layout-api.ts deleted file mode 100644 index e379e7f7ca..0000000000 --- a/apps/zui/src/js/api/layout-api.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {flashElement} from "src/app/commands/flash-element" -import Layout from "../state/Layout" -import {PaneName} from "../state/Layout/types" -import {ApiDomain} from "./api-domain" -import Appearance from "../state/Appearance" - -export class LayoutApi extends ApiDomain { - activatePane(name: PaneName) { - const {state, dispatch} = this - if ( - Appearance.secondarySidebarIsOpen(state) && - Layout.getCurrentPaneName(state) === name - ) { - flashElement.run(`[data-section-tab-value='${name}']`) - } else { - dispatch(Appearance.showSecondarySidebar()) - dispatch(Layout.setCurrentPaneName(name)) - } - } -} diff --git a/apps/zui/src/js/api/zui-api.ts b/apps/zui/src/js/api/zui-api.ts index 1392962410..e9098f7d47 100644 --- a/apps/zui/src/js/api/zui-api.ts +++ b/apps/zui/src/js/api/zui-api.ts @@ -12,11 +12,10 @@ import {CurrentApi} from "./current/current-api" import {EditorApi} from "./editor/editor-api" import {NoticeApi} from "./notice/notice-api" import {UrlApi} from "./url/url-api" -import {LayoutApi} from "./layout-api" import {TableViewApi} from "src/zui-kit" import {LakeModel} from "../models/lake" -// This should start to be deprecated maybe... +// This is deprecated in favor of domain handlers and operations export default class ZuiApi { table: TableViewApi | null = null public abortables = new Abortables() @@ -36,7 +35,6 @@ export default class ZuiApi { public dispatch: AppDispatch public getState: GetState public notice: NoticeApi - public layout: LayoutApi init(d: AppDispatch, gs: GetState) { this.dispatch = d @@ -49,7 +47,6 @@ export default class ZuiApi { this.editor = new EditorApi(d, gs) this.notice = new NoticeApi(this) this.url = new UrlApi(this) - this.layout = new LayoutApi(this) } getZealot(lake?: LakeModel) { @@ -57,13 +54,14 @@ export default class ZuiApi { } createAbortable(tab?: string, tag?: string) { - this.abortables.abort({tab, tag}) + try { + this.abortables.abort({tab, tag}) + } catch (e) { + console.log("Abort Handled", e) + } const ctl = new AbortController() const id = this.abortables.add({ - abort: () => { - console.log("aborted", tab, tag) - ctl.abort() - }, + abort: () => ctl.abort(), tab, tag, }) diff --git a/apps/zui/src/js/components/AboutWindow.tsx b/apps/zui/src/js/components/AboutWindow.tsx index 343e54c18b..585e4da03d 100644 --- a/apps/zui/src/js/components/AboutWindow.tsx +++ b/apps/zui/src/js/components/AboutWindow.tsx @@ -1,6 +1,6 @@ import React, {useEffect, useState} from "react" import TextContent from "./TextContent" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import {EnvAboutApp} from "src/domain/env/types" import {invoke} from "src/core/invoke" @@ -19,7 +19,7 @@ export function Content(props: EnvAboutApp) { return (
- +
diff --git a/apps/zui/src/js/components/CircleChevron.tsx b/apps/zui/src/js/components/CircleChevron.tsx deleted file mode 100644 index 59cefdeb70..0000000000 --- a/apps/zui/src/js/components/CircleChevron.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from "react" -import Arrow from "./icons/chevron-left-md" -import pick from "lodash/pick" -import classNames from "classnames" - -type Props = { - light?: boolean - dark?: boolean - expand?: boolean - collapse?: boolean - right?: boolean - left?: boolean -} - -export default class PaneToggle extends React.Component { - render() { - const classes = pick( - this.props, - "light", - "dark", - "collapse", - "expand", - "right", - "left" - ) - - return ( - - ) - } -} diff --git a/apps/zui/src/js/components/CloseButton.tsx b/apps/zui/src/js/components/CloseButton.tsx index d93191a4ec..eb1cb6b4fc 100644 --- a/apps/zui/src/js/components/CloseButton.tsx +++ b/apps/zui/src/js/components/CloseButton.tsx @@ -1,7 +1,7 @@ import React from "react" import classNames from "classnames" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" type Props = { light?: boolean @@ -10,7 +10,7 @@ type Props = { const CloseButton = ({light, ...rest}: Props) => ( ) diff --git a/apps/zui/src/js/components/Content.tsx b/apps/zui/src/js/components/Content.tsx index 0e567e0107..833e9c1d00 100644 --- a/apps/zui/src/js/components/Content.tsx +++ b/apps/zui/src/js/components/Content.tsx @@ -4,7 +4,7 @@ export const Content = styled.section` line-height: 1.6; a { - color: var(--havelock); + color: var(--primary-color); text-decoration: underline; cursor: pointer; } diff --git a/apps/zui/src/js/components/FilterNode.tsx b/apps/zui/src/js/components/FilterNode.tsx deleted file mode 100644 index be099d1e43..0000000000 --- a/apps/zui/src/js/components/FilterNode.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, {MouseEvent} from "react" -import styled from "styled-components" -import {CircleCloseButton} from "./CircleCloseButton" - -type Props = { - filter: string - focused?: boolean - pending?: boolean - onClick?: (e: MouseEvent) => void - onRemoveClick?: (e: MouseEvent) => void - onFocus?: (e: any) => void -} - -const ButtonWrap = styled.div` - position: absolute; - top: 0; - right: 0; - transform: translate(50%, -50%); - .circle { - color: var(--wet-cement); - } -` - -export default class FilterNode extends React.PureComponent { - render() { - const classNames = ["filter-node"] - if (this.props.focused) classNames.push("focused") - - return ( -
-

this.props.onFocus && this.props.onFocus(e)} - > - {this.props.filter} -

- {this.props.onRemoveClick && ( - - - - )} -
- ) - } -} diff --git a/apps/zui/src/js/components/HTMLContextMenu.tsx b/apps/zui/src/js/components/HTMLContextMenu.tsx index 65d7c91f63..424176d69d 100644 --- a/apps/zui/src/js/components/HTMLContextMenu.tsx +++ b/apps/zui/src/js/components/HTMLContextMenu.tsx @@ -14,6 +14,7 @@ import ReactDOM from "react-dom" import classNames from "classnames" import useListener from "./hooks/useListener" import doc from "../lib/doc" +import {handleClick} from "src/core/menu/handle-click" export default function HTMLContextMenu() { const [template, setTemplate] = useState(null) @@ -40,7 +41,7 @@ function HTMLMenuItem({item}) { } else { return (
  • item.click(item)} + onClick={() => handleClick(item)} className={classNames({disabled: item.enabled === false})} aria-label={item.label} > diff --git a/apps/zui/src/js/components/InfoNotice.tsx b/apps/zui/src/js/components/InfoNotice.tsx deleted file mode 100644 index 91a87b898f..0000000000 --- a/apps/zui/src/js/components/InfoNotice.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react" -import ReactDOM from "react-dom" - -import lib from "../lib" - -type Props = {children: any} - -export default function InfoNotice({children}: Props) { - return ReactDOM.createPortal( -
    -
    {children}
    -
    , - lib.doc.id("tooltip-root") - ) -} diff --git a/apps/zui/src/js/components/LakeModals/StatusLight.tsx b/apps/zui/src/js/components/LakeModals/StatusLight.tsx deleted file mode 100644 index 3740e76c64..0000000000 --- a/apps/zui/src/js/components/LakeModals/StatusLight.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from "react" -import styled from "styled-components" -import {LakeStatus} from "../../state/LakeStatuses/types" - -const StatusLight = ({...props}: any) => { - return ( - - - - - - - - - ) -} - -export default styled(StatusLight)<{status: LakeStatus}>` - fill: ${(p) => { - switch (p.status) { - case "connected": - return "var(--green)" - case "disconnected": - return "var(--red)" - default: - return "var(--lead)" - } - }}; -` diff --git a/apps/zui/src/js/components/LogDetails/ColumnDescription.tsx b/apps/zui/src/js/components/LogDetails/ColumnDescription.tsx deleted file mode 100644 index 194d6e8fde..0000000000 --- a/apps/zui/src/js/components/LogDetails/ColumnDescription.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import zeekLogInfo from "src/ppl/zeek/logInfo" -import React from "react" -import ReactMarkdown from "react-markdown" -import {Column} from "../../types" -import {invoke} from "src/core/invoke" - -type Props = { - column: Column - path: string -} - -export default function ColumnDescription({column, path}: Props) { - const info = zeekLogInfo(path) - const col = info.describeColumn(column) - - return ( -
    -
    -

    {column.name}

    {col.type}

    -
    -
    - {col.desc} -
    - {info.isKnown() && ( - - )} -
    - ) -} diff --git a/apps/zui/src/js/components/Login.tsx b/apps/zui/src/js/components/Login.tsx index d5dbcd81c6..80d23b0759 100644 --- a/apps/zui/src/js/components/Login.tsx +++ b/apps/zui/src/js/components/Login.tsx @@ -8,7 +8,6 @@ import MacSpinner from "./MacSpinner" import {isString} from "lodash" import {updateStatus} from "../flows/lake/update-status" import {login} from "../flows/lake/login" -import ToolbarButton from "src/app/query-home/toolbar/actions/button" import {LakeModel} from "../models/lake" const PageWrap = styled.div` @@ -21,17 +20,15 @@ const PageWrap = styled.div` const StyledHeader = styled.h1` margin: 110px 0 0 0; - color: var(--aqua); ${(p) => p.theme.typography.headingPage} ` const StyledP = styled.p` margin: 18px 0 0 0; - color: var(--aqua); ${(p) => p.theme.typography.labelNormal} ` -const StyledButton = styled(ToolbarButton)` +const StyledButton = styled.button` margin: 36px 0 0 0; ` @@ -76,11 +73,9 @@ const Login = ({lake}: Props) => { This lake requires authentication. Please log in to continue. {error && Error: {error}} - : null} - /> + + {isFetching ? : null} {isFetching ? "Cancel" : "Login"} + ) } diff --git a/apps/zui/src/js/components/MenuBarButton.tsx b/apps/zui/src/js/components/MenuBarButton.tsx deleted file mode 100644 index e9c706ceff..0000000000 --- a/apps/zui/src/js/components/MenuBarButton.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import * as React from "react" -import classNames from "classnames" - -import ClockIcon from "../icons/ClockIcon" -import DropdownArrow from "../icons/DropdownArrow" -import {ReactNode} from "react" - -type Props = { - children: ReactNode - dropdown?: boolean - className?: string - icon?: React.ReactNode -} & React.HTMLProps - -const MenuBarButton = React.forwardRef( - function MenuBarButton( - {className, children, dropdown, icon, ...props}: Props, - ref - ) { - return ( - - ) - } -) - -export default MenuBarButton diff --git a/apps/zui/src/js/components/ModalBox/Buttons.tsx b/apps/zui/src/js/components/ModalBox/Buttons.tsx deleted file mode 100644 index c934a76dc9..0000000000 --- a/apps/zui/src/js/components/ModalBox/Buttons.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, {MouseEvent} from "react" - -import {ModalButton} from "./types" -import ButtonRow from "../ButtonRow" -import ToolbarButton from "src/app/query-home/toolbar/actions/button" - -type Props = { - template: ModalButton[] - closeModal: Function -} - -export default function Buttons({template, closeModal}: Props) { - return ( - - {template.map((b, i, a) => ( - b.click(closeModal, e)} - /> - ))} - - ) -} - -type ButtonItemProps = { - text: string - onClick: (e: MouseEvent) => void - isLast: boolean - disabled?: boolean - icon?: React.ReactNode - showSpinner?: boolean -} - -function ButtonItem({ - text, - onClick, - isLast, - disabled = false, - icon = null, -}: ButtonItemProps) { - if (isLast) { - return ( - - ) - } - - return ( - - ) -} diff --git a/apps/zui/src/js/components/ModalBox/ModalBox.tsx b/apps/zui/src/js/components/ModalBox/ModalBox.tsx deleted file mode 100644 index 305857f1d0..0000000000 --- a/apps/zui/src/js/components/ModalBox/ModalBox.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import {useSelector} from "react-redux" -import React from "react" - -import {ModalBoxProps} from "./types" -import Animate from "../Animate" -import ModalContents from "./ModalContents" -import modal from "../../state/Modal" - -export default function ModalBox({name, children, ...props}: ModalBoxProps) { - const active = useSelector(modal.getName) - - function enter(anime, el) { - return anime - .timeline({ - duration: 150, - }) - .add({ - targets: document.querySelector(".modal-overlay"), - backgroundColor: ["rgba(38,37,36,0.0)", "rgba(38,37,36,0.15)"], - easing: "linear", - }) - .add( - { - targets: el.querySelector(".modal-contents"), - opacity: { - value: [0, 1], - easing: "easeInOutSine", - }, - scale: [0.8, 1], - easing: "easeInOutSine", - }, - 0 - ) - } - - return ( - - {children} - - ) -} diff --git a/apps/zui/src/js/components/ModalBox/ModalContents.tsx b/apps/zui/src/js/components/ModalBox/ModalContents.tsx deleted file mode 100644 index 9a81f89336..0000000000 --- a/apps/zui/src/js/components/ModalBox/ModalContents.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from "react" -import ReactDOM from "react-dom" -import classNames from "classnames" - -import {ModalContentsProps} from "./types" -import Buttons from "./Buttons" -import CloseButton from "../CloseButton" -import lib from "../../lib" -import useModalController from "./useModalController" - -const ModalContents = React.forwardRef( - function ModalContents( - { - children, - className, - title, - onClose, - buttons: template, - ...rest - }: ModalContentsProps, - ref - ) { - const {closeModal, buttons} = useModalController(template, onClose) - - return ReactDOM.createPortal( -
    -
    - - -
    {children}
    - -
    -
    , - lib.doc.id("modal-root") - ) - } -) - -export default ModalContents diff --git a/apps/zui/src/js/components/ModalBox/types.ts b/apps/zui/src/js/components/ModalBox/types.ts deleted file mode 100644 index ebbd6e9fdb..0000000000 --- a/apps/zui/src/js/components/ModalBox/types.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {ModalName} from "../../state/Modal/types" -import {RefAttributes} from "react" -import * as React from "react" - -export type ModalButton = { - label: string - click: Function - icon?: React.ReactNode - disabled?: boolean -} -export type ModalButtonTemplate = void | string | ModalButton[] -export type ModalBoxProps = { - children: any - title: string - name: ModalName - className?: string - buttons: ModalButtonTemplate - onClose?: Function -} - -export type ModalContentsProps = { - children: any - title: string - className?: string - buttons: ModalButtonTemplate - onClose?: Function -} & RefAttributes diff --git a/apps/zui/src/js/components/ModalBox/useModalController.ts b/apps/zui/src/js/components/ModalBox/useModalController.ts deleted file mode 100644 index f5648d94b7..0000000000 --- a/apps/zui/src/js/components/ModalBox/useModalController.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {useDispatch} from "react-redux" - -import {ModalButtonTemplate} from "./types" -import {isArray, isString} from "../../lib/is" -import {last} from "../../lib/Array" -import Modal from "../../state/Modal" -import useEventListener from "../hooks/useEventListener" - -export default function useModalController( - template: ModalButtonTemplate, - onClose?: Function -) { - const dispatch = useDispatch() - let buttons = [] - - if (isString(template)) { - buttons = [{label: template, click: closeModal}] - } - - if (isArray(template)) { - buttons = template - } - - function closeModal() { - dispatch(Modal.hide()) - onClose && onClose() - } - - function keyDown(e) { - if (e.key === "Escape") { - e.stopPropagation() - e.preventDefault() - closeModal() - } - if (e.key === "Enter") { - e.stopPropagation() - e.preventDefault() - const b = last(buttons) - if (b) { - b.click(closeModal, e) - } else { - closeModal() - } - } - } - - useEventListener(document, "keydown", keyDown, [template]) - - return { - closeModal, - buttons, - } -} diff --git a/apps/zui/src/js/components/Notice.tsx b/apps/zui/src/js/components/Notice.tsx deleted file mode 100644 index ddb54fbc17..0000000000 --- a/apps/zui/src/js/components/Notice.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import {cssVar, transparentize} from "polished" -import React, {useState, useEffect} from "react" -import ReactDOM from "react-dom" -import {CSSTransition} from "react-transition-group" -import styled from "styled-components" -import doc from "../lib/doc" -import {CircleCloseButton} from "./CircleCloseButton" - -const Wrap = styled.div` - position: fixed; - bottom: 0; - right: 0; - left: 0; - display: flex; - justify-content: center; - height: 112px; -` - -const bg = cssVar("--wet-cement") as string -const shadow = transparentize(0.65, bg) - -const Content = styled.div<{timeout: {appear: number; exit: number}}>` - pointer-events: all; - white-space: nowrap; - user-select: none; - background: var(--wet-cement); - border-radius: 8px; - height: 32px; - display: flex; - align-items: center; - box-shadow: 0 2px 10px 3px ${shadow}; - - button { - display: block; - margin-right: 8px; - } - - --ease-in-expo: cubic-bezier(0.95, 0.05, 0.795, 0.035); - --ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1); - - &.notice-appear { - transform: translateY(100px); - } - - &.notice-appear-active { - transition: transform ${(p) => p.timeout.appear}ms var(--ease-out-expo); - transform: translateY(0px); - } - - &.notice-exit { - opacity: 1; - transform: scale(1); - } - - &.notice-exit-active { - opacity: 0; - transform: scale(0); - transition: all ${(p) => p.timeout.exit}ms var(--ease-in-expo); - } - - &.notice-exit-done { - opacity: 0; - } -` - -const Message = styled.p` - ${(p) => p.theme.typography.labelNormal} - margin: 0; - color: white; - padding: 0 16px; -` - -type Props = { - text: string - onDone?: () => void -} - -export function Notice({text, onDone, ...rest}: Props) { - const [visible, setVisible] = useState(true) - const appear = 500 - const exit = 350 - const duration = 3000 - - useEffect(() => { - const id = setTimeout(() => setVisible(false), duration + appear) - return () => { - clearTimeout(id) - } - }, []) - - return ReactDOM.createPortal( - - - - {text} - setVisible(false)} /> - - - , - doc.id("tooltip-root") - ) -} diff --git a/apps/zui/src/js/components/StartupError.tsx b/apps/zui/src/js/components/StartupError.tsx deleted file mode 100644 index 6ff70d4156..0000000000 --- a/apps/zui/src/js/components/StartupError.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from "react" -import styled from "styled-components" -import Link from "./common/Link" - -const Wrap = styled.div` - padding: 24px; - padding-top: 54px; - min-height: 100vh; - background: linear-gradient(to bottom right, #f8eee3, #fae1e0); -` - -const WindowDragArea = styled.div` - -webkit-app-region: drag; - position: fixed; - top: 0; - left: 0; - right: 0; - height: 30px; - background-color: rgba(0, 0, 0, 0.05); -` - -const Content = styled.div` - max-width: 600px; - margin: 0 auto; -` - -const Pre = styled.pre` - font-size: 10px; - overflow: auto; - background-color: rgba(0, 0, 0, 0.05); - padding: 12px 18px; - margin-bottom: 24px; - border-radius: 8px; -` - -const Title = styled.h1` - font-size: 13px; - font-weight: 600; - color: var(--red); - margin-bottom: 12px; - user-select: none; -` - -const Actions = styled.div` - display: flex; - align-items: center; - justify-content: flex-end; - - a { - font-size: 11px; - color: var(--havelock); - margin-right: 24px; - } -` - -const StyledLink = styled(Link)` - outline: 1px solid orange; -` - -type Props = { - error: object -} - -function format(e) { - if (e instanceof Error) { - return e.stack - } else { - return JSON.stringify(e, null, 2) - } -} - -export default function StartupError({error}: Props) { - const e = format(error) - - return ( - - - - Zui Failed to Start -
    {e}
    - - - Contact Support - - -
    -
    - ) -} diff --git a/apps/zui/src/js/components/TabBar/SearchTab.tsx b/apps/zui/src/js/components/TabBar/SearchTab.tsx index 1407f377b7..ec3ad070f4 100644 --- a/apps/zui/src/js/components/TabBar/SearchTab.tsx +++ b/apps/zui/src/js/components/TabBar/SearchTab.tsx @@ -1,6 +1,6 @@ import React, {HTMLProps} from "react" import classNames from "classnames" -import Icon, {IconName} from "src/app/core/icon-temp" +import {Icon, IconName} from "src/components/icon" import styled from "styled-components" type Props = { @@ -15,15 +15,21 @@ type Props = { const CloseButton = styled.button` background: none; border: none; - padding: 0; - margin-right: 8px; + padding: 4px; border-radius: 6px; + margin-right: 6px; + &:hover { background: rgba(0, 0, 0, 0.08); } &:active { background: rgba(0, 0, 0, 0.12); } + + svg { + width: 0.95rem; + height: 0.95rem; + } ` const SearchTab = React.forwardRef(function SearchTab( @@ -37,7 +43,7 @@ const SearchTab = React.forwardRef(function SearchTab( className={classNames("tab", {active, "is-new": isNew, preview})} >
    - +

    {title}

    removeTab(e)} className="no-drag"> diff --git a/apps/zui/src/js/components/TabBar/TabBar.tsx b/apps/zui/src/js/components/TabBar/TabBar.tsx index 1df3153c02..51a5e16d6b 100644 --- a/apps/zui/src/js/components/TabBar/TabBar.tsx +++ b/apps/zui/src/js/components/TabBar/TabBar.tsx @@ -1,4 +1,4 @@ -import {useQueryIdNameMap} from "src/app/query-home/hooks/use-query-id-name-map" +import {useQueryIdNameMap} from "./use-query-id-name-map" import React, {useEffect, useState} from "react" import {useSelector} from "react-redux" import {animated} from "react-spring" @@ -26,12 +26,11 @@ const AnimatedSearchTab = animated(SearchTab) const MAX_WIDTH = 200 const BG = styled.div` - background: var(--tab-background); display: flex; align-items: center; - padding-right: 16px; height: 100%; grid-area: tabs; + gap: 10px; -webkit-app-region: drag; ` @@ -54,7 +53,6 @@ const TrafficLightBG = styled.div` align-items: center; width: 128px; flex-shrink: 0; - background: var(--tab-background); z-index: 1; padding-right: 10px; ` @@ -74,13 +72,17 @@ export default function TabBar() { const ctl = useTabController(count, calcWidth) useEffect(() => calcWidth(), [rect.width]) const sidebarCollapsed = !useSelector(Appearance.sidebarIsOpen) + const rightbarCollapse = !useSelector(Appearance.secondarySidebarIsOpen) + const paddingInlineEnd = rightbarCollapse ? 20 : 10 + const paddingInlineStart = sidebarCollapsed ? 20 : 0 return ( - + {sidebarCollapsed && global.env.isMac && ( )} + {sidebarCollapsed && !global.env.isMac && } {ids.map((id: string) => { const tabModel = tab(id, lakes, pools, queryIdNameMap, lakeId) diff --git a/apps/zui/src/app/query-home/hooks/use-query-id-name-map.ts b/apps/zui/src/js/components/TabBar/use-query-id-name-map.ts similarity index 100% rename from apps/zui/src/app/query-home/hooks/use-query-id-name-map.ts rename to apps/zui/src/js/components/TabBar/use-query-id-name-map.ts diff --git a/apps/zui/src/js/components/TabBar/useTabController.ts b/apps/zui/src/js/components/TabBar/useTabController.ts index a3437ae7d6..74b53b34ad 100644 --- a/apps/zui/src/js/components/TabBar/useTabController.ts +++ b/apps/zui/src/js/components/TabBar/useTabController.ts @@ -2,7 +2,6 @@ import {useSelector} from "react-redux" import {startTransition, useEffect, useRef, useState} from "react" import Tabs from "../../state/Tabs" -import {newTab} from "src/app/query-home/flows/new-tab" import {useDispatch} from "src/app/core/state" export default function (count: number, calcWidths: Function) { @@ -24,7 +23,7 @@ export default function (count: number, calcWidths: Function) { previewId: useSelector(Tabs.getPreview), onAddClick() { - dispatch(newTab()) + dispatch(Tabs.createQuerySession()) }, onRemoveClick(event: MouseEvent, id: string) { diff --git a/apps/zui/src/js/components/Tooltip.tsx b/apps/zui/src/js/components/Tooltip.tsx deleted file mode 100644 index 3857a1624c..0000000000 --- a/apps/zui/src/js/components/Tooltip.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react" -import ReactTooltip from "react-tooltip" -import classNames from "classnames" - -type Props = { - children?: any - className?: string - id?: string -} - -export default function Tooltip({className, children, id, ...rest}: Props) { - return ( - - {children} - - ) -} diff --git a/apps/zui/src/js/components/common/EmptySection.tsx b/apps/zui/src/js/components/common/EmptySection.tsx index fbcc66efae..a3ac714898 100644 --- a/apps/zui/src/js/components/common/EmptySection.tsx +++ b/apps/zui/src/js/components/common/EmptySection.tsx @@ -10,13 +10,13 @@ const EmptyWrapper = styled.div` user-select: none; svg { - fill: var(--foreground-color); + fill: var(--fg-color); opacity: 0.1; } p { ${(props) => props.theme.typography.labelSmall}; - color: var(--slate); + color: var(--fg-color-less); text-align: center; margin: 16px 14px 0; } diff --git a/apps/zui/src/js/components/status-bar/query-progress.tsx b/apps/zui/src/js/components/status-bar/query-progress.tsx index 6fe73b349b..515e9166f9 100644 --- a/apps/zui/src/js/components/status-bar/query-progress.tsx +++ b/apps/zui/src/js/components/status-bar/query-progress.tsx @@ -17,7 +17,7 @@ const Loader = styled.div` border-top: 0.2em solid rgba(0, 0, 0, 0.1); border-right: 0.2em solid rgba(0, 0, 0, 0.1); border-bottom: 0.2em solid rgba(0, 0, 0, 0.1); - border-left: 0.2em solid var(--foreground-color); + border-left: 0.2em solid var(--fg-color); transform: translateZ(0); animation: load8 1.1s infinite linear; } diff --git a/apps/zui/src/js/flows/searchBar/actions.ts b/apps/zui/src/js/flows/searchBar/actions.ts index 36fd3054bc..3528d40bed 100644 --- a/apps/zui/src/js/flows/searchBar/actions.ts +++ b/apps/zui/src/js/flows/searchBar/actions.ts @@ -53,7 +53,7 @@ export function appendQueryIn(field: zed.Field, value: zed.Value): Thunk { } } -export function appendQueryNotIn(field: zed.Field, value: zed.Any): Thunk { +export function appendQueryNotIn(field: zed.Field, value: zed.Value): Thunk { return function (dispatch, getState) { dispatch( changeTo( diff --git a/apps/zui/src/js/icons/ThreeDotsIcon.tsx b/apps/zui/src/js/icons/ThreeDotsIcon.tsx deleted file mode 100644 index e6c44b3bcf..0000000000 --- a/apps/zui/src/js/icons/ThreeDotsIcon.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from "react" - -import ThreeDotsSvg from "src/app/core/icons/three-dots" - -export default function ThreeDotsIcon(props: any) { - return -} diff --git a/apps/zui/src/js/initializers/init-resize-listener.ts b/apps/zui/src/js/initializers/init-resize-listener.ts new file mode 100644 index 0000000000..06a98fec51 --- /dev/null +++ b/apps/zui/src/js/initializers/init-resize-listener.ts @@ -0,0 +1,21 @@ +export function initResizeListener() { + let id + function reset() { + clearTimeout(id) + } + function addClass() { + document.body.classList.add("is-dragging") + } + function removeClass() { + document.body.classList.remove("is-dragging") + } + function schedule(fn, ms) { + id = setTimeout(fn, ms) + } + + window.onresize = () => { + reset() + addClass() + schedule(removeClass, 150) + } +} diff --git a/apps/zui/src/js/initializers/initDOM.ts b/apps/zui/src/js/initializers/initDOM.ts index 716ddf5156..81b05419d0 100644 --- a/apps/zui/src/js/initializers/initDOM.ts +++ b/apps/zui/src/js/initializers/initDOM.ts @@ -4,6 +4,9 @@ export default function initDOM() { appendDivId("tooltip-root") appendDivId("context-menu-root") appendDivId("measure-layer", {hidden: true}) + if (globalThis.env.isMac) { + document.body.classList.add("is-mac") + } } type Args = { diff --git a/apps/zui/src/js/initializers/initIpcListeners.ts b/apps/zui/src/js/initializers/initIpcListeners.ts index 6c336d6f5b..bc919ff519 100644 --- a/apps/zui/src/js/initializers/initIpcListeners.ts +++ b/apps/zui/src/js/initializers/initIpcListeners.ts @@ -5,17 +5,17 @@ import Tabs from "../state/Tabs" import {Store} from "../state/types" import initNewSearchTab from "./initNewSearchTab" import Editor from "../state/Editor" -import submitSearch from "src/app/query-home/flows/submit-search" import {commands} from "src/app/commands/command" import * as zed from "@brimdata/zed-js" import {viewLogDetail} from "../flows/viewLogDetail" import tabHistory from "src/app/router/tab-history" +import {submitSearch} from "src/domain/session/handlers" export default (store: Store) => { global.zui.on("clearPins", () => { store.dispatch(Editor.deleteAllPins()) store.dispatch(Editor.setValue("")) - store.dispatch(submitSearch()) + submitSearch() }) global.zui.on("toggleLeftSidebar", () => { diff --git a/apps/zui/src/js/initializers/initNewSearchTab.ts b/apps/zui/src/js/initializers/initNewSearchTab.ts index 5afadac85a..d8dbd5aecf 100644 --- a/apps/zui/src/js/initializers/initNewSearchTab.ts +++ b/apps/zui/src/js/initializers/initNewSearchTab.ts @@ -1,7 +1,7 @@ import tabHistory from "src/app/router/tab-history" import Tabs from "../state/Tabs" import {Store} from "../state/types" -import submitSearch from "../../app/query-home/flows/submit-search" +import {submitSearch} from "src/domain/session/handlers" export default function (store: Store, params: any) { const {href, isNewWin} = params @@ -10,5 +10,5 @@ export default function (store: Store, params: any) { } else { store.dispatch(tabHistory.replace(href)) } - store.dispatch(submitSearch()) + submitSearch() } diff --git a/apps/zui/src/js/initializers/initialize.ts b/apps/zui/src/js/initializers/initialize.ts index 39988cf246..0304ffd058 100644 --- a/apps/zui/src/js/initializers/initialize.ts +++ b/apps/zui/src/js/initializers/initialize.ts @@ -6,7 +6,6 @@ import initIpcListeners from "./initIpcListeners" import initStore from "./initStore" import {initAutosave} from "./initAutosave" import {commands} from "src/app/commands/command" -import {menus} from "src/core/menu" import {initHandlers} from "./init-handlers" import {invoke} from "src/core/invoke" import {WindowName} from "src/electron/windows/types" @@ -15,6 +14,9 @@ import {initializeTabs} from "./init-tabs" import {initializeMonaco} from "./init-monaco" import {initializePluginContextSync} from "./init-plugin-context-sync" import toast from "react-hot-toast" +import {startTransition} from "react" +import {initResizeListener} from "./init-resize-listener" +import {setMenuContext} from "src/core/menu" const getWindowId = () => { const params = new URLSearchParams(window.location.search) @@ -42,18 +44,21 @@ export default async function initialize( initDOM() initIpcListeners(store) initHandlers({ + transition: startTransition, + oldApi: api, dispatch: store.dispatch, select: (fn) => fn(store.getState()), invoke: invoke, toast: toast, }) + setMenuContext({select: (fn) => fn(store.getState()), api}) initDebugGlobals(store, api) initAutosave(store) commands.setContext(store, api) - menus.setContext({api}) invoke("windowInitialized", global.windowId) initializeTabs(store) initializeMonaco() initializePluginContextSync(store) + initResizeListener() return {store, api} } diff --git a/apps/zui/src/js/lib/System.ts b/apps/zui/src/js/lib/System.ts index 387076ad85..14ef94b689 100644 --- a/apps/zui/src/js/lib/System.ts +++ b/apps/zui/src/js/lib/System.ts @@ -1,14 +1,4 @@ -import {MenuItemConstructorOptions, PopupOptions} from "electron" import {invoke} from "src/core/invoke" -import {showContextMenu as show} from "src/core/menu/show-context-menu" - -// Remove this function -export async function showContextMenu( - template: MenuItemConstructorOptions[], - opts: PopupOptions = {} -) { - show(template, opts) -} export function showMessageBox(opts: Electron.MessageBoxOptions) { if (global.env.isIntegrationTest) { diff --git a/apps/zui/src/js/state/Current/selectors.ts b/apps/zui/src/js/state/Current/selectors.ts index 7155a35759..19ffa0fcd5 100644 --- a/apps/zui/src/js/state/Current/selectors.ts +++ b/apps/zui/src/js/state/Current/selectors.ts @@ -1,6 +1,5 @@ import {matchPath} from "react-router" import * as Pools from "../Pools/selectors" -import Tabs from "../Tabs" import {State} from "../types" import Lakes from "../Lakes" import {MemoryHistory} from "history" @@ -24,7 +23,7 @@ export const getHistory = ( state, windowName = global.windowName ): MemoryHistory => { - const id = Tabs.getActive(state) + const id = getActive(state) if (windowName === "search") return global.tabHistories.getOrCreate(id) if (windowName === "detail" || windowName === "hidden") return global.windowHistory diff --git a/apps/zui/src/js/state/Layout/reducer.ts b/apps/zui/src/js/state/Layout/reducer.ts index e665169ce1..2c43d94e52 100644 --- a/apps/zui/src/js/state/Layout/reducer.ts +++ b/apps/zui/src/js/state/Layout/reducer.ts @@ -30,16 +30,11 @@ const slice = createSlice({ setCurrentPaneName(s, action: PayloadAction) { s.currentPaneName = action.payload }, - showTitleForm: { - prepare: (action: "create" | "update") => ({payload: {action}}), - reducer: (s, a: PayloadAction<{action: "create" | "update"}>) => { - s.isEditingTitle = true - s.titleFormAction = a.payload.action - }, + showTitleForm(s) { + s.isEditingTitle = true }, hideTitleForm(s) { s.isEditingTitle = false - s.titleFormAction = "create" }, toggleHistogram(s) { s.showHistogram = !s.showHistogram diff --git a/apps/zui/src/js/state/Layout/types.ts b/apps/zui/src/js/state/Layout/types.ts index a64c08718a..a7a7092143 100644 --- a/apps/zui/src/js/state/Layout/types.ts +++ b/apps/zui/src/js/state/Layout/types.ts @@ -1,3 +1,3 @@ -export type ResultsView = "INSPECTOR" | "TABLE" +export type ResultsView = "INSPECTOR" | "TABLE" | "CHART" export type ColumnHeadersViewState = "AUTO" | "ON" | "OFF" export type PaneName = "detail" | "versions" | "history" | "columns" diff --git a/apps/zui/src/js/state/Pools/selectors.ts b/apps/zui/src/js/state/Pools/selectors.ts index 6c42ff9560..ade958836c 100644 --- a/apps/zui/src/js/state/Pools/selectors.ts +++ b/apps/zui/src/js/state/Pools/selectors.ts @@ -38,7 +38,9 @@ export const getPools = (lakeId: string | null) => (state: State): Pool[] => { const l = getLake(state, lakeId) - return Object.keys(l).map((key) => Pool.from(l[key])) + return Object.keys(l) + .map((key) => Pool.from(l[key])) + .sort((a, b) => (a.name > b.name ? 1 : -1)) } export const getPoolNames = diff --git a/apps/zui/src/js/state/QueryVersions/flows/save-query-version.ts b/apps/zui/src/js/state/QueryVersions/flows/save-query-version.ts deleted file mode 100644 index d58843bdd9..0000000000 --- a/apps/zui/src/js/state/QueryVersions/flows/save-query-version.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {Thunk} from "src/js/state/types" -import QueryVersions from "src/js/state/QueryVersions/index" -import {QueryVersion} from "src/js/state/QueryVersions/types" -import {getQuerySource} from "../../Queries/flows/get-query-source" -import RemoteQueries from "src/js/state/RemoteQueries" -import {appendRemoteQueries} from "src/js/state/RemoteQueries/flows/remote-queries" - -export const saveQueryVersion = - (queryId: string, version: QueryVersion): Thunk> => - async (dispatch, getState) => { - const source = dispatch(getQuerySource(queryId)) - if (source === "remote") { - const query = RemoteQueries.find(getState(), queryId) - await dispatch(appendRemoteQueries([{...query, ...version}])) - } - - dispatch(QueryVersions.at(queryId).create(version)) - - return version - } diff --git a/apps/zui/src/js/state/ResultsToolbar/selectors.ts b/apps/zui/src/js/state/ResultsToolbar/selectors.ts deleted file mode 100644 index a6e11c2595..0000000000 --- a/apps/zui/src/js/state/ResultsToolbar/selectors.ts +++ /dev/null @@ -1,3 +0,0 @@ -import activeTabSelect from "../Tab/activeTabSelect" - -export const get = activeTabSelect((tab) => tab.resultsToolbar) diff --git a/apps/zui/src/js/state/ResultsToolbar/slice.ts b/apps/zui/src/js/state/ResultsToolbar/slice.ts deleted file mode 100644 index 01cc6b52ab..0000000000 --- a/apps/zui/src/js/state/ResultsToolbar/slice.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {PayloadAction, Update, createSlice} from "@reduxjs/toolkit" -import {MenuItem} from "src/core/menu" - -export const slice = createSlice({ - name: "TAB_RESULTS_TOOLBAR", - initialState: [] as MenuItem[], - reducers: { - set(_, action: PayloadAction) { - return action.payload - }, - update(state, action: PayloadAction>) { - let index = state.findIndex((item) => { - return item.id === action.payload.id - }) - const item = state[index] - if (item) { - state[index] = {...item, ...action.payload.changes} - } - }, - }, -}) - -export const reducer = slice.reducer diff --git a/apps/zui/src/js/state/ResultsToolbar/index.ts b/apps/zui/src/js/state/Selection/index.ts similarity index 53% rename from apps/zui/src/js/state/ResultsToolbar/index.ts rename to apps/zui/src/js/state/Selection/index.ts index d9ef66f4f9..7864010c8a 100644 --- a/apps/zui/src/js/state/ResultsToolbar/index.ts +++ b/apps/zui/src/js/state/Selection/index.ts @@ -1,7 +1,8 @@ +import {reducer, actions} from "./reducer" import * as selectors from "./selectors" -import {slice} from "./slice" export default { - ...slice.actions, + reducer, + ...actions, ...selectors, } diff --git a/apps/zui/src/js/state/Selection/reducer.ts b/apps/zui/src/js/state/Selection/reducer.ts new file mode 100644 index 0000000000..0d1a39c54f --- /dev/null +++ b/apps/zui/src/js/state/Selection/reducer.ts @@ -0,0 +1,29 @@ +import {PayloadAction, createSlice} from "@reduxjs/toolkit" +import * as zed from "@brimdata/zed-js" + +const slice = createSlice({ + name: "TAB_SELECTION", + initialState: { + value: null as zed.Value | null, + field: null as zed.Field | null, + rootValue: null as zed.Value | null, + }, + reducers: { + set( + _, + action: PayloadAction<{ + value: zed.Value | null + field: zed.Field | null + rootValue: zed.Value | null + }> + ) { + return action.payload + }, + reset() { + return {value: null, field: null, rootValue: null} + }, + }, +}) + +export const reducer = slice.reducer +export const actions = slice.actions diff --git a/apps/zui/src/js/state/Selection/selectors.ts b/apps/zui/src/js/state/Selection/selectors.ts new file mode 100644 index 0000000000..e21bc1303c --- /dev/null +++ b/apps/zui/src/js/state/Selection/selectors.ts @@ -0,0 +1,6 @@ +import activeTabSelect from "../Tab/activeTabSelect" + +export const get = activeTabSelect((tab) => tab.selection) +export const getValue = activeTabSelect((tab) => tab.selection.value) +export const getField = activeTabSelect((tab) => tab.selection.field) +export const getRootValue = activeTabSelect((tab) => tab.selection.rootValue) diff --git a/apps/zui/src/js/state/Tab/reducer.ts b/apps/zui/src/js/state/Tab/reducer.ts index 4d264eceb5..ffb69a4dcd 100644 --- a/apps/zui/src/js/state/Tab/reducer.ts +++ b/apps/zui/src/js/state/Tab/reducer.ts @@ -6,8 +6,8 @@ import {reducer as table} from "../Table/reducer" import logDetails from "../LogDetails/reducer" import {reducer as results} from "../Results/reducer" import {reducer as histogram} from "../Histogram/reducer" +import {reducer as selection} from "../Selection/reducer" import {nanoid} from "@reduxjs/toolkit" -import {reducer as resultsToolbar} from "../ResultsToolbar/slice" const tabReducer = combineReducers({ editor, @@ -19,9 +19,9 @@ const tabReducer = combineReducers({ layout, logDetails, results, - resultsToolbar, histogram, table, + selection, }) export type TabReducer = typeof tabReducer diff --git a/apps/zui/src/js/state/Table/index.ts b/apps/zui/src/js/state/Table/index.ts index 7c68744147..a585f8983c 100644 --- a/apps/zui/src/js/state/Table/index.ts +++ b/apps/zui/src/js/state/Table/index.ts @@ -1,11 +1,6 @@ -import * as zed from "@brimdata/zed-js" -import activeTabSelect from "../Tab/activeTabSelect" -import {State} from "../types" import {actions} from "./reducer" - +import * as selectors from "./selectors" export default { - getStateForShape: (state: State, shape: zed.Type) => - activeTabSelect((tab) => tab.table.states.get(shape))(state), - getScrollPosition: activeTabSelect((tab) => tab.table.scrollPosition), + ...selectors, ...actions, } diff --git a/apps/zui/src/js/state/Table/reducer.ts b/apps/zui/src/js/state/Table/reducer.ts index 3ed3f62634..4dd717626e 100644 --- a/apps/zui/src/js/state/Table/reducer.ts +++ b/apps/zui/src/js/state/Table/reducer.ts @@ -1,36 +1,94 @@ -import {createSlice, PayloadAction as Payload} from "@reduxjs/toolkit" +import { + createSlice, + PayloadAction as Payload, + PayloadAction, +} from "@reduxjs/toolkit" import * as zed from "@brimdata/zed-js" -import {ZedTableState} from "src/components/zed-table/types" +import {TableSettingsState} from "./types" +import {ColumnSizingInfoState} from "@tanstack/react-table" +import {actions as results} from "../Results/reducer" +import {RESULTS_QUERY} from "src/views/results-pane/run-results-query" -const slice = createSlice({ +const table = createSlice({ name: "TAB_TABLE", initialState: { - states: new Map(), + settings: new Map(), scrollPosition: {top: 0, left: 0}, - lastShape: null as zed.Type | null, + shape: null as zed.Type | null, + columnExpandedDefault: false, + columnResizeInfo: {} as ColumnSizingInfoState, }, reducers: { - setStateForShape( - state, - action: Payload<{shape: zed.Type; state: ZedTableState}> - ) { - state.states.set(action.payload.shape, action.payload.state) - }, setScrollPosition(state, action: Payload<{top: number; left: number}>) { state.scrollPosition = action.payload }, - setLastShape(state, action: Payload) { - state.lastShape = action.payload + setShape(state, action: Payload) { + state.shape = action.payload + }, + }, + extraReducers: (builder) => { + builder.addCase(results.setShapes, (state, action) => { + if (action.payload.id == RESULTS_QUERY) { + const shapes = Object.values(action.payload.shapes) + state.shape = + shapes.length === 1 ? (zed.typeunder(shapes[0]) as zed.Type) : null + } + }) + builder.addMatcher( + (action) => action.type.startsWith(settings.name), + (state, action) => { + const shape = state.shape + const prev = state.settings.get(shape) + const next = settingsReducer(prev, action) + state.settings.set(shape, next) + } + ) + }, +}) + +const settings = createSlice({ + name: "TAB_TABLE_SETTINGS", + initialState: { + valueExpanded: {}, + valuePage: {}, + columnWidth: {}, + columnExpanded: {}, + columnVisible: {}, + columnSorted: {}, + }, + reducers: { + setValueExpanded(state, action: PayloadAction>) { + state.valueExpanded = action.payload + }, + setValuePage(state, action: PayloadAction>) { + state.valuePage = action.payload + }, + setColumnWidth(state, action: PayloadAction>) { + state.columnWidth = action.payload + }, + setColumnExpanded(state, action: PayloadAction>) { + state.columnExpanded = action.payload + }, + setColumnVisible(state, action: PayloadAction>) { + state.columnVisible = action.payload }, - setValueExpanded(state, action: Payload>) { - const prev = state.states.get(state.lastShape) - state.states.set(state.lastShape, { - ...prev, - valueExpanded: action.payload, - }) + setColumnSorted( + state, + action: PayloadAction> + ) { + state.columnSorted = action.payload + }, + expandColumn(state, action: PayloadAction) { + state.columnExpanded[action.payload] = true + }, + collapseColumn(state, action: PayloadAction) { + state.columnExpanded[action.payload] = false }, }, }) -export const reducer = slice.reducer -export const actions = slice.actions +const settingsReducer = settings.reducer + +export const reducer = table.reducer +export const actions = {...table.actions, ...settings.actions} +export const initialSettings = settings.getInitialState diff --git a/apps/zui/src/js/state/Table/selectors.ts b/apps/zui/src/js/state/Table/selectors.ts new file mode 100644 index 0000000000..2ccfdca032 --- /dev/null +++ b/apps/zui/src/js/state/Table/selectors.ts @@ -0,0 +1,145 @@ +import {getActiveQuery} from "../Current/selectors" +import activeTabSelect from "../Tab/activeTabSelect" +import {createSelector} from "@reduxjs/toolkit" +import {initialSettings} from "./reducer" +import * as zed from "@brimdata/zed-js" +import {TableSettingsState} from "./types" + +export const getShape = activeTabSelect((tab) => tab.table.shape) +export const getSettings = activeTabSelect((tab) => tab.table.settings) + +export const getShapeSettings = createSelector( + getShape, + getSettings, + (shape, settings) => settings.get(shape) ?? initialSettings() +) + +export const getScrollPosition = activeTabSelect( + (tab) => tab.table.scrollPosition +) + +export const getColumnExpandedDefault = activeTabSelect( + (tab) => tab.table.columnExpandedDefault +) + +export const getColumnSorts = createSelector( + getActiveQuery, + (query) => query.toAst().sorts +) + +export const getColumnVisible = createSelector( + getShapeSettings, + (settings) => settings.columnVisible +) + +export const getColumnExpanded = createSelector( + getShapeSettings, + (settings) => settings.columnExpanded +) + +export const getNestedColumns = createSelector( + getShape, + getShapeSettings, + (shape, settings) => { + return createColumns(shape as zed.TypeRecord, settings) + } +) + +export const getColumns = createSelector(getNestedColumns, (columns) => { + return flatten(columns) +}) + +export const getVisibleColumns = createSelector( + getShape, + getShapeSettings, + (shape, settings) => { + return flatten(createColumns(shape as zed.TypeRecord, settings)).filter( + (c) => c.isVisible + ) + } +) + +export const getColumnCount = createSelector(getColumns, (columns) => { + return columns.length +}) + +export const getVisibleColumnCount = createSelector( + getVisibleColumns, + (columns) => { + return columns.length + } +) + +export const getHiddenColumnCount = createSelector( + getColumnCount, + getVisibleColumnCount, + (all, visible) => { + return all - visible + } +) + +function flatten(columns: TableColumn[]) { + let array = [] + for (let col of columns) { + if (col.isExpanded) { + array = array.concat(flatten(col.children)) + } else { + array.push(col) + } + } + return array +} + +export type TableColumn = { + id: string + name: string + namePath: string[] + type: zed.Type + index: number + indexPath: number[] + parent: TableColumn | null + children: TableColumn[] | null + isExpanded: boolean + isVisible: boolean + width: number + sorted: "asc" | "desc" | null +} + +function createColumns( + typeRecord: zed.TypeRecord, + settings: TableSettingsState, + parent: TableColumn = null +) { + const fields = typeRecord?.fields ?? [] + return fields.map((field, index) => + createColumn(parent, field, index, settings) + ) +} + +function createColumn( + parent: TableColumn, + field: zed.TypeField, + index: number, + settings: TableSettingsState +) { + const indexPath = parent ? [...parent.indexPath, index] : [index] + const id = `col:${indexPath.join(",")}` + const column: TableColumn = { + id, + parent, + name: field.name, + type: field.type, + index: index, + indexPath, + namePath: parent ? [...parent.namePath, field.name] : [field.name], + isExpanded: settings.columnExpanded[id], + isVisible: settings.columnVisible[id] ?? true, + width: settings.columnWidth[id], + sorted: settings.columnSorted[id], + children: null, + } + if (field.type instanceof zed.TypeRecord) { + column.children = createColumns(field.type, settings, column) + } + return column +} diff --git a/apps/zui/src/js/state/Table/types.ts b/apps/zui/src/js/state/Table/types.ts new file mode 100644 index 0000000000..41c6d260a0 --- /dev/null +++ b/apps/zui/src/js/state/Table/types.ts @@ -0,0 +1,21 @@ +import * as zed from "@brimdata/zed-js" +import {ColumnSizingInfoState} from "@tanstack/react-table" + +// This is saved per table instance +export type TableState = { + columnExpandedDefault: boolean // table + columnResizeInfo: ColumnSizingInfoState // table + shape: zed.Type + settings: Map + scrollPosition: {top: 0; left: 0} +} + +// This is saved per shape in each table instance +export type TableSettingsState = { + valueExpanded: {} + valuePage: {} + columnWidth: {} + columnExpanded: {} + columnVisible: {} + columnSorted: {} +} diff --git a/apps/zui/src/plugins/brimcap/packets/download.ts b/apps/zui/src/plugins/brimcap/packets/download.ts index 76eda115a3..86d19357d9 100644 --- a/apps/zui/src/plugins/brimcap/packets/download.ts +++ b/apps/zui/src/plugins/brimcap/packets/download.ts @@ -4,7 +4,7 @@ import {createCli} from "../cli" import os from "os" import {window, env, commands} from "src/zui" import {queryForConnLog} from "./query-conn-log" -import {DOWNLOAD, DownloadArgs} from "./types" +import {DOWNLOAD} from "./types" function getSearchArgsFromConn(conn: zed.Record) { const dur = conn.try("duration") as zed.Duration @@ -45,7 +45,7 @@ export async function downloadPackets(root: string, pool: string, uid: string) { } export function activateDownloadPacketsCommand(packetsDir: string) { - commands.create(DOWNLOAD, (pool: string, uid: string) => + commands.create(DOWNLOAD, (pool: string, uid: string) => downloadPackets(packetsDir, pool, uid) ) } diff --git a/apps/zui/src/plugins/brimcap/packets/menu-item.ts b/apps/zui/src/plugins/brimcap/packets/menu-item.ts index c057190706..e1a83945d4 100644 --- a/apps/zui/src/plugins/brimcap/packets/menu-item.ts +++ b/apps/zui/src/plugins/brimcap/packets/menu-item.ts @@ -8,12 +8,11 @@ const MENU_NAME = "results.toolbarMenu" const packetsMenuItem: MenuItem = { id: "packets", - iconName: "sharkfin", + iconName: "wireshark", label: "Packets", description: "Download Packets", - command: DOWNLOAD, + command: DOWNLOAD as any, enabled: false, - priority: 1, } async function onSelectionChange({row}) { @@ -27,7 +26,8 @@ async function onSelectionChange({row}) { enabled = true } } - menus.get(MENU_NAME).update(packetsMenuItem.id, { + const id = packetsMenuItem.id + menus.updateItem(MENU_NAME, id, { enabled, args: [pool, uid] as DownloadArgs, }) @@ -36,5 +36,9 @@ async function onSelectionChange({row}) { export function activatePacketsMenuItem() { session.on("result-selection-change", onSelectionChange) - menus.extend(MENU_NAME, [packetsMenuItem]) + menus.extend(MENU_NAME, (menu: MenuItem[]) => { + const index = menu.findIndex((item) => item.id == "export-results") + menu.splice(index, 0, packetsMenuItem) + return menu + }) } diff --git a/apps/zui/src/plugins/brimcap/suricata/correlations.ts b/apps/zui/src/plugins/brimcap/suricata/correlations.ts index 8bf0b5d794..6f3b43ffae 100644 --- a/apps/zui/src/plugins/brimcap/suricata/correlations.ts +++ b/apps/zui/src/plugins/brimcap/suricata/correlations.ts @@ -7,7 +7,6 @@ export function activateSuricataCorrelations() { correlations.create(SURICATA_CONNS, { when: whenSuricata, query: () => { - debugger return zedScript` from ${session.poolName} | _path=="conn" diff --git a/apps/zui/src/ppl/css/_load-files-input.scss b/apps/zui/src/ppl/css/_load-files-input.scss deleted file mode 100644 index 458942d5ae..0000000000 --- a/apps/zui/src/ppl/css/_load-files-input.scss +++ /dev/null @@ -1,188 +0,0 @@ -@mixin radiation-circle { - position: absolute; - width: 300px; - height: 300px; - background: var(--cello); - opacity: 0.03; - border-radius: 50%; -} - -@keyframes updown { - from { - transform: translateY(5px); - } - - to { - transform: translateY(-5px); - } -} - -div.load-files-input { - margin: 24px 0; - min-width: 360px; - position: relative; - border-radius: 16px; - border: 2px dashed var(--orange); - box-shadow: inset 0 0 2px 0px rgba(0, 0, 0, 0.3); - background: white; - width: 100%; - height: 150px; - overflow: hidden; - padding: 22px; - box-shadow: none; - user-select: none; - - & > * { - pointer-events: none; - } - - .content { - display: flex; - justify-content: space-between; - align-items: center; - height: 100%; - width: 100%; - } - - .controls { - z-index: 1; - - button { - width: auto; - pointer-events: all; - } - - p { - @include label-small; - color: var(--slate); - } - } - - .file-types { - display: flex; - justify-content: space-between; - align-items: center; - - svg { - filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.15)); - } - } - - .files-stack { - position: relative; - margin-left: 22px; - height: 64px; - width: 54px; - - svg { - position: absolute; - top: 0; - left: 0; - - &:nth-child(2) { - top: 2px; - left: 3px; - } - - &:nth-child(3) { - top: 2 * 2px; - left: 2 * 3px; - } - } - } - - .radiation { - z-index: 0; - right: -190px; - top: -50%; - height: 300px; - width: 300px; - position: absolute; - - div { - @include radiation-circle; - - &:nth-child(1) { - transform: translateX(-25px) scale(1.1); - } - - &:nth-child(2) { - transform: translateX(-50px) scale(1.2); - } - } - } - - input[type="file"] { - width: 0.1px; - height: 0.1px; - opacity: 0; - overflow: hidden; - position: absolute; - z-index: -1; - } - - .drag-over-content { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - align-items: center; - justify-content: center; - z-index: 1; - opacity: 0; - border-radius: 14px; - - svg { - fill: white; - margin-right: 12px; - height: 16px; - width: 16px; - } - - p { - display: flex; - align-items: center; - pointer-events: none; - @include heading-section; - animation: updown 1200ms ease-in-out infinite alternate; - color: white; - } - } - - &.dragging { - transition: all 1s; - border-style: solid; - box-shadow: 0 8px 16px -1px rgba(0, 0, 0, 0.5); - - .content { - transition: opacity 1s; - opacity: 0; - } - - .drag-over-content { - transition: opacity 1s; - opacity: 1; - - p { - animation: updown 1200ms ease-in-out infinite alternate; - } - } - - .radiation { - z-index: 1; - transition: transform 1000ms; - transform: scale(3.3); - - div { - transition: opacity 1500ms; - opacity: 1; - } - } - - button { - pointer-events: none; - } - } -} diff --git a/apps/zui/src/ppl/detail/EventLimit.tsx b/apps/zui/src/ppl/detail/EventLimit.tsx index dc2570f262..33fd5d362e 100644 --- a/apps/zui/src/ppl/detail/EventLimit.tsx +++ b/apps/zui/src/ppl/detail/EventLimit.tsx @@ -3,8 +3,8 @@ import React, {memo, useCallback} from "react" import {useDispatch} from "src/app/core/state" import Link from "src/js/components/common/Link" import {openNewSearchTab} from "src/js/flows/openNewSearchWindow" -import submitSearch from "src/app/query-home/flows/submit-search" import Editor from "src/js/state/Editor" +import {submitSearch} from "src/domain/session/handlers" type Props = { count: number @@ -19,7 +19,7 @@ export default memo(function EventLimit({query, count, limit}) { if (global.windowName === "detail") { dispatch(openNewSearchTab()) } else { - dispatch(submitSearch()) + submitSearch() } }, [query]) diff --git a/apps/zui/src/ppl/detail/EventTimeline.tsx b/apps/zui/src/ppl/detail/EventTimeline.tsx index feb20b99aa..b6416d7cb4 100644 --- a/apps/zui/src/ppl/detail/EventTimeline.tsx +++ b/apps/zui/src/ppl/detail/EventTimeline.tsx @@ -1,13 +1,12 @@ import useContentRect from "src/app/core/hooks/useContentRect" import {scaleTime, extent} from "d3" -import React, {memo, useEffect, useState} from "react" +import React, {memo, useState} from "react" import styled from "styled-components" import {SecurityEventInterface} from "./models/security-event" import EventTag from "./EventTag" import {useDispatch} from "src/app/core/state" import {viewLogDetail} from "src/js/flows/viewLogDetail" import useResizeEffect from "src/app/core/hooks/useResizeEffect" -import ReactTooltip from "react-tooltip" import {isEqual} from "lodash" import useCallbackRef from "src/js/components/hooks/useCallbackRef" import time from "src/js/models/time" @@ -16,7 +15,7 @@ const Lane = styled.div` position: relative; display: flex; align-items: center; - height: 18px; + height: 26px; margin-bottom: 3px; &:last-of-type { margin-bottom: 0px; @@ -32,7 +31,7 @@ const Lane = styled.div` const Axis = styled.div` height: 1px; background: none; - box-shadow: 0 0.5px 0 var(--cloudy); + box-shadow: 0 0.5px 0 var(--border-color); width: 100%; ` @@ -77,13 +76,6 @@ function getDomain(events) { } export default memo(function EventTimeline({events, current}: Props) { - useEffect(() => { - // This is silly, but ReactTooltip cannot handle this component rerendering - // with new data. On their docs they have a case for this and suggest this - // workaround. They also have us hiding all the tooltips manually when this - // re-renders. Not very "react". - ReactTooltip.rebuild() - }, [events]) const dispatch = useDispatch() const [width, setWidth] = useState(0) const [lastItem, lastItemRef] = useContentRect() @@ -130,13 +122,9 @@ export default memo(function EventTimeline({events, current}: Props) {
    { - ReactTooltip.hide() onClick(e) }} - data-tip={time(e.getTime()).format()} - data-place="left" - data-effect="solid" - data-delay-show={0} + data-tooltip={time(e.getTime()).format()} style={{...getX(e)}} > p.theme.typography.labelSmall} + font-family: var(--mono-font); ` type Props = {event: SecurityEventInterface; className?: string} diff --git a/apps/zui/src/ppl/import/DataFileIcon.tsx b/apps/zui/src/ppl/import/DataFileIcon.tsx deleted file mode 100644 index bbddaa58f5..0000000000 --- a/apps/zui/src/ppl/import/DataFileIcon.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react" - -export default function DataFileIcon(props: any) { - return ( - - - - - - - - - - - - - - - ) -} diff --git a/apps/zui/src/ppl/import/LoadFilesInput.tsx b/apps/zui/src/ppl/import/LoadFilesInput.tsx deleted file mode 100644 index 82474db0e2..0000000000 --- a/apps/zui/src/ppl/import/LoadFilesInput.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import ToolbarButton from "src/app/query-home/toolbar/actions/button" -import classNames from "classnames" -import React, {MouseEvent} from "react" -import useCallbackRef from "src/js/components/hooks/useCallbackRef" -import Folder from "src/js/icons/Folder" -import DataFileIcon from "./DataFileIcon" -import {useFilesDrop} from "src/util/hooks/use-files-drop" - -type Props = { - onChange: (files: File[]) => void - className?: string -} - -export default function LoadFilesInput(props: Props) { - const [input, setInput] = useCallbackRef() - const [{canDrop, isOver}, drop] = useFilesDrop({onDrop: props.onChange}) - - function openDialog(_: MouseEvent) { - if (input) input.click() - } - - return ( -
    - props.onChange(Array.from(e.currentTarget.files))} - /> -
    -
    -
    -
    -
    -
    -
    - -

    Or drag & drop them here.

    -
    -
    -
    - - - -
    -
    -
    -
    -

    - Drop to import... -

    -
    -
    - ) -} diff --git a/apps/zui/src/ppl/zeek/zeek-plugin.tsx b/apps/zui/src/ppl/zeek/zeek-plugin.tsx index 97c0a22aff..b50457a40f 100644 --- a/apps/zui/src/ppl/zeek/zeek-plugin.tsx +++ b/apps/zui/src/ppl/zeek/zeek-plugin.tsx @@ -5,7 +5,7 @@ import React from "react" import * as zed from "@brimdata/zed-js" -export function isPath(name: string | string[], value: zed.Value) { +export function isPath(name: string | string[], value: zed.Type) { return name === "_path" && zed.isStringy(value) } diff --git a/apps/zui/src/test/system/teardown.ts b/apps/zui/src/test/system/teardown.ts index 279e8d39f7..56dbf3fb73 100644 --- a/apps/zui/src/test/system/teardown.ts +++ b/apps/zui/src/test/system/teardown.ts @@ -1,6 +1,6 @@ import {app, ipcMain, ipcRenderer} from "electron" import {autoUpdater} from "electron-updater" -import {pools, session} from "src/zui" +import {pools, session, commands} from "src/zui" export function teardown() { app.removeAllListeners() @@ -31,6 +31,7 @@ function teardownMockIpc(ipc: typeof ipcRenderer | typeof ipcMain) { function teardownPluginApi() { session._teardown() pools._teardown() + commands._teardown() } function teardownAutoUpdater() { diff --git a/apps/zui/src/util/find-ancestor.ts b/apps/zui/src/util/find-ancestor.ts new file mode 100644 index 0000000000..e84454a3d2 --- /dev/null +++ b/apps/zui/src/util/find-ancestor.ts @@ -0,0 +1,8 @@ +function getParent(node: Element) { + return node.parentNode instanceof Element ? node.parentNode : null +} + +export function findAncestor(node: Element, match: (n: Element) => boolean) { + while (node && !match(node)) node = getParent(node) + return node +} diff --git a/apps/zui/src/util/fixed-positioner.ts b/apps/zui/src/util/fixed-positioner.ts index eaefa853ea..73c204bd30 100644 --- a/apps/zui/src/util/fixed-positioner.ts +++ b/apps/zui/src/util/fixed-positioner.ts @@ -1,10 +1,10 @@ export function fixedPositioner(props: { - target: HTMLElement - anchor?: HTMLElement + target: Element + anchor?: Element targetPoint?: string anchorPoint?: string targetMargin?: string - keepOnScreen?: boolean + overflow?: "nudge" | "flip" }) { /* Default Fallbacks */ const doc = document.documentElement @@ -13,7 +13,7 @@ export function fixedPositioner(props: { const anchorPoint = props.anchorPoint ?? "center center" const targetPoint = props.targetPoint ?? "center center" const targetMargin = props.targetMargin ?? "0 0 0 0" - const keepOnScreen = props.keepOnScreen ?? true + const overflow = props.overflow ?? "nudge" /* Set Up Variables */ const anchorRect = anchor.getBoundingClientRect() @@ -22,53 +22,30 @@ export function fixedPositioner(props: { const leftMax = doc.clientWidth - leftMin const topMin = 0 const topMax = doc.clientHeight - topMin + const bounds = {leftMin, topMin, topMax, leftMax} const [anchorX, anchorY] = parsePoint(anchorPoint) const [targetX, targetY] = parsePoint(targetPoint) const margin = parseMargin(targetMargin) + const args = { + anchorRect, + targetRect, + anchorX, + anchorY, + targetX, + targetY, + margin, + } /* 1. Start with the anchor's top left position */ - let left = anchorRect.left - let top = anchorRect.top + let position = getPosition(args) + let overflows = getOverflows(targetRect, position, bounds) - /* 2. Move target's top left corner to the anchor's point */ - if (anchorX === "center") left = anchorRect.left + anchorRect.width / 2 - if (anchorX === "left") left = left + 0 - if (anchorX === "right") left = left + anchorRect.width - if (anchorY === "center") top = anchorRect.top + anchorRect.height / 2 - if (anchorY === "top") top = top + 0 - if (anchorY === "bottom") top = top + anchorRect.height - - /* 3. Move the target so that the targetPoint is on top of the anchorPoint */ - if (targetX === "center") left = left - targetRect.width / 2 - if (targetX === "left") left = left + 0 + margin.left - if (targetX === "right") left = left - targetRect.width - margin.right - if (targetY === "center") top = top - targetRect.height / 2 - if (targetY === "top") top = top + 0 + margin.top - if (targetY === "bottom") top = top - targetRect.height - margin.bottom - - /* 4. Try to keep the target on the screen */ - if (keepOnScreen) { - const {width, height} = targetRect - if (left + width > leftMax) { - const diff = left + width - leftMax - left -= diff - } - // then If you overflow to the left, set at left limit - if (left < leftMin) { - left = leftMin - } - // If you overflow on the bottom, back up - if (top + height > topMax) { - const diff = top + height - topMax - top -= diff - } - // then If you overflow on the top, set at top limit - if (top < topMin) { - top = topMin - } + if (overflow === "nudge") { + return nudge(position, overflows) + } else if (overflow === "flip") { + const newPoints = flip(args, overflows) + return getPosition({...args, ...newPoints}) } - - return {top, left} } /* Private Functions */ @@ -115,3 +92,98 @@ function toPixels(s: string) { throw new Error("Only pixel values accepted") } + +function getPosition({ + anchorRect, + targetRect, + anchorX, + anchorY, + targetX, + targetY, + margin, +}) { + /* 1. Start with the anchor's top left position */ + let left = anchorRect.left + let top = anchorRect.top + + /* 2. Move target's top left corner to the anchor's point */ + if (anchorX === "center") left = anchorRect.left + anchorRect.width / 2 + if (anchorX === "left") left = left + 0 + if (anchorX === "right") left = left + anchorRect.width + if (anchorY === "center") top = anchorRect.top + anchorRect.height / 2 + if (anchorY === "top") top = top + 0 + if (anchorY === "bottom") top = top + anchorRect.height + + /* 3. Move the target so that the targetPoint is on top of the anchorPoint */ + if (targetX === "center") left = left - targetRect.width / 2 + if (targetX === "left") left = left + 0 + margin.left + if (targetX === "right") left = left - targetRect.width - margin.right + if (targetY === "center") top = top - targetRect.height / 2 + if (targetY === "top") top = top + 0 + margin.top + if (targetY === "bottom") top = top - targetRect.height - margin.bottom + + return {top, left} +} + +function getOverflows(rect, position, bounds) { + const {width, height} = rect + const {top, left} = position + const {leftMax, leftMin, topMax, topMin} = bounds + const overflows = {top: 0, left: 0, right: 0, bottom: 0} + // Oveflowing to the right + if (left + width > leftMax) { + overflows.right = left + width - leftMax + } + // Overflowing to the left + if (left < leftMin) { + overflows.left = leftMin - left + } + // Overflowing at bottom + if (top + height > topMax) { + overflows.bottom = top + height - topMax + } + // Overflowing at top + if (top < topMin) { + overflows.top = topMin - top + } + return overflows +} + +function nudge(position, over) { + let {left, top} = position + + if (over.left) { + left += over.left + } else if (over.right) { + left -= over.right + } + + if (over.top) { + top += over.top + } else if (over.bottom) { + top -= over.bottom + } + + return {top, left} +} + +function flip(args, over) { + let {anchorX, anchorY, targetX, targetY} = args + + if (over.top) { + anchorY = "bottom" + targetY = "top" + } else if (over.bottom) { + anchorY = "top" + targetY = "bottom" + } + + if (over.left) { + anchorX = "right" + targetX = "left" + } else if (over.right) { + anchorX = "left" + targetX = "right" + } + return {anchorX, anchorY, targetX, targetY} +} diff --git a/apps/zui/src/util/hooks/use-color-scheme.ts b/apps/zui/src/util/hooks/use-color-scheme.ts new file mode 100644 index 0000000000..074394759f --- /dev/null +++ b/apps/zui/src/util/hooks/use-color-scheme.ts @@ -0,0 +1,18 @@ +import {useEffect, useState} from "react" + +const query = "(prefers-color-scheme: dark)" + +export function useColorScheme() { + const [isDark, setIsDark] = useState(() => window.matchMedia(query).matches) + + useEffect(() => { + const media = window.matchMedia(query) + const fn = ({matches}) => setIsDark(matches) + media.addEventListener("change", fn) + return () => { + media.removeEventListener("change", fn) + } + }, []) + + return {isDark, isLight: !isDark} +} diff --git a/apps/zui/src/util/hooks/use-fixed-position.ts b/apps/zui/src/util/hooks/use-fixed-position.ts index 89968a5662..6fd505e3c4 100644 --- a/apps/zui/src/util/hooks/use-fixed-position.ts +++ b/apps/zui/src/util/hooks/use-fixed-position.ts @@ -1,24 +1,24 @@ -import {useLayoutEffect, useState} from "react" +import {MutableRefObject, useLayoutEffect, useState} from "react" import useListener from "src/js/components/hooks/useListener" import {CSSProperties} from "react" import {fixedPositioner} from "../fixed-positioner" -type Props = Parameters[0] +type Props = Partial[0]> & { + target?: HTMLElement + targetRef?: MutableRefObject +} export function useFixedPosition(props: Props) { - const [style, setStyle] = useState({ - top: 0, - left: 0, - position: "fixed", - }) + const [style, setStyle] = useState({top: 0, left: 0}) - function run() { - if (!props.target) return - setStyle((prev) => ({...prev, ...fixedPositioner(props)})) + function calculate() { + const target = props.target || props.targetRef?.current + if (!target) return + setStyle(fixedPositioner({...props, target})) } - useLayoutEffect(run, Object.values(props)) - useListener(global.window, "resize", run) + useLayoutEffect(calculate, Object.values(props)) + useListener(global.window, "resize", calculate) return style } diff --git a/apps/zui/src/util/objectify.ts b/apps/zui/src/util/objectify.ts new file mode 100644 index 0000000000..077552f919 --- /dev/null +++ b/apps/zui/src/util/objectify.ts @@ -0,0 +1,5 @@ +export function objectify(keys, value) { + let obj = {} + for (let key of keys) obj[key] = value + return obj +} diff --git a/apps/zui/src/app/query-home/title-bar/plus-one.ts b/apps/zui/src/util/plus-one.ts similarity index 100% rename from apps/zui/src/app/query-home/title-bar/plus-one.ts rename to apps/zui/src/util/plus-one.ts diff --git a/apps/zui/src/util/tree.ts b/apps/zui/src/util/tree.ts new file mode 100644 index 0000000000..bfe4943821 --- /dev/null +++ b/apps/zui/src/util/tree.ts @@ -0,0 +1,28 @@ +export function find(data, id) { + if (!data) return + + for (let item of data) { + if (item.id === id) return item + const found = find(item.children, id) + if (found) return found + } +} + +export function getDecendents(data) { + let nodes = [data] + for (let item of data.children || []) { + nodes = nodes.concat(getDecendents(item)) + } + return nodes +} + +export function getDecendentIds(data) { + return getDecendents(data).map((d) => d.id) +} + +export function walk(data, fn) { + for (let item of data) { + fn(item) + if (item.children) walk(item.children, fn) + } +} diff --git a/apps/zui/src/views/application/index.tsx b/apps/zui/src/views/application/index.tsx index 2fa7976244..21d6e8cc7b 100644 --- a/apps/zui/src/views/application/index.tsx +++ b/apps/zui/src/views/application/index.tsx @@ -10,7 +10,7 @@ import {useAppMenu} from "./use-app-menu" import {WelcomePage} from "src/views/welcome-page" import {useReleaseNotes} from "./use-release-notes" import {InitPool, Show} from "src/views/pool-page" -import {QueryRoute} from "src/app/query-home/route" +import {SessionRoute} from "src/views/session-page/route" import Head from "next/head" import {useTabId} from "src/app/core/hooks/use-tab-id" import {NoTabsPane} from "src/views/no-tabs-pane" @@ -27,7 +27,7 @@ function AppRoutes() { - + diff --git a/apps/zui/src/views/application/use-app-menu.ts b/apps/zui/src/views/application/use-app-menu.ts index eb9a3fd4f7..e111d37e43 100644 --- a/apps/zui/src/views/application/use-app-menu.ts +++ b/apps/zui/src/views/application/use-app-menu.ts @@ -37,9 +37,6 @@ export function useAppMenu() { } update() - global.zui.on("updateSearchAppMenu", update) - return () => { - global.zui.off("updateSearchAppMenu", update) - } + return global.zui.on("updateSearchAppMenu", update) }, [state]) } diff --git a/apps/zui/src/views/application/use-shortcuts.ts b/apps/zui/src/views/application/use-shortcuts.ts index f642f38942..0dbe5845f8 100644 --- a/apps/zui/src/views/application/use-shortcuts.ts +++ b/apps/zui/src/views/application/use-shortcuts.ts @@ -3,7 +3,6 @@ import Mousetrap from "mousetrap" import Modal from "../../js/state/Modal" import Tabs from "../../js/state/Tabs" -import {newTab} from "src/app/query-home/flows/new-tab" import {useDispatch} from "src/app/core/state" export default function () { @@ -12,7 +11,7 @@ export default function () { const el = document.documentElement if (!el) throw new Error("No Document Element") const bindings = new Mousetrap(el) - .bind("mod+t", () => dispatch(newTab())) + .bind("mod+t", () => dispatch(Tabs.createQuerySession())) .bind("mod+w", (e) => { e.preventDefault() dispatch(Tabs.closeActive()) diff --git a/apps/zui/src/views/columns-pane/columns-toolbar.tsx b/apps/zui/src/views/columns-pane/columns-toolbar.tsx index cf2e26aa25..9a17aeaee7 100644 --- a/apps/zui/src/views/columns-pane/columns-toolbar.tsx +++ b/apps/zui/src/views/columns-pane/columns-toolbar.tsx @@ -1,18 +1,23 @@ import React from "react" import {Toolbar} from "src/components/toolbar" import {ButtonMenu} from "src/components/button-menu" -import {useResultsContext} from "src/app/query-home" import {columnsToolbarMenu} from "src/app/menus/columns-toolbar-menu" +import Table from "src/js/state/Table" +import {useSelector} from "react-redux" export function ColumnsToolbar() { - const {table} = useResultsContext() - if (!table) return null - const menu = columnsToolbarMenu.build(table) + const shape = useSelector(Table.getShape) + const columnCount = useSelector(Table.getVisibleColumnCount) + const hiddenCount = useSelector(Table.getHiddenColumnCount) + + if (!shape) return null + + const items = columnsToolbarMenu() return ( - +

    - {table.columnCount} Columns / {table.hiddenColumnCount} Hidden + {columnCount} Columns / {hiddenCount} Hidden

    ) diff --git a/apps/zui/src/views/columns-pane/columns-tree.tsx b/apps/zui/src/views/columns-pane/columns-tree.tsx index 01cd728320..f9bb484f4f 100644 --- a/apps/zui/src/views/columns-pane/columns-tree.tsx +++ b/apps/zui/src/views/columns-pane/columns-tree.tsx @@ -1,17 +1,20 @@ import React from "react" import {columnListItemMenu} from "src/app/menus/column-list-item-menu" import {ListItem} from "src/components/list-item" -import {ZedColumn} from "src/components/zed-table/column" import {NodeRendererProps, Tree} from "react-arborist" -import {useResultsContext} from "src/app/query-home" import {FillFlexParent} from "src/components/fill-flex-parent" import classNames from "classnames" import {EmptyText} from "src/app/features/right-pane/common" +import {useSelector} from "react-redux" +import Table from "src/js/state/Table" +import {TableColumn} from "src/js/state/Table/selectors" +import {collapseColumn, expandColumn} from "src/domain/results/handlers" +import {TREE_ITEM_HEIGHT} from "src/app/features/sidebar/item" -function Node(props: NodeRendererProps) { +function Node(props: NodeRendererProps) { const {node} = props const column = node.data - const menu = columnListItemMenu.build(column) + const menu = columnListItemMenu(column) return ( ) { innerRef={props.dragHandle} indent={node.level} isOpen={node.isOpen} - canToggle={column.isRecordType} + canToggle={column.children != null} onToggle={() => { - node.isOpen ? column.collapse() : column.expand() + node.isOpen ? collapseColumn(column.id) : expandColumn(column.id) node.toggle() }} menu={menu} @@ -37,8 +40,9 @@ function Node(props: NodeRendererProps) { } export function ColumnsTree() { - const {table} = useResultsContext() - if (!table) + const columns = useSelector(Table.getNestedColumns) + const openState = useSelector(Table.getColumnExpanded) + if (columns.length == 0) return Only available when results are in Table view. return ( @@ -47,12 +51,12 @@ export function ColumnsTree() { return ( setIsOpen(true)} label="Histogram Settings" ref={button} diff --git a/apps/zui/src/views/load-pane/form.module.css b/apps/zui/src/views/load-pane/form.module.css index a12d3aa675..d4d99e2638 100644 --- a/apps/zui/src/views/load-pane/form.module.css +++ b/apps/zui/src/views/load-pane/form.module.css @@ -9,7 +9,7 @@ padding-bottom: var(--side-padding); } -.formBody > * { +.formBody>* { padding: 0 var(--side-padding); } @@ -19,11 +19,11 @@ margin: var(--side-padding); margin-top: auto; margin-bottom: 1em; - color: var(--foreground-color-light); + color: var(--fg-color-less); text-align: center; font-size: 13px; box-shadow: inset 0 0 6px -2px rgb(0 0 0 / 0.15); - border: 1px solid var(--border-color-dark); + border: 1px solid var(--border-color-more); background: transparent; } @@ -37,7 +37,7 @@ .files { padding: 0; - background: white; + background: var(--form-bg-color); border: var(--form-border); border-radius: var(--form-border-radius); overflow: hidden auto; @@ -84,12 +84,12 @@ .form summary { cursor: pointer; letter-spacing: 0.3px; - color: var(--foreground-color-light); - padding: calc(var(--form-field-gap) / 3) 6px ; + color: var(--fg-color-less); + padding: calc(var(--form-field-gap) / 3) 6px; padding-right: 0; font-weight: 500; user-select: none; - transition: none; + transition: none; white-space: nowrap; } @@ -110,15 +110,16 @@ .summaryRule { display: inline-flex; align-items: center; - width: calc(100% - 1em); /* The em is the marker */ + width: calc(100% - 1em); + /* The em is the marker */ gap: 0.5em; } .summaryRule hr { flex: 0; height: 1px; - border:none; - border-top: 1px solid var(--border-color-dark); + border: none; + border-top: 1px solid var(--border-color-more); transition: all 200ms; } @@ -127,7 +128,7 @@ flex: 1; } -.form details[open] > summary { +.form details[open]>summary { margin-bottom: 10px; transition: all 400ms; } @@ -136,6 +137,6 @@ padding-bottom: calc(var(--form-field-gap)); } -.form details > *:not(summary) { +.form details>*:not(summary) { margin-left: var(--side-padding); - } +} diff --git a/apps/zui/src/views/load-pane/form.tsx b/apps/zui/src/views/load-pane/form.tsx index 1624771ef4..434b0747ce 100644 --- a/apps/zui/src/views/load-pane/form.tsx +++ b/apps/zui/src/views/load-pane/form.tsx @@ -1,6 +1,6 @@ import baseForm from "src/components/forms.module.css" import {ScrollShadow} from "./scroll-shadow" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import Current from "src/js/state/Current" import {useForm} from "react-hook-form" import {useSelector} from "react-redux" @@ -103,8 +103,8 @@ export function Form(props: { aria-label={basename(f)} > diff --git a/apps/zui/src/views/load-pane/index.module.css b/apps/zui/src/views/load-pane/index.module.css index f825be80b2..e119caaf08 100644 --- a/apps/zui/src/views/load-pane/index.module.css +++ b/apps/zui/src/views/load-pane/index.module.css @@ -4,7 +4,7 @@ display: grid; grid-template-rows: 1fr; grid-template-columns: 1fr 360px; - border-radius: 8px 8px 0 0 ; + border-radius: 8px 8px 0 0; overflow: hidden; background-color: var(--chrome-color); } @@ -19,7 +19,7 @@ height: 100%; width: 100%; grid-row: 1 / 2; - grid-column: 1 / 2; + grid-column: 1 / 2; padding: 10px; padding-right: 0px; } diff --git a/apps/zui/src/views/load-pane/results.module.css b/apps/zui/src/views/load-pane/results.module.css index fb2479a6d7..ce1887954d 100644 --- a/apps/zui/src/views/load-pane/results.module.css +++ b/apps/zui/src/views/load-pane/results.module.css @@ -1,7 +1,7 @@ .results { display: grid; grid-template-rows: 38px 1fr 30px; - background: white; + background: var(--bg-color); margin-top: 0; box-shadow: var(--shadow-elevation-low); border-radius: 6px; @@ -16,7 +16,7 @@ align-items: center; justify-content: space-between; padding: 0 18px; - color: var(--foreground-color-light); + color: var(--fg-color-less); contain: inline-size; gap: 4px; } @@ -49,13 +49,13 @@ display: flex; align-items: center; justify-content: flex-end; - background-color: white; + background-color: var(--bg-color); gap: 12px; border-radius: 0 0 6px 6px; } .results footer button { - color: var(--foreground-color-light); + color: var(--fg-color-less); text-decoration: none; border-radius: 6px; padding: 0 6px; @@ -69,13 +69,13 @@ } .results footer button:hover { - color: var(--foreground-color); - background: var(--hover-dark); + color: var(--fg-color); + background: var(--emphasis-bg-less); } .results footer button:active { - color: var(--foreground-color); - background: var(--active-dark); + color: var(--fg-color); + background: var(--emphasis-bg); } .results label { @@ -96,6 +96,7 @@ display: flex; align-items: center; justify-content: center; - color: var(--foreground-color-light); - font-weight: bold;; + color: var(--fg-color-less); + font-weight: bold; + ; } diff --git a/apps/zui/src/views/load-pane/results.tsx b/apps/zui/src/views/load-pane/results.tsx index 3012a4eb9a..a61c0ac7f3 100644 --- a/apps/zui/src/views/load-pane/results.tsx +++ b/apps/zui/src/views/load-pane/results.tsx @@ -14,8 +14,8 @@ import {ErrorWell} from "src/components/error-well" import {isNumber} from "lodash" import {useZq} from "./use-zq" import {ResultDimension, ResultDisplay} from "./use-results-display" -import {BareStringView} from "src/app/query-home/results/bare-string-view" -import {PathView} from "src/app/query-home/results/path-view" +import {PathView} from "../results-pane/path-view" +import {BareStringView} from "../results-pane/bare-string-view" const HEAD_LIMIT = 100 @@ -106,7 +106,7 @@ function Toolbar(props: { { iconName: props.display.format === "table" - ? "expand-horizontal" + ? "expand_horizontal" : "expand", label: "Expand All", click: () => props.display.expandAll(), @@ -114,7 +114,7 @@ function Toolbar(props: { { iconName: props.display.format === "table" - ? "collapse-horizontal" + ? "collapse_horizontal" : "collapse", label: "Collapse All", click: () => props.display.collapseAll(), diff --git a/apps/zui/src/views/load-pane/shaper.module.css b/apps/zui/src/views/load-pane/shaper.module.css index ac155a01d9..0b0f7b4ba1 100644 --- a/apps/zui/src/views/load-pane/shaper.module.css +++ b/apps/zui/src/views/load-pane/shaper.module.css @@ -9,7 +9,7 @@ font-size: 14px; font-weight: 600; text-align: center; - color: var(--foreground-color-light); + color: var(--fg-color-less); } .toolbarActions { @@ -24,7 +24,7 @@ min-width: 0; display: grid; grid-template-rows: 44px 1fr; - background: white; + background: var(--bg-color); border-radius: 6px; box-shadow: var(--shadow-elevation-low); } diff --git a/apps/zui/src/views/load-pane/shaper.tsx b/apps/zui/src/views/load-pane/shaper.tsx index 329c6c6077..361fd8d9ca 100644 --- a/apps/zui/src/views/load-pane/shaper.tsx +++ b/apps/zui/src/views/load-pane/shaper.tsx @@ -1,9 +1,6 @@ import {IconButton} from "src/components/icon-button" import styles from "./shaper.module.css" -import { - ZedEditor, - useZedEditorKeyboardSubmit, -} from "src/app/query-home/search-area/zed-editor" +import {ZedEditor, useZedEditorKeyboardSubmit} from "src/components/zed-editor" import DragAnchor from "src/components/drag-anchor" import useSelect from "src/app/core/hooks/use-select" import {useDispatch} from "src/app/core/state" diff --git a/apps/zui/src/views/pool-page/details.module.css b/apps/zui/src/views/pool-page/details.module.css index f8931bbe58..38de5cf621 100644 --- a/apps/zui/src/views/pool-page/details.module.css +++ b/apps/zui/src/views/pool-page/details.module.css @@ -1,4 +1,4 @@ -.details { +.details { padding: var(--page-padding); max-width: var(--page-max-width); width: 100%; diff --git a/apps/zui/src/views/pool-page/index.module.css b/apps/zui/src/views/pool-page/index.module.css index e6cfe2dead..efcc25b982 100644 --- a/apps/zui/src/views/pool-page/index.module.css +++ b/apps/zui/src/views/pool-page/index.module.css @@ -15,8 +15,8 @@ .header { position: sticky; top: 0; - background: white; border-bottom: 1px solid var(--border-color); + background-color: var(--bg-color); } .headerContent { diff --git a/apps/zui/src/views/pool-page/index.tsx b/apps/zui/src/views/pool-page/index.tsx index ee3679c545..9ac795870c 100644 --- a/apps/zui/src/views/pool-page/index.tsx +++ b/apps/zui/src/views/pool-page/index.tsx @@ -65,7 +65,7 @@ export function InitPool({children}) { export const Show = () => { const pool = useSelector(Current.mustGetPool) - const menu = poolToolbarMenu.build(pool) + const menu = poolToolbarMenu(pool) const isEmpty = pool.empty() return (
    @@ -78,7 +78,7 @@ export const Show = () => {
    - +
    diff --git a/apps/zui/src/views/pool-page/job.module.css b/apps/zui/src/views/pool-page/job.module.css index 0f908b6fd0..178b7116ef 100644 --- a/apps/zui/src/views/pool-page/job.module.css +++ b/apps/zui/src/views/pool-page/job.module.css @@ -6,7 +6,7 @@ align-items: center; column-gap: 1em; grid-template-areas: "icon info actions" - ". details ."; + ". details ."; min-height: 86px; } @@ -41,7 +41,7 @@ .status { grid-area: status; - color: var(--foreground-color-light); + color: var(--fg-color-less); font-size: 0.8rem; } @@ -57,34 +57,39 @@ } .loadingIcon path:nth-child(1) { - animation: upload 1.6s 532ms infinite var(--pop-easing); + animation: upload 1.6s 532ms infinite var(--pop-easing); } + .loadingIcon path:nth-child(2) { animation: upload 1.6s 266ms infinite var(--pop-easing); } + .loadingIcon path:nth-child(3) { - animation: upload 1.6s infinite var(--pop-easing); + animation: upload 1.6s infinite var(--pop-easing); } + @keyframes upload { from { transform: translateY(80%); opacity: 0; } + 50% { opacity: 1; transform: translateY(0); } + to { opacity: 0; transform: translateY(-80%); } - + } .loadingIcon { - color: var(--foreground-color-light); + color: var(--fg-color-less); color: var(--blue); - background: var(--chrome-color-dark); + background: var(--chrome-color-more); } .successIcon { @@ -101,6 +106,6 @@ border-top: 1px solid var(--border-color); margin-top: 0.5rem; padding-top: 0.75rem; - color: var(--foreground-color-light); + color: var(--fg-color-less); grid-area: details; } diff --git a/apps/zui/src/views/pool-page/job.tsx b/apps/zui/src/views/pool-page/job.tsx index cc0eef0173..569600582a 100644 --- a/apps/zui/src/views/pool-page/job.tsx +++ b/apps/zui/src/views/pool-page/job.tsx @@ -2,7 +2,7 @@ import ProgressIndicator from "src/js/components/ProgressIndicator" import styles from "./job.module.css" import {IconButton} from "src/components/icon-button" import {ThreeUpArrows} from "./three-up-arrows" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import {ReactNode} from "react" type JobStatus = "loading" | "error" | "success" | "aborted" @@ -61,7 +61,7 @@ function JobIcon(props: {status: JobStatus}) { case "aborted": return (
    - +
    ) } diff --git a/apps/zui/src/views/pool-page/recent-loads.module.css b/apps/zui/src/views/pool-page/recent-loads.module.css index ba22ae0f9d..23bc63813f 100644 --- a/apps/zui/src/views/pool-page/recent-loads.module.css +++ b/apps/zui/src/views/pool-page/recent-loads.module.css @@ -16,13 +16,13 @@ gap: .5rem; } -.list > * { +.list>* { padding: 1rem; border-radius: 16px; cursor: default; background: var(--chrome-color); } -.list > *:hover { - background: var(--hover-dark); +.list>*:hover { + background: var(--emphasis-bg-less); } diff --git a/apps/zui/src/views/preferences-modal/index.module.css b/apps/zui/src/views/preferences-modal/index.module.css index c92ba31369..712f0d081b 100644 --- a/apps/zui/src/views/preferences-modal/index.module.css +++ b/apps/zui/src/views/preferences-modal/index.module.css @@ -6,70 +6,3 @@ .title { margin-bottom: calc(var(--form-field-gap) * 3); } - - /* .settings-form { - border-radius: 3px; - - a { - text-decoration: underline; - cursor: pointer; - @include label-small; - } - - input, - select { - width: 240px; - } - - .setting-panel { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 12px; - height: 48px; - border-bottom: 1px solid var(--ivory); - position: relative; - - &:last-child { - border: none; - } - } - } - - .errors { - h4 { - margin-bottom: 0.25rem; - } - - ul { - margin-top: 1rem; - line-height: 1.5; - } - - a { - color: var(--red); - cursor: pointer; - text-decoration: underline; - } - - p { - margin: 0; - @include label-small; - } - } - - .feedback { - position: absolute; - right: 12px; - top: 1px; - margin: 0; - @include label-small; - line-height: 14px; - background: var(--havelock); - color: white; - padding: 0 6px; - border-radius: 4px; - animation: fadein 300ms; - z-index: 1; - } -} */ diff --git a/apps/zui/src/app/query-home/results/alert-view.ts b/apps/zui/src/views/results-pane/alert-view.ts similarity index 100% rename from apps/zui/src/app/query-home/results/alert-view.ts rename to apps/zui/src/views/results-pane/alert-view.ts diff --git a/apps/zui/src/app/query-home/results/bare-string-view.ts b/apps/zui/src/views/results-pane/bare-string-view.ts similarity index 100% rename from apps/zui/src/app/query-home/results/bare-string-view.ts rename to apps/zui/src/views/results-pane/bare-string-view.ts diff --git a/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx b/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx index ed054b0b7d..4ad8f5056f 100644 --- a/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx +++ b/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx @@ -1,7 +1,6 @@ import React from "react" import {useSelector} from "react-redux" -import {createFrom} from "src/app/commands/pins" -import Icon from "src/app/core/icon-temp" +import {Icon} from "src/components/icon" import {Pool} from "src/app/core/pools/pool" import {Item} from "src/app/features/sidebar/item" import useLakeId from "src/app/router/hooks/use-lake-id" @@ -10,8 +9,8 @@ import {VirtualList} from "src/js/components/virtual-list" import Pools from "src/js/state/Pools" import {State} from "src/js/state/types" import styled from "styled-components" -import {Button} from "../../../app/query-home/title-bar/button" import {newPool} from "src/domain/pools/handlers" +import {setFromPin} from "src/domain/session/handlers" const BG = styled.div` width: 100%; @@ -32,7 +31,6 @@ const Message = styled(Content)` ` const Card = styled.section` - background: white; display: flex; flex-direction: column; align-items: center; @@ -50,7 +48,7 @@ export function isMissingPoolError(e: unknown) { } function PoolsList({pools}: {pools: Pool[]}) { - const rowHeight = 26 + const rowHeight = 32 return ( @@ -67,7 +65,7 @@ function PoolsList({pools}: {pools: Pool[]}) { text={props.item.name} style={props.style} icon={} - onClick={() => createFrom.run(props.item.name)} + onClick={() => setFromPin(props.item.name)} aria={props.aria} /> ) @@ -86,7 +84,7 @@ function NoPoolsMessage() { } - + ) diff --git a/apps/zui/src/views/results-pane/errors/network-error.tsx b/apps/zui/src/views/results-pane/errors/network-error.tsx index ac6b236765..b358b980a0 100644 --- a/apps/zui/src/views/results-pane/errors/network-error.tsx +++ b/apps/zui/src/views/results-pane/errors/network-error.tsx @@ -1,6 +1,5 @@ import React from "react" -import {useDispatch} from "src/app/core/state" -import submitSearch from "src/app/query-home/flows/submit-search" +import {submitSearch} from "src/domain/session/handlers" import ConnectionError from "src/js/components/ConnectionError" export function isNetworkError(e: unknown) { @@ -8,6 +7,5 @@ export function isNetworkError(e: unknown) { } export function NetworkError() { - const dispatch = useDispatch() - return dispatch(submitSearch())} /> + return submitSearch()} /> } diff --git a/apps/zui/src/views/results-pane/inspector.tsx b/apps/zui/src/views/results-pane/inspector.tsx index 9f7d316449..adeda14930 100644 --- a/apps/zui/src/views/results-pane/inspector.tsx +++ b/apps/zui/src/views/results-pane/inspector.tsx @@ -9,8 +9,10 @@ import * as zed from "@brimdata/zed-js" import {valueContextMenu} from "src/app/menus/value-context-menu" import useSelect from "src/app/core/hooks/use-select" import {ListViewApi} from "src/zui-kit" -import {PathView} from "src/app/query-home/results/path-view" -import {AlertView} from "src/app/query-home/results/alert-view" +import {PathView} from "./path-view" +import {AlertView} from "./alert-view" +import {showMenu} from "src/core/menu" +import Selection from "src/js/state/Selection" export function Inspector(props: {height?: number}) { const {values, shapes, width, height, loadMore, key} = useResultsPaneContext() @@ -59,14 +61,18 @@ export function Inspector(props: {height?: number}) { }} valueProps={{ onClick: (e, value, field) => { + const rootValue = field.rootRecord + dispatch(Selection.set({value, field, rootValue})) if (field && field instanceof zed.Field) { dispatch(viewLogDetail(field.rootRecord)) } }, onContextMenu: (e, value, field) => { e.preventDefault() + const rootValue = field.rootRecord + dispatch(Selection.set({value, field, rootValue})) if (field && field instanceof zed.Field) { - valueContextMenu.build(value, field, field.rootRecord).show() + showMenu(valueContextMenu(value, field, field.rootRecord)) } }, }} diff --git a/apps/zui/src/app/query-home/results/path-view.ts b/apps/zui/src/views/results-pane/path-view.ts similarity index 100% rename from apps/zui/src/app/query-home/results/path-view.ts rename to apps/zui/src/views/results-pane/path-view.ts diff --git a/apps/zui/src/views/results-pane/results-pane.module.css b/apps/zui/src/views/results-pane/results-pane.module.css index bc8f733a2a..5c7d83979a 100644 --- a/apps/zui/src/views/results-pane/results-pane.module.css +++ b/apps/zui/src/views/results-pane/results-pane.module.css @@ -2,3 +2,12 @@ height: 100%; min-height: 40px; } + +.comingSoon { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + text-align: center; + margin-top: 5rem; +} diff --git a/apps/zui/src/views/results-pane/table-controller.tsx b/apps/zui/src/views/results-pane/table-controller.tsx index 9cdd9b50e0..c5dc80e367 100644 --- a/apps/zui/src/views/results-pane/table-controller.tsx +++ b/apps/zui/src/views/results-pane/table-controller.tsx @@ -1,49 +1,15 @@ -import {useMemo} from "react" -import {ZedTableHandlers, ZedTableState} from "src/components/zed-table/types" -import {useDispatch} from "src/app/core/state" -import {RESULTS_QUERY} from "src/views/results-pane/run-results-query" -import {useResultsContext} from "src/app/query-home" -import {headerContextMenu} from "src/app/menus/header-context-menu" -import {useSelector} from "react-redux" -import TableState from "src/js/state/Table" -import {State} from "src/js/state/types" -import {valueContextMenu} from "src/app/menus/value-context-menu" +import {useEffect, useMemo} from "react" +import Slice from "src/js/state/Table" import {useResultsPaneContext} from "./context" -import {useNextPage} from "src/core/query/use-query" +import useSelect from "src/app/core/hooks/use-select" -export function useTableState() { - const {firstShape} = useResultsPaneContext() - const {query} = useResultsContext() - const state = useSelector((state: State) => - TableState.getStateForShape(state, firstShape) - ) - return useMemo( - () => ({...state, columnSorted: query.toAst().sorts}), - [state, query] - ) -} - -export function useTableHandlers() { +export function useScrollPosition(table) { const ctx = useResultsPaneContext() - const dispatch = useDispatch() - const shape = ctx.firstShape - const nextPage = useNextPage(RESULTS_QUERY) - return useMemo( - () => ({ - onStateChange: (state) => { - dispatch(TableState.setStateForShape({shape, state})) - }, - onScrollNearBottom: nextPage, - onHeaderContextMenu(e, column) { - headerContextMenu - .build(this, column) - .showUnder(e.currentTarget as HTMLElement) - }, - onValueContextMenu(e, value, field, cell) { - e.preventDefault() - valueContextMenu.build(value, field, cell.value).show() - }, - }), - [shape] - ) + const select = useSelect() + useEffect(() => { + const pos = select(Slice.getScrollPosition) + table?.scrollTo(pos) + }, [ctx.key]) + + return useMemo(() => select(Slice.getScrollPosition), []) } diff --git a/apps/zui/src/views/results-pane/table-inspector.tsx b/apps/zui/src/views/results-pane/table-inspector.tsx index bcf62aa072..c86aaff4f7 100644 --- a/apps/zui/src/views/results-pane/table-inspector.tsx +++ b/apps/zui/src/views/results-pane/table-inspector.tsx @@ -1,9 +1,9 @@ import React from "react" -import {fuse} from "src/app/commands/editor" import {config} from "src/components/zed-table/config" import styled from "styled-components" import {useResultsPaneContext} from "./context" import {Inspector} from "./inspector" +import {fuse} from "src/domain/editor/handlers" /** * This component is for when the user wants a table, * but their data has more than one shape @@ -33,7 +33,7 @@ export function TableInspector() { {shapes.length} Shapes — Filter to one shape or{" "} - fuse.run()}>fuse + fuse()}>fuse {" "} results to view as a table. diff --git a/apps/zui/src/views/results-pane/table.tsx b/apps/zui/src/views/results-pane/table.tsx index 65f7d15474..b7bf808884 100644 --- a/apps/zui/src/views/results-pane/table.tsx +++ b/apps/zui/src/views/results-pane/table.tsx @@ -1,78 +1,84 @@ -import React, {useEffect, useMemo} from "react" -import {useResultsContext} from "src/app/query-home" +import React, {useState} from "react" import {useResultsPaneContext} from "./context" -import {useTableState} from "./table-controller" import {useDispatch} from "src/app/core/state" -import TableState from "src/js/state/Table" +import Slice from "src/js/state/Table" import {headerContextMenu} from "src/app/menus/header-context-menu" import {valueContextMenu} from "src/app/menus/value-context-menu" -import useSelect from "src/app/core/hooks/use-select" import {TableView, TableViewApi} from "src/zui-kit" -import {useZuiApi} from "src/app/core/context" -import {BareStringView} from "src/app/query-home/results/bare-string-view" -import {PathView} from "src/app/query-home/results/path-view" import {openLogDetailsWindow} from "src/js/flows/openLogDetailsWindow" import {viewLogDetail} from "src/js/flows/viewLogDetail" -import * as zed from "@brimdata/zed-js" -import {AlertView} from "src/app/query-home/results/alert-view" +import {useSelector} from "react-redux" +import {useScrollPosition} from "./table-controller" +import {AlertView} from "./alert-view" +import {BareStringView} from "./bare-string-view" +import {PathView} from "./path-view" +import {showMenu} from "src/core/menu" +import Selection from "src/js/state/Selection" + +// 1. Don't forget to save the shape using zed.typeunder export function Table() { - const {table, setTable} = useResultsContext() - const ctx = useResultsPaneContext() - const api = useZuiApi() - const shape = ctx.firstShape - const recordShape = zed.typeunder(shape) as zed.TypeRecord - const state = useTableState() - const select = useSelect() - const initialScrollPosition = useMemo( - () => select(TableState.getScrollPosition), - [] - ) const dispatch = useDispatch() - - useEffect(() => { - dispatch(TableState.setLastShape(shape)) - return () => { - dispatch(TableState.setLastShape(null)) - } - }, [shape]) - - useEffect(() => { - const pos = select(TableState.getScrollPosition) - table?.scrollTo(pos) - }, [ctx.key]) + const [table, setTable] = useState(null) + const ctx = useResultsPaneContext() + const settings = useSelector(Slice.getShapeSettings) + const shape = useSelector(Slice.getShape) + const initialScrollPosition = useScrollPosition(table) return ( { - setTable(table) - api.table = table - }} - shape={recordShape} + ref={setTable} + shape={shape} values={ctx.values} width={ctx.width} height={ctx.height} initialScrollPosition={initialScrollPosition} - state={{ - value: state, - onChange: (state) => { - dispatch(TableState.setStateForShape({shape, state})) - }, + valuePageState={{ + value: settings.valuePage, + onChange: (next) => dispatch(Slice.setValuePage(next)), + }} + valueExpandedState={{ + value: settings.valueExpanded, + onChange: (next) => dispatch(Slice.setValueExpanded(next)), + }} + columnExpandedDefaultState={{ + value: useSelector(Slice.getColumnExpandedDefault), + }} + columnExpandedState={{ + value: settings.columnExpanded, + onChange: (next) => dispatch(Slice.setColumnExpanded(next)), + }} + columnSortedState={{ + value: settings.columnSorted, + onChange: (next) => dispatch(Slice.setColumnSorted(next)), + }} + columnWidthState={{ + value: settings.columnWidth, + onChange: (next) => dispatch(Slice.setColumnWidth(next)), + }} + columnVisibleState={{ + value: settings.columnVisible, + onChange: (next) => dispatch(Slice.setColumnVisible(next)), }} headerCellProps={{ onContextMenu: (e, column) => { - headerContextMenu - .build(table, column) - .showUnder(e.currentTarget as HTMLElement) + showMenu( + headerContextMenu(table, column), + e.currentTarget as HTMLElement + ) }, }} cellProps={{ onContextMenu: (e, value, field, cell) => { e.preventDefault() - valueContextMenu.build(value, field, cell.value).show() + const rootValue = field.rootRecord + dispatch(Selection.set({value, field, rootValue})) + showMenu(valueContextMenu(value, field, cell.value)) }, - onClick: (e, _value, field) => { + onClick: (e, value, field) => { e.preventDefault() + const rootValue = field.rootRecord + dispatch(Selection.set({value, field, rootValue})) dispatch(viewLogDetail(field.rootRecord)) }, onDoubleClick: (e, _value, field) => { @@ -81,7 +87,7 @@ export function Table() { }, }} onScroll={(pos) => { - dispatch(TableState.setScrollPosition(pos)) + dispatch(Slice.setScrollPosition(pos)) if (table.nearBottom(30)) ctx.loadMore() }} viewConfig={{ diff --git a/apps/zui/src/views/session-page/detail-bar.module.css b/apps/zui/src/views/session-page/detail-bar.module.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/zui/src/views/session-page/detail-bar.tsx b/apps/zui/src/views/session-page/detail-bar.tsx new file mode 100644 index 0000000000..fd6562a63e --- /dev/null +++ b/apps/zui/src/views/session-page/detail-bar.tsx @@ -0,0 +1,3 @@ +export function DetailBar() { + return +} diff --git a/apps/zui/src/views/session-page/editor-resizer.tsx b/apps/zui/src/views/session-page/editor-resizer.tsx new file mode 100644 index 0000000000..3161b586d5 --- /dev/null +++ b/apps/zui/src/views/session-page/editor-resizer.tsx @@ -0,0 +1,35 @@ +import DragAnchor from "src/components/drag-anchor" +import {useDispatch} from "../../app/core/state" +import Layout from "src/js/state/Layout" +import {useRef} from "react" +import useSelect from "../../app/core/hooks/use-select" + +export function EditorResizer({container}) { + const dispatch = useDispatch() + const select = useSelect() + const start = useRef(0) + + const onStart = () => { + start.current = select(Layout.getEditorHeight) + } + + const onDrag = (e, {dy}) => { + dispatch(Layout.setEditorHeight(start.current + dy)) + } + + const onEnd = () => { + if (container.current) { + const height = container.current.clientHeight + dispatch(Layout.setEditorHeight(height + 10 /* Margin */)) + } + } + + return ( + + ) +} diff --git a/apps/zui/src/views/session-page/editor.module.css b/apps/zui/src/views/session-page/editor.module.css new file mode 100644 index 0000000000..0209d1b02f --- /dev/null +++ b/apps/zui/src/views/session-page/editor.module.css @@ -0,0 +1,4 @@ +.container { + margin-top: 10px; + position: relative; +} diff --git a/apps/zui/src/views/session-page/editor.tsx b/apps/zui/src/views/session-page/editor.tsx new file mode 100644 index 0000000000..fad4227063 --- /dev/null +++ b/apps/zui/src/views/session-page/editor.tsx @@ -0,0 +1,46 @@ +import React, {useRef} from "react" + +import {useSelector} from "react-redux" +import MainEditor from "src/js/state/Editor" +import {useDispatch} from "src/app/core/state" +import {cmdOrCtrl} from "src/app/core/utils/keyboard" +import Config from "src/js/state/Config" +import {useTabId} from "src/app/core/hooks/use-tab-id" +import {ZedEditor} from "src/components/zed-editor" +import {EditorResizer} from "src/views/session-page/editor-resizer" +import styles from "./editor.module.css" +import {submitSearch} from "src/domain/session/handlers" + +export function Editor() { + const value = useSelector(MainEditor.getValue) + const runOnEnter = useSelector(Config.getRunOnEnter) + const dispatch = useDispatch() + const tabId = useTabId() + const container = useRef() + const onChange = (v: string) => { + dispatch(MainEditor.setValue(v)) + } + + const onKey = (e: React.KeyboardEvent) => { + const isEnterKey = e.key === "Enter" + const isModKey = e.shiftKey || cmdOrCtrl(e) + if (isEnterKey) { + if ((runOnEnter && !isModKey) || (!runOnEnter && isModKey)) { + e.preventDefault() + submitSearch() + } + } + } + + return ( +
    + + +
    + ) +} diff --git a/apps/zui/src/views/session-page/footer.module.css b/apps/zui/src/views/session-page/footer.module.css new file mode 100644 index 0000000000..d9756c5d87 --- /dev/null +++ b/apps/zui/src/views/session-page/footer.module.css @@ -0,0 +1,28 @@ +.footer { + height: 2.625rem; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 10px; + box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.1); + gap: 1rem; + z-index: 1; +} + +.label { + text-transform: none; + letter-spacing: normal; + font-weight: normal; + font-size: 0.8rem; +} + +.footer [aria-pressed=true] .label { + font-weight: bold; +} + +.counts { + font-family: var(--mono-font); + display: flex; + white-space: nowrap; + gap: 1.5rem; +} diff --git a/apps/zui/src/views/session-page/footer.tsx b/apps/zui/src/views/session-page/footer.tsx new file mode 100644 index 0000000000..996679fda1 --- /dev/null +++ b/apps/zui/src/views/session-page/footer.tsx @@ -0,0 +1,125 @@ +import {ButtonMenu} from "src/components/button-menu" +import styles from "./footer.module.css" +import {ToolbarTabs} from "src/components/toolbar-tabs" +import {useSelector} from "react-redux" +import Layout from "src/js/state/Layout" +import { + collapseAllColumns, + collapseAllHandler, + expandAllColumns, + expandAllHandler, + showInspectorView, + showTableView, + toggleHistogram, +} from "src/domain/results/handlers" +import React from "react" +import {RESULTS_QUERY} from "src/views/results-pane/run-results-query" +import styled from "styled-components" +import Results from "src/js/state/Results" +import {pluralize} from "src/util/pluralize" +import {MenuItem} from "src/core/menu" + +export function Footer() { + const view = useSelector(Layout.getResultsView) + + const tableItems: MenuItem[] = [ + {iconName: "chart", click: toggleHistogram, label: "Toggle Histogram"}, + { + iconName: "expand_horizontal", + click: expandAllColumns, + label: "Expand Columns", + }, + { + iconName: "collapse_horizontal", + click: collapseAllColumns, + label: "Collapse Columns", + }, + ] + const inspectorItems: MenuItem[] = [ + {iconName: "chart", click: toggleHistogram, label: "Toggle Histogram"}, + {iconName: "expand", click: expandAllHandler, label: "Expand Rows"}, + {iconName: "collapse", click: collapseAllHandler, label: "Collapse Rows"}, + ] + + return ( +
    + + +
    + + +
    +
    + ) +} + +const Span = styled.span` + display: inline-flex; + align-items: center; + gap: 10px; +` + +export function RowCount() { + const status = useSelector(Results.getStatus(RESULTS_QUERY)) + const count = useSelector(Results.getCount(RESULTS_QUERY)) + if (status === "FETCHING") { + return ( + + Fetching... + + ) + } else if (status === "COMPLETE") { + return ( + + {count} {pluralize("Row", count)} + + ) + } else if (status === "INCOMPLETE") { + return ( + + First {count} {pluralize("Row", count)} + + ) + } else if (status === "LIMIT") { + return ( + + Limited to {count} {pluralize("Row", count)} + + ) + } +} + +function ShapeCount() { + const shapes = useSelector(Results.getShapes(RESULTS_QUERY)) + const status = useSelector(Results.getStatus(RESULTS_QUERY)) + const count = Object.keys(shapes).length + if (["COMPLETE", "LIMIT", "INCOMPLETE"].includes(status)) { + return ( + + {count} {pluralize("Shape", count)} + + ) + } else { + return null + } +} diff --git a/apps/zui/src/views/session-page/grid.module.css b/apps/zui/src/views/session-page/grid.module.css new file mode 100644 index 0000000000..1baf05f9fd --- /dev/null +++ b/apps/zui/src/views/session-page/grid.module.css @@ -0,0 +1,5 @@ +.grid { + height: 100%; + display: grid; + grid-template-columns: minmax(0, 1fr); +} diff --git a/apps/zui/src/views/session-page/grid.tsx b/apps/zui/src/views/session-page/grid.tsx new file mode 100644 index 0000000000..49c7dd3beb --- /dev/null +++ b/apps/zui/src/views/session-page/grid.tsx @@ -0,0 +1,20 @@ +import {useSelector} from "react-redux" +import styles from "./grid.module.css" +import Layout from "src/js/state/Layout" + +export function Grid({children}) { + const title = "min-content" + const pins = "min-content" + const editorPx = useSelector(Layout.getEditorHeight) + "px" + const editor = `minmax(10vh, min(${editorPx}, 65vh))` + const results = "minmax(0, 1fr)" + const footer = "min-content" + const rows = [title, pins, editor, results, footer] + const style = {gridTemplateRows: rows.join(" ")} + + return ( +
    + {children} +
    + ) +} diff --git a/apps/zui/src/views/session-page/index.module.css b/apps/zui/src/views/session-page/index.module.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/zui/src/views/session-page/index.tsx b/apps/zui/src/views/session-page/index.tsx new file mode 100644 index 0000000000..1edc4295fb --- /dev/null +++ b/apps/zui/src/views/session-page/index.tsx @@ -0,0 +1,18 @@ +import {Editor} from "./editor" +import {Footer} from "./footer" +import {Grid} from "./grid" +import {Pins} from "./pins" +import {Results} from "./results" +import {Toolbar} from "./toolbar" + +export function SessionPage() { + return ( + + + + + +