diff --git a/frontend/src/scenes/data-warehouse/editor/editorSidebarLogic.ts b/frontend/src/scenes/data-warehouse/editor/editorSidebarLogic.ts index 8239bd166551d..c7128d138beea 100644 --- a/frontend/src/scenes/data-warehouse/editor/editorSidebarLogic.ts +++ b/frontend/src/scenes/data-warehouse/editor/editorSidebarLogic.ts @@ -2,6 +2,8 @@ import Fuse from 'fuse.js' import { connect, kea, path, selectors } from 'kea' import { router } from 'kea-router' import { subscriptions } from 'kea-subscriptions' +import { FEATURE_FLAGS } from 'lib/constants' +import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { databaseTableListLogic } from 'scenes/data-management/database/databaseTableListLogic' import { sceneLogic } from 'scenes/sceneLogic' import { Scene } from 'scenes/sceneTypes' @@ -14,6 +16,7 @@ import { DatabaseSchemaDataWarehouseTable, DatabaseSchemaTable } from '~/queries import { DataWarehouseSavedQuery, PipelineTab } from '~/types' import { dataWarehouseViewsLogic } from '../saved_queries/dataWarehouseViewsLogic' +import { viewLinkLogic } from '../viewLinkLogic' import { editorSceneLogic } from './editorSceneLogic' import type { editorSidebarLogicType } from './editorSidebarLogicType' import { multitabEditorLogic } from './multitabEditorLogic' @@ -39,6 +42,20 @@ const savedQueriesfuse = new Fuse([], { includeMatches: true, }) +const nonMaterializedViewsfuse = new Fuse([], { + keys: [{ name: 'name', weight: 2 }], + threshold: 0.3, + ignoreLocation: true, + includeMatches: true, +}) + +const materializedViewsfuse = new Fuse([], { + keys: [{ name: 'name', weight: 2 }], + threshold: 0.3, + ignoreLocation: true, + includeMatches: true, +}) + export const editorSidebarLogic = kea([ path(['data-warehouse', 'editor', 'editorSidebarLogic']), connect({ @@ -49,8 +66,17 @@ export const editorSidebarLogic = kea([ ['dataWarehouseSavedQueries', 'dataWarehouseSavedQueryMapById', 'dataWarehouseSavedQueriesLoading'], databaseTableListLogic, ['posthogTables', 'dataWarehouseTables', 'databaseLoading', 'views', 'viewsMapById'], + featureFlagLogic, + ['featureFlags'], + ], + actions: [ + editorSceneLogic, + ['selectSchema'], + dataWarehouseViewsLogic, + ['deleteDataWarehouseSavedQuery', 'runDataWarehouseSavedQuery'], + viewLinkLogic, + ['selectSourceTable', 'toggleJoinTableModal'], ], - actions: [editorSceneLogic, ['selectSchema'], dataWarehouseViewsLogic, ['deleteDataWarehouseSavedQuery']], }), selectors(({ actions }) => ({ contents: [ @@ -60,13 +86,19 @@ export const editorSidebarLogic = kea([ s.relevantPosthogTables, s.relevantDataWarehouseTables, s.databaseLoading, + s.relevantNonMaterializedViews, + s.relevantMaterializedViews, + s.featureFlags, ], ( relevantSavedQueries, dataWarehouseSavedQueriesLoading, relevantPosthogTables, relevantDataWarehouseTables, - databaseLoading + databaseLoading, + relevantNonMaterializedViews, + relevantMaterializedViews, + featureFlags ) => [ { key: 'data-warehouse-sources', @@ -85,6 +117,15 @@ export const editorSidebarLogic = kea([ onClick: () => { actions.selectSchema(table) }, + menuItems: [ + { + label: 'Add join', + onClick: () => { + actions.selectSourceTable(table.name) + actions.toggleJoinTableModal() + }, + }, + ], })), onAdd: () => { router.actions.push(urls.pipeline(PipelineTab.Sources)) @@ -107,13 +148,25 @@ export const editorSidebarLogic = kea([ onClick: () => { actions.selectSchema(table) }, + menuItems: [ + { + label: 'Add join', + onClick: () => { + actions.selectSourceTable(table.name) + actions.toggleJoinTableModal() + }, + }, + ], })), } as SidebarCategory, { key: 'data-warehouse-views', noun: ['view', 'views'], loading: dataWarehouseSavedQueriesLoading, - items: relevantSavedQueries.map(([savedQuery, matches]) => ({ + items: (featureFlags[FEATURE_FLAGS.DATA_MODELING] + ? relevantNonMaterializedViews + : relevantSavedQueries + ).map(([savedQuery, matches]) => ({ key: savedQuery.id, name: savedQuery.name, url: '', @@ -135,6 +188,23 @@ export const editorSidebarLogic = kea([ }).actions.createTab(savedQuery.query.query, savedQuery) }, }, + { + label: 'Add join', + onClick: () => { + actions.selectSourceTable(savedQuery.name) + actions.toggleJoinTableModal() + }, + }, + ...(featureFlags[FEATURE_FLAGS.DATA_MODELING] && !savedQuery.status + ? [ + { + label: 'Materialize', + onClick: () => { + actions.runDataWarehouseSavedQuery(savedQuery.id) + }, + }, + ] + : []), { label: 'Delete', status: 'danger', @@ -145,8 +215,77 @@ export const editorSidebarLogic = kea([ ], })), } as SidebarCategory, + ...(featureFlags[FEATURE_FLAGS.DATA_MODELING] + ? [ + { + key: 'data-warehouse-materialized-views', + noun: ['materialized view', 'materialized views'], + loading: dataWarehouseSavedQueriesLoading, + items: relevantMaterializedViews.map(([materializedView, matches]) => ({ + key: materializedView.id, + name: materializedView.name, + url: '', + searchMatch: matches + ? { + matchingFields: matches.map((match) => match.key), + nameHighlightRanges: matches.find((match) => match.key === 'name')?.indices, + } + : null, + onClick: () => { + actions.selectSchema(materializedView) + }, + menuItems: [ + { + label: 'Edit view definition', + onClick: () => { + multitabEditorLogic({ + key: `hogQLQueryEditor/${router.values.location.pathname}`, + }).actions.createTab(materializedView.query.query, materializedView) + }, + }, + { + label: 'Add join', + onClick: () => { + actions.selectSourceTable(materializedView.name) + actions.toggleJoinTableModal() + }, + }, + ...(featureFlags[FEATURE_FLAGS.DATA_MODELING] && materializedView.status + ? [ + { + label: 'Run', + onClick: () => { + actions.runDataWarehouseSavedQuery(materializedView.id) + }, + }, + ] + : []), + { + label: 'Delete', + status: 'danger', + onClick: () => { + actions.deleteDataWarehouseSavedQuery(materializedView.id) + }, + }, + ], + })), + }, + ] + : []), ], ], + nonMaterializedViews: [ + (s) => [s.dataWarehouseSavedQueries], + (views): DataWarehouseSavedQuery[] => { + return views.filter((view) => !view.status && !view.last_run_at) + }, + ], + materializedViews: [ + (s) => [s.dataWarehouseSavedQueries], + (views): DataWarehouseSavedQuery[] => { + return views.filter((view) => view.status || view.last_run_at) + }, + ], activeListItemKey: [ (s) => [s.activeScene, s.sceneParams], (activeScene, sceneParams): [string, number] | null => { @@ -188,6 +327,28 @@ export const editorSidebarLogic = kea([ return dataWarehouseSavedQueries.map((savedQuery) => [savedQuery, null]) }, ], + relevantNonMaterializedViews: [ + (s) => [s.nonMaterializedViews, navigation3000Logic.selectors.searchTerm], + (nonMaterializedViews, searchTerm): [DataWarehouseSavedQuery, FuseSearchMatch[] | null][] => { + if (searchTerm) { + return nonMaterializedViewsfuse + .search(searchTerm) + .map((result) => [result.item, result.matches as FuseSearchMatch[]]) + } + return nonMaterializedViews.map((view) => [view, null]) + }, + ], + relevantMaterializedViews: [ + (s) => [s.materializedViews, navigation3000Logic.selectors.searchTerm], + (materializedViews, searchTerm): [DataWarehouseSavedQuery, FuseSearchMatch[] | null][] => { + if (searchTerm) { + return materializedViewsfuse + .search(searchTerm) + .map((result) => [result.item, result.matches as FuseSearchMatch[]]) + } + return materializedViews.map((view) => [view, null]) + }, + ], })), subscriptions({ dataWarehouseTables: (dataWarehouseTables) => {