From c353044ae3432127db86fa6047d25d3f7f432e02 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Fri, 29 Apr 2022 16:38:42 +0200 Subject: [PATCH 1/2] feat: implemented recent queries --- .../Settings/Logs/LogsNavigation.tsx | 1 + .../Settings/Logs/RecentQueriesItem.tsx | 40 +++++++++++ .../project/[ref]/logs-explorer/index.tsx | 3 + .../project/[ref]/logs-explorer/recent.tsx | 71 +++++++++++++++++++ studio/stores/content/ProjectContentStore.ts | 33 ++++++++- studio/types/userContent.ts | 4 +- 6 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 studio/components/interfaces/Settings/Logs/RecentQueriesItem.tsx create mode 100644 studio/pages/project/[ref]/logs-explorer/recent.tsx diff --git a/studio/components/interfaces/Settings/Logs/LogsNavigation.tsx b/studio/components/interfaces/Settings/Logs/LogsNavigation.tsx index 6885ea51601..dce0ee1553d 100644 --- a/studio/components/interfaces/Settings/Logs/LogsNavigation.tsx +++ b/studio/components/interfaces/Settings/Logs/LogsNavigation.tsx @@ -17,6 +17,7 @@ const LogsNavigation = () => { const tabs = [ { id: 'query', label: 'Query' }, logsSavedQueries ? { id: 'saved', label: 'Saved' } : null, + { id: 'recent', label: 'Recent' }, { id: 'templates', label: 'Templates' }, ].filter(Boolean) as TabItem[] diff --git a/studio/components/interfaces/Settings/Logs/RecentQueriesItem.tsx b/studio/components/interfaces/Settings/Logs/RecentQueriesItem.tsx new file mode 100644 index 00000000000..571613d84dd --- /dev/null +++ b/studio/components/interfaces/Settings/Logs/RecentQueriesItem.tsx @@ -0,0 +1,40 @@ +import { Button, IconPlay } from '@supabase/ui' +import Table from 'components/to-be-cleaned/Table' +import { useRouter } from 'next/router' +import { LogSqlSnippets } from 'types' + +interface Props { + item: LogSqlSnippets.Content +} + +const RecentQueriesItem: React.FC = ({ item }) => { + const router = useRouter() + const { ref } = router.query + + return ( + + +
+
{item.sql}
+
+
+ + + +
+ ) +} + +export default RecentQueriesItem diff --git a/studio/pages/project/[ref]/logs-explorer/index.tsx b/studio/pages/project/[ref]/logs-explorer/index.tsx index cb8978d5f24..62cad014df0 100644 --- a/studio/pages/project/[ref]/logs-explorer/index.tsx +++ b/studio/pages/project/[ref]/logs-explorer/index.tsx @@ -85,6 +85,9 @@ export const LogsExplorerPage: NextPage = () => { pathname: router.pathname, query: { ...router.query, q: query }, }) + content.addRecentLogSqlSnippet({ + sql: query + }) } const handleClear = () => { diff --git a/studio/pages/project/[ref]/logs-explorer/recent.tsx b/studio/pages/project/[ref]/logs-explorer/recent.tsx new file mode 100644 index 00000000000..ae16b4630dc --- /dev/null +++ b/studio/pages/project/[ref]/logs-explorer/recent.tsx @@ -0,0 +1,71 @@ +import React, { useEffect } from 'react' +import { NextPage } from 'next' +import Link from 'next/link' +import { observer } from 'mobx-react-lite' +import { Button, IconClock, IconSave, Loading } from '@supabase/ui' +import { useStore, withAuth } from 'hooks' +import RecentQueriesItem from 'components/interfaces/Settings/Logs/RecentQueriesItem' +import LogsExplorerLayout from 'components/layouts/LogsExplorerLayout/LogsExplorerLayout' + +import Table from 'components/to-be-cleaned/Table' +import { useRouter } from 'next/router' +import { LogSqlSnippets } from 'types' + +export const LogsSavedPage: NextPage = () => { + const { content, ui } = useStore() + const router = useRouter() + const { ref } = router.query + + useEffect(()=>{ + content.loadPersistentData() + }, [ui.selectedProjectRef]) + const recent = content.recentLogSqlSnippets.slice().reverse() + + return ( + +
+ {recent.length > 0 && ( + <> +
+ +
+ + Snippets + + + } + body={ + <> + {recent.map((item: LogSqlSnippets.Content) => )} + + } + /> + + )} + + {recent.length === 0 && ( + <> +
+ +

No Recent Queries Yet

+

+ Your recent queries run from the{' '} + + Query + {' '} + tab will show here. +

+
+ + )} + + ) +} + +export default withAuth(observer(LogsSavedPage)) diff --git a/studio/stores/content/ProjectContentStore.ts b/studio/stores/content/ProjectContentStore.ts index 78c4ea3f40f..57f824ddfa6 100644 --- a/studio/stores/content/ProjectContentStore.ts +++ b/studio/stores/content/ProjectContentStore.ts @@ -2,7 +2,7 @@ import { makeAutoObservable } from 'mobx' import { keyBy } from 'lodash' import { get, post, patch, delete_ } from 'lib/common/fetch' -import { UserContent, UserContentMap } from 'types' +import { LogSqlSnippets, UserContent, UserContentMap } from 'types' import { IRootStore } from '../RootStore' import { API_URL } from 'lib/constants' @@ -15,13 +15,17 @@ export interface IProjectContentStore { isInitialized: boolean isLoaded: boolean error: any + recentLogSqlSnippets: LogSqlSnippets.Content[] load: () => void + loadPersistentData: () => Promise create: (x: UserContent) => { data: UserContent; error: { error: { message: string } } } list: (filter?: any) => any[] reports: (filter?: any) => any[] sqlSnippets: (filter?: any) => any[] logSqlSnippets: (filter?: CustomFilter) => UserContent[] + addRecentLogSqlSnippet: (snippet: Partial) => void + clearRecentLogSqlSnippets: () => void } export default class ProjectContentStore implements IProjectContentStore { @@ -35,15 +39,22 @@ export default class ProjectContentStore implements IProjectContentStore { } baseUrl: string + localStorageKey: string + recentLogSqlKey: string data: UserContentMap = {} + recentLogSqlSnippets: LogSqlSnippets.Content[] = [] state = this.STATES.INITIAL error = null + constructor(rootStore: IRootStore, options: { projectRef: string }) { const { projectRef } = options this.rootStore = rootStore this.baseUrl = `${API_URL}/projects/${projectRef}/content` + this.localStorageKey = `project-content-${projectRef}` + this.recentLogSqlKey = `${this.localStorageKey}-recent-log-sql` + this.loadPersistentData() makeAutoObservable(this) } @@ -86,12 +97,19 @@ export default class ProjectContentStore implements IProjectContentStore { } } - async loadPersistentData() {} + async loadPersistentData() { + this.loadRecentLogSqlSnippets() + } async loadRemotePersistentData(userId: any) { const sqlSnippets = this.sqlSnippets((x: any) => x.owner_id === userId) } + loadRecentLogSqlSnippets() { + if (typeof window === 'undefined') return; + this.recentLogSqlSnippets = JSON.parse((window as any).localStorage.getItem(this.recentLogSqlKey) || "[]") + } + list(filter?: any) { const arr = Object.values(this.data) if (!!filter) { @@ -134,6 +152,17 @@ export default class ProjectContentStore implements IProjectContentStore { return arr_filtered } } + public addRecentLogSqlSnippet(snippet: Partial) { + if (typeof window === 'undefined') return; + const defaults : LogSqlSnippets.Content= {schema_version: "1", favorite: false, sql: "", content_id: ""} + this.recentLogSqlSnippets.push({...defaults, ...snippet}); + (window as any).localStorage.setItem(this.recentLogSqlKey, JSON.stringify(this.recentLogSqlSnippets)) + } + public clearRecentLogSqlSnippets() { + if (typeof window === 'undefined') return; + this.recentLogSqlSnippets = []; + (window as any).localStorage.setItem(this.recentLogSqlKey, JSON.stringify([])) + } logSqlSnippets(filter?: CustomFilter) { let arr = (Object.values(this.data)[0] as any || []) as UserContent[] diff --git a/studio/types/userContent.ts b/studio/types/userContent.ts index 1219ea809b3..f7e9e755d7e 100644 --- a/studio/types/userContent.ts +++ b/studio/types/userContent.ts @@ -1,10 +1,10 @@ -export interface UserContent { +export interface UserContent { id?: string name: string description?: string type: 'sql' | 'report' | 'log_sql' visibility: 'user' | 'project' | 'org' | 'public' - content: Dashboards.Content | SqlSnippets.Content | LogSqlSnippets.Content + content: T owner_id?: number // user id last_updated_by?: number // user id inserted_at?: string // '2021-08-26T08:24:52.040695+00:00' From 0914077a2166b2f4c88ad97c53e2c9b4a020da34 Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Tue, 3 May 2022 17:37:53 +0800 Subject: [PATCH 2/2] fix: feature flag the feature --- studio/components/interfaces/Settings/Logs/LogsNavigation.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/studio/components/interfaces/Settings/Logs/LogsNavigation.tsx b/studio/components/interfaces/Settings/Logs/LogsNavigation.tsx index dce0ee1553d..ebea8863af9 100644 --- a/studio/components/interfaces/Settings/Logs/LogsNavigation.tsx +++ b/studio/components/interfaces/Settings/Logs/LogsNavigation.tsx @@ -13,11 +13,12 @@ const LogsNavigation = () => { const indexRoute = 'query' const logsSavedQueries = useFlag('logsSavedQueries') + const logsRecentQueries = useFlag('logsRecentQueries') const tabs = [ { id: 'query', label: 'Query' }, logsSavedQueries ? { id: 'saved', label: 'Saved' } : null, - { id: 'recent', label: 'Recent' }, + logsRecentQueries ? { id: 'recent', label: 'Recent' } : null, { id: 'templates', label: 'Templates' }, ].filter(Boolean) as TabItem[]