diff --git a/frontend/src/lib/monaco/CodeEditor.tsx b/frontend/src/lib/monaco/CodeEditor.tsx index 10dabd94c1bb4..3d431e485dcba 100644 --- a/frontend/src/lib/monaco/CodeEditor.tsx +++ b/frontend/src/lib/monaco/CodeEditor.tsx @@ -32,7 +32,8 @@ export interface CodeEditorProps extends Omit sourceQuery?: AnyDataNode globals?: Record schema?: Record | null - onMetadata?: (metadata: HogQLMetadataResponse) => void + onMetadata?: (metadata: HogQLMetadataResponse | null) => void + onMetadataLoading?: (loading: boolean) => void onError?: (error: string | null, isValidView: boolean) => void } let codeEditorIndex = 0 @@ -122,6 +123,7 @@ export function CodeEditor({ schema, onError, onMetadata, + onMetadataLoading, ...editorProps }: CodeEditorProps): JSX.Element { const { isDarkModeOn } = useValues(themeLogic) @@ -142,6 +144,7 @@ export function CodeEditor({ editor: editor, onError, onMetadata, + onMetadataLoading, }) useMountedLogic(builtCodeEditorLogic) diff --git a/frontend/src/lib/monaco/codeEditorLogic.tsx b/frontend/src/lib/monaco/codeEditorLogic.tsx index b02e4d38d780a..9d6a061716459 100644 --- a/frontend/src/lib/monaco/codeEditorLogic.tsx +++ b/frontend/src/lib/monaco/codeEditorLogic.tsx @@ -50,7 +50,8 @@ export interface CodeEditorLogicProps { globals?: Record multitab?: boolean onError?: (error: string | null, isValidView: boolean) => void - onMetadata?: (metadata: HogQLMetadataResponse) => void + onMetadata?: (metadata: HogQLMetadataResponse | null) => void + onMetadataLoading?: (loading: boolean) => void } export const codeEditorLogic = kea([ @@ -78,11 +79,13 @@ export const codeEditorLogic = kea([ reloadMetadata: async (_, breakpoint) => { const model = props.editor?.getModel() if (!model || !props.monaco || !METADATA_LANGUAGES.includes(props.language as HogLanguage)) { + props.onMetadata?.(null) return null } await breakpoint(300) const query = props.query if (query === '') { + props.onMetadata?.(null) return null } @@ -281,6 +284,9 @@ export const codeEditorLogic = kea([ error: (error) => { props.onError?.(error, values.isValidView) }, + metadataLoading: (loading) => { + props.onMetadataLoading?.(loading) + }, })), propsChanged(({ actions, props }, oldProps) => { if ( diff --git a/frontend/src/scenes/data-warehouse/editor/OutputPane.tsx b/frontend/src/scenes/data-warehouse/editor/OutputPane.tsx index b4a665606b55f..f45a36249132f 100644 --- a/frontend/src/scenes/data-warehouse/editor/OutputPane.tsx +++ b/frontend/src/scenes/data-warehouse/editor/OutputPane.tsx @@ -1,7 +1,7 @@ import 'react-data-grid/lib/styles.css' import { IconGear } from '@posthog/icons' -import { LemonButton, LemonTabs } from '@posthog/lemon-ui' +import { LemonButton, LemonTabs, Spinner } from '@posthog/lemon-ui' import clsx from 'clsx' import { BindLogic, useActions, useValues } from 'kea' import { AnimationType } from 'lib/animations/animations' @@ -42,11 +42,12 @@ export function OutputPane(): JSX.Element { const { setActiveTab } = useActions(outputPaneLogic) const { variablesForInsight } = useValues(variablesLogic) - const { editingView, sourceQuery, exportContext, isValidView, error, editorKey } = useValues(multitabEditorLogic) + const { editingView, sourceQuery, exportContext, isValidView, error, editorKey, metadataLoading } = + useValues(multitabEditorLogic) const { saveAsInsight, saveAsView, setSourceQuery, runQuery } = useActions(multitabEditorLogic) const { isDarkModeOn } = useValues(themeLogic) const { response, responseLoading, responseError, queryId, pollResponse } = useValues(dataNodeLogic) - const { dataWarehouseSavedQueriesLoading } = useValues(dataWarehouseViewsLogic) + const { updatingDataWarehouseSavedQuery } = useValues(dataWarehouseViewsLogic) const { updateDataWarehouseSavedQuery } = useActions(dataWarehouseViewsLogic) const { visualizationType, queryCancelled } = useValues(dataVisualizationLogic) const { featureFlags } = useValues(featureFlagLogic) @@ -100,11 +101,19 @@ export function OutputPane(): JSX.Element { ? [ { key: OutputTab.Info, - label: 'Info', + label: ( + + Info {metadataLoading ? : null} + + ), }, { key: OutputTab.Lineage, - label: 'Lineage', + label: ( + + Lineage {metadataLoading ? : null} + + ), }, ] : []), @@ -136,7 +145,7 @@ export function OutputPane(): JSX.Element { {editingView ? ( <> updateDataWarehouseSavedQuery({ diff --git a/frontend/src/scenes/data-warehouse/editor/OutputPaneTabs/lineageTabLogic.ts b/frontend/src/scenes/data-warehouse/editor/OutputPaneTabs/lineageTabLogic.ts index 2089d22c4513a..54f15273d4091 100644 --- a/frontend/src/scenes/data-warehouse/editor/OutputPaneTabs/lineageTabLogic.ts +++ b/frontend/src/scenes/data-warehouse/editor/OutputPaneTabs/lineageTabLogic.ts @@ -145,7 +145,7 @@ export const lineageTabLogic = kea([ events(({ cache, actions }) => ({ afterMount: () => { if (!cache.pollingInterval) { - cache.pollingInterval = setInterval(actions.loadDataWarehouseSavedQueries, 5000) + cache.pollingInterval = setInterval(actions.loadDataWarehouseSavedQueries, 10000) } }, beforeUnmount: () => { diff --git a/frontend/src/scenes/data-warehouse/editor/QueryWindow.tsx b/frontend/src/scenes/data-warehouse/editor/QueryWindow.tsx index 7bfbe9310d7e8..f6cd183b5b536 100644 --- a/frontend/src/scenes/data-warehouse/editor/QueryWindow.tsx +++ b/frontend/src/scenes/data-warehouse/editor/QueryWindow.tsx @@ -36,8 +36,17 @@ export function QueryWindow(): JSX.Element { }) const { allTabs, activeModelUri, queryInput, editingView, sourceQuery } = useValues(logic) - const { selectTab, deleteTab, createTab, setQueryInput, runQuery, setError, setIsValidView, setMetadata } = - useActions(logic) + const { + selectTab, + deleteTab, + createTab, + setQueryInput, + runQuery, + setError, + setIsValidView, + setMetadata, + setMetadataLoading, + } = useActions(logic) return (
@@ -83,6 +92,9 @@ export function QueryWindow(): JSX.Element { onMetadata: (metadata) => { setMetadata(metadata) }, + onMetadataLoading: (loading) => { + setMetadataLoading(loading) + }, }} /> diff --git a/frontend/src/scenes/data-warehouse/editor/editorSidebarLogic.tsx b/frontend/src/scenes/data-warehouse/editor/editorSidebarLogic.tsx index c45ea5559fb5a..375750061b4a3 100644 --- a/frontend/src/scenes/data-warehouse/editor/editorSidebarLogic.tsx +++ b/frontend/src/scenes/data-warehouse/editor/editorSidebarLogic.tsx @@ -49,7 +49,7 @@ export const editorSidebarLogic = kea([ sceneLogic, ['activeScene', 'sceneParams'], dataWarehouseViewsLogic, - ['dataWarehouseSavedQueries', 'dataWarehouseSavedQueryMapById', 'dataWarehouseSavedQueriesLoading'], + ['dataWarehouseSavedQueries', 'dataWarehouseSavedQueryMapById', 'initialDataWarehouseSavedQueryLoading'], databaseTableListLogic, ['posthogTables', 'dataWarehouseTables', 'databaseLoading', 'views', 'viewsMapById'], ], @@ -66,14 +66,14 @@ export const editorSidebarLogic = kea([ contents: [ (s) => [ s.relevantSavedQueries, - s.dataWarehouseSavedQueriesLoading, + s.initialDataWarehouseSavedQueryLoading, s.relevantPosthogTables, s.relevantDataWarehouseTables, s.databaseLoading, ], ( relevantSavedQueries, - dataWarehouseSavedQueriesLoading, + initialDataWarehouseSavedQueryLoading, relevantPosthogTables, relevantDataWarehouseTables, databaseLoading @@ -140,7 +140,7 @@ export const editorSidebarLogic = kea([ { key: 'data-warehouse-views', noun: ['view', 'views'], - loading: dataWarehouseSavedQueriesLoading, + loading: initialDataWarehouseSavedQueryLoading, items: relevantSavedQueries.map(([savedQuery, matches]) => ({ key: savedQuery.id, name: savedQuery.name, diff --git a/frontend/src/scenes/data-warehouse/editor/multitabEditorLogic.tsx b/frontend/src/scenes/data-warehouse/editor/multitabEditorLogic.tsx index 7f713327b5197..abe19c1c56428 100644 --- a/frontend/src/scenes/data-warehouse/editor/multitabEditorLogic.tsx +++ b/frontend/src/scenes/data-warehouse/editor/multitabEditorLogic.tsx @@ -78,7 +78,8 @@ export const multitabEditorLogic = kea([ setError: (error: string | null) => ({ error }), setIsValidView: (isValidView: boolean) => ({ isValidView }), setSourceQuery: (sourceQuery: DataVisualizationNode) => ({ sourceQuery }), - setMetadata: (metadata: HogQLMetadataResponse) => ({ metadata }), + setMetadata: (metadata: HogQLMetadataResponse | null) => ({ metadata }), + setMetadataLoading: (loading: boolean) => ({ loading }), editView: (query: string, view: DataWarehouseSavedQuery) => ({ query, view }), }), propsChanged(({ actions, props }, oldProps) => { @@ -155,6 +156,12 @@ export const multitabEditorLogic = kea([ setIsValidView: (_, { isValidView }) => isValidView, }, ], + metadataLoading: [ + true, + { + setMetadataLoading: (_, { loading }) => loading, + }, + ], metadata: [ null as HogQLMetadataResponse | null, { diff --git a/frontend/src/scenes/data-warehouse/saved_queries/dataWarehouseViewsLogic.tsx b/frontend/src/scenes/data-warehouse/saved_queries/dataWarehouseViewsLogic.tsx index 9a08ba084246f..e1167b61fa52e 100644 --- a/frontend/src/scenes/data-warehouse/saved_queries/dataWarehouseViewsLogic.tsx +++ b/frontend/src/scenes/data-warehouse/saved_queries/dataWarehouseViewsLogic.tsx @@ -1,5 +1,5 @@ import { lemonToast } from '@posthog/lemon-ui' -import { actions, connect, events, kea, listeners, path, selectors } from 'kea' +import { actions, connect, events, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import api from 'lib/api' import { databaseTableListLogic } from 'scenes/data-management/database/databaseTableListLogic' @@ -16,6 +16,23 @@ export const dataWarehouseViewsLogic = kea([ values: [userLogic, ['user'], databaseTableListLogic, ['views', 'databaseLoading']], actions: [databaseTableListLogic, ['loadDatabase']], })), + reducers({ + initialDataWarehouseSavedQueryLoading: [ + true, + { + loadDataWarehouseSavedQueriesSuccess: () => false, + loadDataWarehouseSavedQueriesFailure: () => false, + }, + ], + updatingDataWarehouseSavedQuery: [ + false, + { + updateDataWarehouseSavedQuery: () => true, + updateDataWarehouseSavedQuerySuccess: () => false, + updateDataWarehouseSavedQueryFailure: () => false, + }, + ], + }), actions({ runDataWarehouseSavedQuery: (viewId: string) => ({ viewId }), }), @@ -60,6 +77,10 @@ export const dataWarehouseViewsLogic = kea([ }, updateDataWarehouseSavedQuerySuccess: () => { actions.loadDatabase() + lemonToast.success('View updated') + }, + updateDataWarehouseSavedQueryError: () => { + lemonToast.error('Failed to update view') }, runDataWarehouseSavedQuery: async ({ viewId }) => { try {