Skip to content

Commit

Permalink
fix(editor-3001): fix tabs, error state, loading states (#26881)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
EDsCODE and github-actions[bot] authored Dec 13, 2024
1 parent d2b08cc commit 1eeaf0f
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 139 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 16 additions & 2 deletions frontend/src/queries/nodes/DataNode/dataNodeLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ export const dataNodeLogic = kea<dataNodeLogicType>([
if (cache.localResults[stringifiedQuery] && !refresh) {
return cache.localResults[stringifiedQuery]
}

if (!query.query) {
return null
}
}

if (!values.currentTeamId) {
Expand Down Expand Up @@ -337,6 +341,12 @@ export const dataNodeLogic = kea<dataNodeLogicType>([
],
})),
reducers(({ props }) => ({
isRefresh: [
false,
{
loadData: (_, { refresh }) => !!refresh,
},
],
dataLoading: [
false,
{
Expand Down Expand Up @@ -474,8 +484,12 @@ export const dataNodeLogic = kea<dataNodeLogicType>([
(variablesOverride) => !!variablesOverride,
],
isShowingCachedResults: [
() => [(_, props) => props.cachedResults ?? null, (_, props) => props.query],
(cachedResults: AnyResponseType | null, query: DataNode): boolean => {
(s) => [(_, props) => props.cachedResults ?? null, (_, props) => props.query, s.isRefresh],
(cachedResults: AnyResponseType | null, query: DataNode, isRefresh): boolean => {
if (isRefresh) {
return false
}

return (
!!cachedResults ||
(cache.localResults && 'query' in query && JSON.stringify(query.query) in cache.localResults)
Expand Down
188 changes: 119 additions & 69 deletions frontend/src/scenes/data-warehouse/editor/OutputPane.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import 'react-data-grid/lib/styles.css'

import { IconGear } from '@posthog/icons'
import { LemonButton, LemonTabs, Spinner } from '@posthog/lemon-ui'
import { LemonButton, LemonTabs } from '@posthog/lemon-ui'
import clsx from 'clsx'
import { useActions, useValues } from 'kea'
import { AnimationType } from 'lib/animations/animations'
import { Animation } from 'lib/components/Animation/Animation'
import { ExportButton } from 'lib/components/ExportButton/ExportButton'
import { useMemo } from 'react'
import DataGrid from 'react-data-grid'
import { InsightErrorState } from 'scenes/insights/EmptyStates'
import { InsightErrorState, StatelessInsightLoadingState } from 'scenes/insights/EmptyStates'
import { HogQLBoldNumber } from 'scenes/insights/views/BoldNumber/BoldNumber'

import { KeyboardShortcut } from '~/layout/navigation-3000/components/KeyboardShortcut'
import { themeLogic } from '~/layout/navigation-3000/themeLogic'
import { dataNodeLogic } from '~/queries/nodes/DataNode/dataNodeLogic'
import { ElapsedTime } from '~/queries/nodes/DataNode/ElapsedTime'
import { LineGraph } from '~/queries/nodes/DataVisualization/Components/Charts/LineGraph'
import { SideBar } from '~/queries/nodes/DataVisualization/Components/SideBar'
import { Table } from '~/queries/nodes/DataVisualization/Components/Table'
Expand All @@ -39,12 +40,12 @@ export function OutputPane(): JSX.Element {
const { editingView, sourceQuery, exportContext, isValidView, error } = useValues(multitabEditorLogic)
const { saveAsInsight, saveAsView, setSourceQuery, runQuery } = useActions(multitabEditorLogic)
const { isDarkModeOn } = useValues(themeLogic)
const { response, responseLoading, responseError } = useValues(dataNodeLogic)
const { response, responseLoading, responseError, queryId, pollResponse } = useValues(dataNodeLogic)
const { dataWarehouseSavedQueriesLoading } = useValues(dataWarehouseViewsLogic)
const { updateDataWarehouseSavedQuery } = useActions(dataWarehouseViewsLogic)
const { visualizationType, queryCancelled } = useValues(dataVisualizationLogic)

const vizKey = `SQLEditorScene`
const vizKey = useMemo(() => `SQLEditorScene`, [])

const columns = useMemo(() => {
return (
Expand All @@ -69,70 +70,6 @@ export function OutputPane(): JSX.Element {
})
}, [response])

const ErrorState = useMemo((): JSX.Element | null => {
return (
<div className={clsx('flex-1 absolute top-0 left-0 right-0 bottom-0 overflow-scroll')}>
<InsightErrorState
query={sourceQuery}
excludeDetail
title={
queryCancelled
? 'The query was cancelled'
: response && 'error' in response
? (response as any).error
: responseError
}
/>
</div>
)
}, [responseError, sourceQuery, queryCancelled, response])

const Content = (): JSX.Element | null => {
if (activeTab === OutputTab.Results) {
if (responseError) {
return ErrorState
}

return responseLoading ? (
<Spinner className="text-3xl" />
) : !response ? (
<span className="text-muted mt-3">Query results will appear here</span>
) : (
<div className="flex-1 absolute top-0 left-0 right-0 bottom-0">
<DataGrid
className={isDarkModeOn ? 'rdg-dark h-full' : 'rdg-light h-full'}
columns={columns}
rows={rows}
/>
</div>
)
}

if (activeTab === OutputTab.Visualization) {
if (responseError) {
return ErrorState
}

return !response ? (
<span className="text-muted mt-3">Query be results will be visualized here</span>
) : (
<div className="flex-1 absolute top-0 left-0 right-0 bottom-0 px-4 py-1 hide-scrollbar">
<InternalDataTableVisualization
uniqueKey={vizKey}
query={sourceQuery}
setQuery={setSourceQuery}
context={{}}
cachedResults={undefined}
exportContext={exportContext}
onSaveInsight={saveAsInsight}
/>
</div>
)
}

return null
}

return (
<div className="flex flex-col w-full flex-1 bg-bg-3000">
{variablesForInsight.length > 0 && (
Expand Down Expand Up @@ -215,7 +152,26 @@ export function OutputPane(): JSX.Element {
</div>
</div>
<div className="flex flex-1 relative bg-dark justify-center items-center">
<Content />
<Content
activeTab={activeTab}
responseError={responseError}
responseLoading={responseLoading}
response={response}
sourceQuery={sourceQuery}
queryCancelled={queryCancelled}
columns={columns}
rows={rows}
isDarkModeOn={isDarkModeOn}
vizKey={vizKey}
setSourceQuery={setSourceQuery}
exportContext={exportContext}
saveAsInsight={saveAsInsight}
queryId={queryId}
pollResponse={pollResponse}
/>
</div>
<div className="flex justify-end pr-2 border-t">
<ElapsedTime />
</div>
</div>
)
Expand Down Expand Up @@ -303,3 +259,97 @@ function InternalDataTableVisualization(
</div>
)
}

const ErrorState = ({ responseError, sourceQuery, queryCancelled, response }: any): JSX.Element | null => {
return (
<div className={clsx('flex-1 absolute top-0 left-0 right-0 bottom-0 overflow-scroll')}>
<InsightErrorState
query={sourceQuery}
excludeDetail
title={
queryCancelled
? 'The query was cancelled'
: response && 'error' in response
? response.error
: responseError
}
/>
</div>
)
}

const Content = ({
activeTab,
responseError,
responseLoading,
response,
sourceQuery,
queryCancelled,
columns,
rows,
isDarkModeOn,
vizKey,
setSourceQuery,
exportContext,
saveAsInsight,
queryId,
pollResponse,
}: any): JSX.Element | null => {
if (activeTab === OutputTab.Results) {
if (responseError) {
return (
<ErrorState
responseError={responseError}
sourceQuery={sourceQuery}
queryCancelled={queryCancelled}
response={response}
/>
)
}

return responseLoading ? (
<StatelessInsightLoadingState queryId={queryId} pollResponse={pollResponse} />
) : !response ? (
<span className="text-muted mt-3">Query results will appear here</span>
) : (
<div className="flex-1 absolute top-0 left-0 right-0 bottom-0">
<DataGrid
className={isDarkModeOn ? 'rdg-dark h-full' : 'rdg-light h-full'}
columns={columns}
rows={rows}
/>
</div>
)
}

if (activeTab === OutputTab.Visualization) {
if (responseError) {
return (
<ErrorState
responseError={responseError}
sourceQuery={sourceQuery}
queryCancelled={queryCancelled}
response={response}
/>
)
}

return !response ? (
<span className="text-muted mt-3">Query be results will be visualized here</span>
) : (
<div className="flex-1 absolute top-0 left-0 right-0 bottom-0 px-4 py-1 hide-scrollbar">
<InternalDataTableVisualization
uniqueKey={vizKey}
query={sourceQuery}
setQuery={setSourceQuery}
context={{}}
cachedResults={undefined}
exportContext={exportContext}
onSaveInsight={saveAsInsight}
/>
</div>
)
}

return null
}
2 changes: 1 addition & 1 deletion frontend/src/scenes/data-warehouse/editor/QueryTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface QueryTabsProps {

export function QueryTabs({ models, onClear, onClick, onAdd, activeModelUri }: QueryTabsProps): JSX.Element {
return (
<div className="flex flex-row overflow-scroll hide-scrollbar h-10">
<div className="flex flex-row w-full overflow-scroll hide-scrollbar h-10">
{models.map((model: QueryTab) => (
<QueryTabComponent
key={model.uri.path}
Expand Down
28 changes: 13 additions & 15 deletions frontend/src/scenes/data-warehouse/editor/QueryWindow.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Monaco } from '@monaco-editor/react'
import { Spinner } from '@posthog/lemon-ui'
import { BindLogic, useActions, useValues } from 'kea'
import { router } from 'kea-router'
import type { editor as importedEditor } from 'monaco-editor'
Expand Down Expand Up @@ -40,14 +39,16 @@ export function QueryWindow(): JSX.Element {
const { selectTab, deleteTab, createTab, setQueryInput, runQuery, setError, setIsValidView } = useActions(logic)

return (
<div className="flex flex-1 flex-col h-full">
<QueryTabs
models={allTabs}
onClick={selectTab}
onClear={deleteTab}
onAdd={createTab}
activeModelUri={activeModelUri}
/>
<div className="flex flex-1 flex-col h-full overflow-hidden">
<div className="overflow-x-auto">
<QueryTabs
models={allTabs}
onClick={selectTab}
onClear={deleteTab}
onAdd={createTab}
activeModelUri={activeModelUri}
/>
</div>
{editingView && (
<div className="h-7 bg-warning-highlight p-1">
<span> Editing view "{editingView.name}"</span>
Expand Down Expand Up @@ -85,16 +86,13 @@ export function QueryWindow(): JSX.Element {
)
}

function InternalQueryWindow(): JSX.Element {
function InternalQueryWindow(): JSX.Element | null {
const { cacheLoading, sourceQuery, queryInput } = useValues(multitabEditorLogic)
const { setSourceQuery } = useActions(multitabEditorLogic)

// NOTE: hacky way to avoid flicker loading
if (cacheLoading) {
return (
<div className="flex-1 flex justify-center items-center">
<Spinner className="text-3xl" />
</div>
)
return null
}

const dataVisualizationLogicProps: DataVisualizationLogicProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const multitabEditorLogic = kea<multitabEditorLogicType>([
actions({
setQueryInput: (queryInput: string) => ({ queryInput }),
updateState: true,
runQuery: (queryOverride?: string) => ({ queryOverride }),
runQuery: (queryOverride?: string, switchTab?: boolean) => ({ queryOverride, switchTab }),
setActiveQuery: (query: string) => ({ query }),
setTabs: (tabs: QueryTab[]) => ({ tabs }),
addTab: (tab: QueryTab) => ({ tab }),
Expand Down Expand Up @@ -311,7 +311,7 @@ export const multitabEditorLogic = kea<multitabEditorLogicType>([
})
localStorage.setItem(editorModelsStateKey(props.key), JSON.stringify(queries))
},
runQuery: ({ queryOverride }) => {
runQuery: ({ queryOverride, switchTab }) => {
const query = queryOverride || values.queryInput

actions.setSourceQuery({
Expand All @@ -328,7 +328,7 @@ export const multitabEditorLogic = kea<multitabEditorLogicType>([
query,
},
autoLoad: false,
}).actions.loadData(true)
}).actions.loadData(!switchTab)
},
saveAsView: async () => {
LemonDialog.openForm({
Expand Down Expand Up @@ -418,7 +418,7 @@ export const multitabEditorLogic = kea<multitabEditorLogicType>([
const _model = props.monaco.editor.getModel(activeModelUri.uri)
const val = _model?.getValue()
actions.setQueryInput(val ?? '')
actions.runQuery()
actions.runQuery(undefined, true)
}
},
})),
Expand Down
Loading

0 comments on commit 1eeaf0f

Please sign in to comment.