diff --git a/.changeset/hot-cheetahs-design.md b/.changeset/hot-cheetahs-design.md new file mode 100644 index 0000000000..9c786a89a4 --- /dev/null +++ b/.changeset/hot-cheetahs-design.md @@ -0,0 +1,5 @@ +--- +'@finos/legend-query-builder': patch +--- + +Change the query builder results panel loading indicator. diff --git a/.changeset/plenty-bananas-boil.md b/.changeset/plenty-bananas-boil.md new file mode 100644 index 0000000000..df145ad58f --- /dev/null +++ b/.changeset/plenty-bananas-boil.md @@ -0,0 +1,5 @@ +--- +'@finos/legend-art': patch +--- + +Add CubesLoadingIndicator and CubesLoadingIndicatorIcon components. diff --git a/packages/legend-art/src/index.ts b/packages/legend-art/src/index.ts index 457b28db65..cbffad468b 100644 --- a/packages/legend-art/src/index.ts +++ b/packages/legend-art/src/index.ts @@ -20,6 +20,7 @@ export * from './icon/LegendLogo.js'; export * from './icon/SVGIcon.js'; export * from './loader/LoadingIcon.js'; +export * from './loader/CubesLoadingIndicator.js'; export * from './input/Input.js'; diff --git a/packages/legend-art/src/loader/CubesLoadingIndicator.tsx b/packages/legend-art/src/loader/CubesLoadingIndicator.tsx new file mode 100644 index 0000000000..9dbb47568c --- /dev/null +++ b/packages/legend-art/src/loader/CubesLoadingIndicator.tsx @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2020-present, Goldman Sachs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import clsx from 'clsx'; + +export interface CubesLoadingIndicatorProps + extends React.HtmlHTMLAttributes { + isLoading: boolean; +} + +export interface CubesLoadingIndicatorIconProps { + size?: 'sm' | 'md' | 'lg'; +} + +export const CubesLoadingIndicatorIcon: React.FC< + CubesLoadingIndicatorIconProps +> = (props) => { + const { size = 'md' } = props; + return ( +
+ + + + +
+ ); +}; + +export const CubesLoadingIndicator: React.FC = ( + props, +) => { + const { isLoading, children, className, ...rest } = props; + + return ( +
+ {children} +
+ ); +}; diff --git a/packages/legend-art/style/components/_cubes-loading-indicator.scss b/packages/legend-art/style/components/_cubes-loading-indicator.scss new file mode 100644 index 0000000000..81d7f9c7ce --- /dev/null +++ b/packages/legend-art/style/components/_cubes-loading-indicator.scss @@ -0,0 +1,138 @@ +/** + * Copyright (c) 2020-present, Goldman Sachs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@use 'sass:math'; + +$loading-icon-frame-rate: math.div(100, 8); +$loading-icon-full-duration: 1.6s; +$loading-icon-frame-duration: math.div($loading-icon-full-duration, 8); + +$loading-icon-square-state-off: rotateX(90deg); +$loading-icon-square-state-on: rotateX(0deg); + +$flip-step-1: $loading-icon-frame-rate * 0; +$flip-step-2: $loading-icon-frame-rate * 1; +$flip-step-3: $loading-icon-frame-rate * 4; +$flip-step-4: $loading-icon-frame-rate * 5; + +$loading-icon-size-md: 32px; +$loading-icon-size-sm: 16px; +$loading-icon-size-lg: 64px; + +.cubes-loading-indicator { + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 1; + display: none; + justify-content: center; + align-items: center; + + &--loading { + display: flex; + } +} + +.cubes-icon { + position: relative; + + &--md { + height: $loading-icon-size-md; + width: $loading-icon-size-md; + } + + &--sm { + width: $loading-icon-size-sm; + height: $loading-icon-size-sm; + } + + &--lg { + width: $loading-icon-size-lg; + height: $loading-icon-size-lg; + + &__icon { + width: calc(50% - 2px); + height: calc(50% - 2px); + } + } + + &__icon { + width: calc(50% - 1px); + height: calc(50% - 1px); + position: absolute; + background: var(--color-legacylight-light-blue-100); + animation: flip-animation $loading-icon-full-duration infinite; + transform: $loading-icon-square-state-off; + + // Top-left + &:nth-child(1) { + top: 0; + left: 0; + animation-delay: $loading-icon-frame-duration * 0; + } + // Top-Right + &:nth-child(2) { + top: 0; + left: 50%; + animation-delay: $loading-icon-frame-duration * 1; + } + // Bottom-Right + &:nth-child(3) { + top: 50%; + left: 50%; + animation-delay: $loading-icon-frame-duration * 2; + } + // Bottom-Left + &:nth-child(4) { + top: 50%; + left: 0; + animation-delay: $loading-icon-frame-duration * 3; + } + } +} + +// The animation loop is split into 8 frames +// The On/Off state is controlled through the variables + +// Frame 0: 90deg rotation along X axis (not visible) +// Frame 1: 0deg rotation along X axis (fully visible) +// Frame 2: +// Frame 3: +// Frame 4: Continue from 0dev +// Frame 5: rotate to 90deg again (hidden) +// Frame 6: +// Frame 7: + +@keyframes flip-animation { + #{$flip-step-1}% { + transform: $loading-icon-square-state-off; + opacity: 0.5; + } + #{$flip-step-2}% { + transform: $loading-icon-square-state-on; + opacity: 1; + } + #{$flip-step-3}% { + transform: $loading-icon-square-state-on; + opacity: 1; + } + #{$flip-step-4}% { + transform: $loading-icon-square-state-off; + opacity: 0.5; + } +} diff --git a/packages/legend-art/style/index.scss b/packages/legend-art/style/index.scss index 315ed10859..ad381cf19c 100644 --- a/packages/legend-art/style/index.scss +++ b/packages/legend-art/style/index.scss @@ -33,6 +33,7 @@ @forward 'components/selector-input'; @forward 'components/tree-view'; @forward 'components/markdown-viewer'; +@forward 'components/cubes-loading-indicator'; // Reset (override library styles) @forward 'reset/mui'; diff --git a/packages/legend-query-builder/src/components/result/QueryBuilderResultPanel.tsx b/packages/legend-query-builder/src/components/result/QueryBuilderResultPanel.tsx index 5c3397b09d..72912aefc4 100644 --- a/packages/legend-query-builder/src/components/result/QueryBuilderResultPanel.tsx +++ b/packages/legend-query-builder/src/components/result/QueryBuilderResultPanel.tsx @@ -16,7 +16,6 @@ import { BlankPanelContent, - PanelLoadingIndicator, PlayIcon, DropdownMenu, MenuContent, @@ -43,6 +42,8 @@ import { CsvIcon, DebugIcon, ReportIcon, + CubesLoadingIndicatorIcon, + CubesLoadingIndicator, } from '@finos/legend-art'; import { observer } from 'mobx-react-lite'; import { flowResult } from 'mobx'; @@ -334,6 +335,9 @@ export const QueryBuilderResultPanel = observer( )); + const isLoading = + resultState.isRunningQuery || resultState.isGeneratingPlan; + return (
- - - {!executionResult && ( + + + + + {!executionResult && !isLoading && ( Build or load a valid query first )} - {executionResult && ( + {executionResult && !isLoading && (