Skip to content

Commit 953b631

Browse files
authored
Feature/review mode (#310)
* Show diffs only in Review Mode * Rename to Review Mode and add reject message * Show Undo Redo only when task not in progress * Fix Undo/Redo in Review Mode * Do not ask for confirmation if no change in sql
1 parent 6d9994c commit 953b631

File tree

5 files changed

+27
-14
lines changed

5 files changed

+27
-14
lines changed

apps/src/metabase/appController.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,15 @@ export class MetabaseController extends AppController<MetabaseAppState> {
161161
return {text: `Using ${Object.keys(template_tags || {}).length} template tags and ${(parameters || []).length} parameters`, code: sql, oldCode: sqlQuery}
162162
}
163163
})
164-
async updateSQLQueryWithParams({ sql, template_tags = {}, parameters = [], parameterValues = [], executeImmediately = true, _type = "markdown", ctes = [] }: { sql: string, template_tags?: object, parameters?: any[], parameterValues?: Array<{id: string, value: string[]}>, executeImmediately?: boolean, _type?: string, ctes: CTE[] }) {
164+
async updateSQLQueryWithParams({ sql, template_tags = {}, parameters = [], parameterValues = [], executeImmediately = true, _type = "markdown", ctes = [], skipConfirmation=false }: { sql: string, template_tags?: object, parameters?: any[], parameterValues?: Array<{id: string, value: string[]}>, executeImmediately?: boolean, _type?: string, ctes: CTE[], skipConfirmation?: boolean }) {
165165
const actionContent: BlankMessageContent = {
166166
type: "BLANK",
167167
};
168168
const state = (await this.app.getState()) as MetabaseAppStateSQLEditor;
169-
const { userApproved, userFeedback } = await RPCs.getUserConfirmation({content: sql, contentTitle: "Approve SQL Query?", oldContent: state.currentCard?.dataset_query?.native?.query || state.sqlQuery || ''});
169+
const oldContent = state.currentCard?.dataset_query?.native?.query || state.sqlQuery || ''
170+
const isContentUnchanged = sql == oldContent
171+
const override = skipConfirmation || isContentUnchanged? false : undefined
172+
const { userApproved, userFeedback } = await RPCs.getUserConfirmation({content: sql, contentTitle: "Approve SQL Query?", oldContent, override});
170173
if (!userApproved) {
171174
actionContent.content = '<UserCancelled>Reason: ' + (userFeedback === '' ? 'No particular reason given' : userFeedback) + '</UserCancelled>';
172175
return actionContent;
@@ -411,7 +414,7 @@ export class MetabaseController extends AppController<MetabaseAppState> {
411414
return {text: `${explanation}${paramValuesInfo}`, code: sql, oldCode: currentQuery, language: "sql", extraArgs: {old: {template_tags: currentTemplateTags, parameters: currentParameters}, new: {template_tags, parameters, parameterValues}}}
412415
}
413416
})
414-
async ExecuteQuery({ sql, _ctes = [], explanation = "", template_tags={}, parameters=[], parameterValues=[] }: { sql: string, _ctes?: CTE[], explanation?: string, template_tags?: object, parameters?: any[], parameterValues?: Array<{id: string, value: string[]}> }) {
417+
async ExecuteQuery({ sql, _ctes = [], explanation = "", template_tags={}, parameters=[], parameterValues=[], skipConfirmation=false }: { sql: string, _ctes?: CTE[], explanation?: string, template_tags?: object, parameters?: any[], parameterValues?: Array<{id: string, value: string[]}>, skipConfirmation?: boolean }) {
415418
// console.log('Template tags are', template_tags)
416419
// console.log('Parameters are', parameters)
417420
// Try parsing template_tags and parameters if they are strings
@@ -440,7 +443,7 @@ export class MetabaseController extends AppController<MetabaseAppState> {
440443
const pageType = metabaseState.useStore().getState().toolContext?.pageType;
441444

442445
if (pageType === 'sql') {
443-
return await this.updateSQLQueryWithParams({ sql, template_tags, parameters, parameterValues, executeImmediately: true, _type: "markdown", ctes: _ctes });
446+
return await this.updateSQLQueryWithParams({ sql, template_tags, parameters, parameterValues, executeImmediately: true, _type: "markdown", ctes: _ctes, skipConfirmation });
444447
}
445448
else if ((pageType === 'dashboard') || (pageType === 'unknown')) {
446449
return await this.runSQLQueryWithParams({ sql, template_tags, parameters, ctes: _ctes });

web/src/app/userConfirmation.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,21 @@ import { getState } from "../state/store"
33
import { sleep } from "../helpers/utils"
44
import { toggleUserConfirmation } from "../state/chat/reducer"
55
import { abortPlan } from '../state/chat/reducer'
6+
import { isUndefined } from "lodash"
67

7-
export async function getUserConfirmation({content, contentTitle, oldContent, override = false}: {content: string, contentTitle: string, oldContent: string | undefined, override?: boolean}) {
8+
export async function getUserConfirmation({content, contentTitle, oldContent, override}: {content: string, contentTitle: string, oldContent: string | undefined, override?: boolean}) {
89
const state = getState()
9-
const isEnabled = state.settings.confirmChanges || override
10+
const isEnabled = isUndefined(override) ? state.settings.confirmChanges : override
1011
if (!isEnabled) return { userApproved: true, userFeedback: '' }
1112
const thread = state.chat.activeThread
1213
dispatch(toggleUserConfirmation({show: true, content: content, contentTitle: contentTitle, oldContent: oldContent}))
1314

1415
while (true){
1516
const state = getState()
1617
const userConfirmation = state.chat.threads[thread].userConfirmation
17-
console.log('Polling user confirmation:', userConfirmation.show, userConfirmation.content, content)
1818
if (userConfirmation.show && userConfirmation.content === content && userConfirmation.userInput != 'NULL'){
1919
const userApproved = userConfirmation.userInput == 'APPROVE'
2020
const userFeedback = userConfirmation.userFeedback || ''
21-
console.log('User approved:', userApproved, 'feedback:', userConfirmation.userFeedback || 'No feedback')
2221
dispatch(toggleUserConfirmation({show: false, content: '', contentTitle: '', oldContent: ''}))
2322
return { userApproved, userFeedback }
2423
}

web/src/components/common/ActionStack.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ export const ActionStack: React.FC<{status: string, actions: Array<ActionStatusV
5959
const url = useAppStore((state) => state.toolContext.url) || '';
6060
const origin = url ? new URL(url).origin : '';
6161
const thread = useSelector((state: RootState) => state.chat.activeThread)
62+
const activeThread = useSelector((state: RootState) => state.chat.threads[thread])
63+
const taskInProgress = !(activeThread.status == 'FINISHED')
6264
const totalThreads = useSelector((state: RootState) => state.chat.threads.length)
6365
const embedConfigs = useSelector((state: RootState) => state.configs.embed);
6466

@@ -105,7 +107,7 @@ export const ActionStack: React.FC<{status: string, actions: Array<ActionStatusV
105107
executeAction({
106108
index: -1,
107109
function: 'ExecuteQuery',
108-
args: {sql: sql, template_tags: extraArgs?.template_tags || {}, parameters: extraArgs?.parameters || []},
110+
args: {sql: sql, template_tags: extraArgs?.template_tags || {}, parameters: extraArgs?.parameters || [], skipConfirmation: true},
109111
});
110112
};
111113

@@ -186,7 +188,7 @@ export const ActionStack: React.FC<{status: string, actions: Array<ActionStatusV
186188
return (
187189
<Box aria-label="thinking-content" borderBottomWidth={1} mb={1} borderBottomColor={'minusxGreen.800'} w={"100%"}>
188190
<Markdown content={text}></Markdown>
189-
{pageType && pageType == 'sql' && undoRedoArr[i]}
191+
{pageType && pageType == 'sql' && !taskInProgress && undoRedoArr[i]}
190192
</Box>
191193
)
192194
})}

web/src/components/common/ChatInputArea.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import {
22
HStack,
33
Stack,
44
Checkbox,
5-
Text
5+
Text,
6+
Badge
67
} from '@chakra-ui/react'
78
import React, { forwardRef, useState, useEffect, useCallback } from 'react'
89
import { useDispatch, useSelector } from 'react-redux'
@@ -108,7 +109,10 @@ const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputAreaProps>(
108109
isChecked={confirmChanges}
109110
onChange={(e) => updateConfirmChanges(e.target.checked)}
110111
>
111-
<Text fontSize="xs">Review SQL Edits</Text>
112+
<HStack spacing={1} align="start">
113+
<Text fontSize="xs">Review Mode</Text>
114+
<Badge size="sm" colorScheme="blue" fontSize="xs">NEW</Badge>
115+
</HStack>
112116
</Checkbox>
113117
)}
114118
</HStack>

web/src/components/common/UserConfirmation.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export const UserConfirmation = () => {
130130
useDarkTheme={true}
131131
leftTitle={<Text fontSize="sm" color="minusxBW.100" textAlign={"center"}>SQL in the Editor</Text>}
132132
rightTitle={<Text fontSize="sm" color="minusxBW.100" textAlign={"center"}>SQL to be executed</Text>}
133-
showDiffOnly={false}
133+
showDiffOnly={true}
134134
/>
135135
</div>
136136

@@ -193,7 +193,12 @@ export const UserConfirmation = () => {
193193
colorScheme="red"
194194
minWidth={"120px"}
195195
>
196-
{showRejectFeedback ? 'Submit' : 'Reject'}
196+
<HStack spacing={1} align="end">
197+
<Text>{showRejectFeedback ? 'Submit' : 'Reject'}</Text>
198+
{!showRejectFeedback && (
199+
<Text fontSize="xs" opacity={0.6}>(with feedback)</Text>
200+
)}
201+
</HStack>
197202
</Button>
198203

199204
{showRejectFeedback && (

0 commit comments

Comments
 (0)