From 56c8a6f77889d5fbd7b6184617f09e1119029130 Mon Sep 17 00:00:00 2001 From: Anton Kulyk <kuliks.anton@gmail.com> Date: Mon, 20 Feb 2023 19:57:35 +0000 Subject: [PATCH] Update action editor empty form state (#28462) --- .../ActionContext/ActionContext.ts | 2 -- .../ImplicitActionContextProvider.tsx | 1 - .../QueryActionContextProvider.tsx | 10 ------ .../ActionCreator/ActionCreator.tsx | 2 -- .../ActionCreator/ActionCreatorView.tsx | 3 -- .../FormCreator/EmptyFormPlaceholder.tsx | 27 +++++++++------ .../FormCreator/FormCreator.styled.tsx | 33 ++++++++++++++----- .../ActionCreator/FormCreator/FormCreator.tsx | 4 +-- 8 files changed, 43 insertions(+), 39 deletions(-) diff --git a/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/ActionContext.ts b/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/ActionContext.ts index 69cafad621b..972ce77a33b 100644 --- a/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/ActionContext.ts +++ b/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/ActionContext.ts @@ -16,7 +16,6 @@ export type ActionContextType = { ui: ActionCreatorUIProps; handleActionChange: (action: EditableActionParams) => void; handleFormSettingsChange: (formSettings: ActionFormSettings) => void; - handleSetupExample: () => void; renderEditorBody: (props: EditorBodyProps) => React.ReactNode; }; @@ -31,7 +30,6 @@ export const ActionContext = createContext<ActionContextType>({ }, handleActionChange: _.noop, handleFormSettingsChange: _.noop, - handleSetupExample: _.noop, renderEditorBody: () => null, }); diff --git a/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/ImplicitActionContextProvider/ImplicitActionContextProvider.tsx b/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/ImplicitActionContextProvider/ImplicitActionContextProvider.tsx index d69e4379a6f..ddf3c001612 100644 --- a/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/ImplicitActionContextProvider/ImplicitActionContextProvider.tsx +++ b/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/ImplicitActionContextProvider/ImplicitActionContextProvider.tsx @@ -75,7 +75,6 @@ function ImplicitActionContextProvider({ }, handleFormSettingsChange, handleActionChange: _.noop, - handleSetupExample: _.noop, renderEditorBody: EditorBody, }), [initialAction, formSettings, canSave, handleFormSettingsChange], diff --git a/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/QueryActionContextProvider.tsx b/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/QueryActionContextProvider.tsx index 9137788cc21..0128814acfc 100644 --- a/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/QueryActionContextProvider.tsx +++ b/frontend/src/metabase/actions/containers/ActionCreator/ActionContext/QueryActionContextProvider.tsx @@ -25,9 +25,6 @@ export interface QueryActionContextProviderProps databaseId?: DatabaseId; } -const EXAMPLE_QUERY = - "UPDATE products\nSET rating = {{ my_new_value }}\nWHERE id = {{ my_primary_key }}"; - function resolveQuestion( action: WritebackQueryAction | undefined, { metadata, databaseId }: { metadata: Metadata; databaseId?: DatabaseId }, @@ -89,11 +86,6 @@ function QueryActionContextProvider({ [question], ); - const handleSetupExample = useCallback(() => { - const nextQuery = query.setQueryText(query.queryText() + EXAMPLE_QUERY); - setQuestion(question.setQuery(nextQuery)); - }, [question, query]); - const handleQueryChange = useCallback((nextQuery: NativeQuery) => { const nextQuestion = nextQuery.question(); const parameters = getTemplateTagParametersFromCard(nextQuestion.card()); @@ -123,7 +115,6 @@ function QueryActionContextProvider({ }, handleActionChange, handleFormSettingsChange: setFormSettings, - handleSetupExample, renderEditorBody, }), [ @@ -133,7 +124,6 @@ function QueryActionContextProvider({ canSave, handleActionChange, setFormSettings, - handleSetupExample, renderEditorBody, ], ); diff --git a/frontend/src/metabase/actions/containers/ActionCreator/ActionCreator.tsx b/frontend/src/metabase/actions/containers/ActionCreator/ActionCreator.tsx index 29d1758c04d..674c77cf766 100644 --- a/frontend/src/metabase/actions/containers/ActionCreator/ActionCreator.tsx +++ b/frontend/src/metabase/actions/containers/ActionCreator/ActionCreator.tsx @@ -88,7 +88,6 @@ function ActionCreator({ ui: UIProps, handleActionChange, handleFormSettingsChange, - handleSetupExample, renderEditorBody, } = useActionContext(); @@ -147,7 +146,6 @@ function ActionCreator({ onChangeAction={handleActionChange} onChangeFormSettings={handleFormSettingsChange} onClickSave={handleClickSave} - onClickExample={handleSetupExample} onCloseModal={onClose} > {renderEditorBody({ isEditable })} diff --git a/frontend/src/metabase/actions/containers/ActionCreator/ActionCreatorView.tsx b/frontend/src/metabase/actions/containers/ActionCreator/ActionCreatorView.tsx index c87c759782f..01dc9fbe1c7 100644 --- a/frontend/src/metabase/actions/containers/ActionCreator/ActionCreatorView.tsx +++ b/frontend/src/metabase/actions/containers/ActionCreator/ActionCreatorView.tsx @@ -37,7 +37,6 @@ interface ActionCreatorProps extends ActionCreatorUIProps { onChangeAction: (action: Partial<WritebackAction>) => void; onChangeFormSettings: (formSettings: ActionFormSettings) => void; onClickSave: () => void; - onClickExample: () => void; onCloseModal?: () => void; } @@ -55,7 +54,6 @@ export default function ActionCreatorView({ onChangeAction, onChangeFormSettings, onClickSave, - onClickExample, onCloseModal, }: ActionCreatorProps) { const [activeSideView, setActiveSideView] = @@ -124,7 +122,6 @@ export default function ActionCreatorView({ formSettings={formSettings} isEditable={isEditable && canChangeFieldSettings} onChange={onChangeFormSettings} - onExampleClick={onClickExample} /> ) : activeSideView === "dataReference" ? ( <DataReferenceInline onClose={closeSideView} /> diff --git a/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/EmptyFormPlaceholder.tsx b/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/EmptyFormPlaceholder.tsx index f4656b509fe..b408e9a7fa0 100644 --- a/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/EmptyFormPlaceholder.tsx +++ b/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/EmptyFormPlaceholder.tsx @@ -3,31 +3,38 @@ import { t } from "ttag"; import Icon from "metabase/components/Icon"; +import MetabaseSettings from "metabase/lib/settings"; + import { EmptyFormPlaceholderWrapper, + ExplainerTitle, ExplainerText, - ExampleButton, + ExplainerList, + ExplainerLink, IconContainer, TopRightIcon, } from "./FormCreator.styled"; -export const EmptyFormPlaceholder = ({ - onExampleClick, -}: { - onExampleClick: () => void; -}) => ( +export const EmptyFormPlaceholder = () => ( <EmptyFormPlaceholderWrapper> <IconContainer> <Icon name="sql" size={62} /> <TopRightIcon name="insight" size={24} /> </IconContainer> - <h3>{t`Build custom forms and business logic.`}</h3> + <ExplainerTitle>{t`Build custom forms and business logic.`}</ExplainerTitle> <ExplainerText> - {t`Actions let you write parameterized SQL that can then be attached to buttons, clicks, or even added on the page as form elements.`} + {t`Actions let you write parameterized SQL that writes back to your database. Actions can be attached to buttons on dashboards to create custom workflows. You can even publicly share the parameterized forms they generate to collect data.`} </ExplainerText> <ExplainerText> - {t`Use actions to update your data based on user input or values on the page.`} + {t`Here are a few ideas for what you can do with actions`} + <ExplainerList> + <li>{t`Create a customer feedback form and embed it on your website.`}</li> + <li>{t`Mark the customer you’re viewing in a dashboard as a VIP.`}</li> + <li>{t`Let team members remove redundant data.`}</li> + </ExplainerList> </ExplainerText> - <ExampleButton onClick={onExampleClick}>{t`See an example`}</ExampleButton> + <ExplainerLink + href={MetabaseSettings.docsUrl("actions/custom")} + >{t`See an example`}</ExplainerLink> </EmptyFormPlaceholderWrapper> ); diff --git a/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/FormCreator.styled.tsx b/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/FormCreator.styled.tsx index 9826399e9ce..8c31ca9a722 100644 --- a/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/FormCreator.styled.tsx +++ b/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/FormCreator.styled.tsx @@ -1,5 +1,6 @@ import styled from "@emotion/styled"; import Icon from "metabase/components/Icon"; +import ExternalLink from "metabase/core/components/ExternalLink"; import { color, lighten } from "metabase/lib/colors"; import { space } from "metabase/styled-components/theme"; @@ -32,24 +33,39 @@ export const EmptyFormPlaceholderWrapper = styled.div` display: flex; flex-direction: column; justify-content: center; - align-items: center; height: 100%; - text-align: center; padding: 5rem; `; +export const ExplainerTitle = styled.h3` + margin-bottom: ${space(1)}; +`; + export const ExplainerText = styled.p` font-weight: 400; + line-height: 1.5rem; color: ${color("text-medium")}; - margin: ${space(2)} auto; + margin: ${space(1)} 0 0 0; +`; + +export const ExplainerList = styled.ul` + list-style-type: disc; + margin-left: 1.5rem; + + li { + font-weight: 400; + line-height: 24px; + color: ${color("text-medium")}; + margin: 0; + } `; -export const ExampleButton = styled.button` - font-weight: bold; - cursor: pointer; - margin: ${space(2)}; +export const ExplainerLink = styled(ExternalLink)` + font-weight: 700; + margin-top: ${space(2)}; + color: ${color("brand")}; - :hover { + &:hover { color: ${lighten("brand", 0.1)}; } `; @@ -59,6 +75,7 @@ export const IconContainer = styled.div` padding: 1.25rem; position: relative; color: ${color("brand")}; + align-self: center; `; export const TopRightIcon = styled(Icon)` diff --git a/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/FormCreator.tsx b/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/FormCreator.tsx index c7ffd40022e..d60d3f031f9 100644 --- a/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/FormCreator.tsx +++ b/frontend/src/metabase/actions/containers/ActionCreator/FormCreator/FormCreator.tsx @@ -22,13 +22,11 @@ function FormCreator({ isEditable, formSettings: passedFormSettings, onChange, - onExampleClick, }: { params: Parameter[]; isEditable: boolean; formSettings?: ActionFormSettings; onChange: (formSettings: ActionFormSettings) => void; - onExampleClick: () => void; }) { const [formSettings, setFormSettings] = useState<ActionFormSettings>( passedFormSettings?.fields ? passedFormSettings : getDefaultFormSettings(), @@ -54,7 +52,7 @@ function FormCreator({ return ( <SidebarContent title={t`Action parameters`}> <FormContainer> - <EmptyFormPlaceholder onExampleClick={onExampleClick} /> + <EmptyFormPlaceholder /> </FormContainer> </SidebarContent> ); -- GitLab