Skip to content
Snippets Groups Projects
Unverified Commit 01e1d722 authored by Anton Kulyk's avatar Anton Kulyk Committed by GitHub
Browse files

Writeback FE bug fix (#24222)

* Remove outdated safe-guard

* Don't use `category` type for action parameters

* Remove useless `filter`

* Fix UUID usage in dashboard filters

* Support user-filled params for HTTP actions
parent a57ec7bd
Branches
Tags embedding-sdk-0.1.2
No related merge requests found
......@@ -596,25 +596,21 @@ function ActionOptions({ dashcard, clickBehavior, updateSettings }) {
);
return (
<>
{actions
.filter(
action => action.type === "query" || action.type === "http",
)
.map(action => (
<ActionOption
key={action.id}
name={action.card?.name || action.name}
description={action.card?.description || action.description}
isSelected={clickBehavior.action === action.id}
onClick={() =>
updateSettings({
type: clickBehavior.type,
action: action.id,
emitter_id: clickBehavior.emitter_id,
})
}
/>
))}
{actions.map(action => (
<ActionOption
key={action.id}
name={action.card?.name || action.name}
description={action.card?.description || action.description}
isSelected={clickBehavior.action === action.id}
onClick={() =>
updateSettings({
type: clickBehavior.type,
action: action.id,
emitter_id: clickBehavior.emitter_id,
})
}
/>
))}
{selectedAction && (
<ClickMappings
object={
......
......@@ -185,7 +185,7 @@ function baseTypeFilterForParameterType(parameterType) {
const [typePrefix] = parameterType.split("/");
const allowedTypes = {
date: [TYPE.Temporal],
id: [TYPE.Integer],
id: [TYPE.Integer, TYPE.UUID],
category: [TYPE.Text, TYPE.Integer],
location: [TYPE.Text],
}[typePrefix];
......
......@@ -17,7 +17,10 @@ import {
} from "metabase/lib/click-behavior";
import { renderLinkURLForClick } from "metabase/lib/formatting/link";
import * as Urls from "metabase/lib/urls";
import { getTemplateTagType } from "metabase/parameters/utils/cards";
import {
getActionTemplateTagType,
getActionParameterType,
} from "metabase/writeback/utils";
export default ({ question, clicked }) => {
const settings = (clicked && clicked.settings) || {};
......@@ -210,8 +213,8 @@ function getActionParameters(
parameters[id] = {
value,
type: isQueryAction
? getTemplateTagType(targetTemplateTag)
: targetTemplateTag.type,
? getActionTemplateTagType(targetTemplateTag)
: getActionParameterType(targetTemplateTag),
};
});
......@@ -219,6 +222,12 @@ function getActionParameters(
}
function getNotProvidedActionParameters(action, parameters) {
return action.type === "query"
? getNotProvidedQueryActionParameters(action, parameters)
: getNotProvidedHTTPActionParameters(action, parameters);
}
function getNotProvidedQueryActionParameters(action, parameters) {
const mappedParameterIDs = Object.keys(parameters);
const emptyParameterIDs = [];
......@@ -229,10 +238,7 @@ function getNotProvidedActionParameters(action, parameters) {
}
});
const tagsMap =
action.type === "query"
? action.card.dataset_query.native["template-tags"]
: action.template.parameters;
const tagsMap = action.card.dataset_query.native["template-tags"];
const templateTags = Object.values(tagsMap);
return templateTags.filter(tag => {
......@@ -245,6 +251,25 @@ function getNotProvidedActionParameters(action, parameters) {
});
}
function getNotProvidedHTTPActionParameters(action, parameters) {
const mappedParameterIDs = Object.keys(parameters);
const emptyParameterIDs = [];
mappedParameterIDs.forEach(parameterId => {
const { value } = parameters[parameterId];
if (value === undefined) {
emptyParameterIDs.push(parameterId);
}
});
const allParameters = Object.values(action.parameters);
return allParameters.filter(parameter => {
const isNotMapped = !mappedParameterIDs.includes(parameter.id);
const isMappedButNoValue = emptyParameterIDs.includes(parameter.id);
return isNotMapped || isMappedButNoValue;
});
}
function getParameterIdValuePairs(
parameterMapping,
{ data, extraData, clickBehavior },
......
......@@ -2,19 +2,31 @@ import React, { useCallback, useMemo } from "react";
import { connect } from "react-redux";
import { t } from "ttag";
import { getActionTemplateTagType } from "metabase/writeback/utils";
import {
getActionTemplateTagType,
getActionParameterType,
} from "metabase/writeback/utils";
import Form from "metabase/containers/Form";
import { TemplateTag } from "metabase-types/types/Query";
import { Parameter, ParameterId } from "metabase-types/types/Parameter";
type MappedParameters = Record<string, { type: string; value: string }>;
type MappedParameters = Record<
string,
{ type: string; value: string | number }
>;
interface Props {
missingParameters: TemplateTag[];
missingParameters: TemplateTag[] | Parameter[];
onSubmit: (parameters: MappedParameters) => { type: string; payload: any };
onSubmitSuccess: () => void;
dispatch: (action: any) => void;
}
function isTemplateTag(
tagOrParameter: TemplateTag | Parameter,
): tagOrParameter is TemplateTag {
return "display-name" in tagOrParameter;
}
function getTemplateTagFieldProps(tag: TemplateTag) {
if (tag.type === "date") {
......@@ -26,37 +38,99 @@ function getTemplateTagFieldProps(tag: TemplateTag) {
return { type: "input" };
}
function getParameterFieldProps(parameter: Parameter) {
if (parameter.type === "date/single") {
return { type: "date" };
}
if (parameter.type === "number/=") {
return { type: "integer" };
}
return { type: "input" };
}
function getFormFieldForTemplateTag(tag: TemplateTag) {
return {
name: tag.id,
title: tag["display-name"],
...getTemplateTagFieldProps(tag),
};
}
function getFormFieldForParameter(parameter: Parameter) {
return {
name: parameter.id,
title: parameter.name,
...getParameterFieldProps(parameter),
};
}
function formatTemplateTagsBeforeSubmit(
values: Record<ParameterId, string | number>,
missingParameters: TemplateTag[],
) {
const formattedParams: MappedParameters = {};
Object.keys(values).forEach(parameterId => {
const tag = missingParameters.find(tag => tag.id === parameterId);
if (tag) {
formattedParams[parameterId] = {
value: values[parameterId],
type: getActionTemplateTagType(tag),
};
}
});
return formattedParams;
}
function formatParametersBeforeSubmit(
values: Record<ParameterId, string | number>,
missingParameters: Parameter[],
) {
const formattedParams: MappedParameters = {};
Object.keys(values).forEach(parameterId => {
const parameter = missingParameters.find(tag => tag.id === parameterId);
if (parameter) {
formattedParams[parameterId] = {
value: values[parameterId],
type: getActionParameterType(parameter),
};
}
});
return formattedParams;
}
function ActionParametersInputForm({
missingParameters,
dispatch,
onSubmit,
onSubmitSuccess,
}: Props) {
const form = useMemo(
() => ({
fields: missingParameters.map(tag => ({
name: tag.id,
title: tag["display-name"],
...getTemplateTagFieldProps(tag),
})),
}),
[missingParameters],
);
const form = useMemo(() => {
return {
fields: missingParameters.map(tagOrParameter => {
const isTag = isTemplateTag(tagOrParameter);
return isTag
? getFormFieldForTemplateTag(tagOrParameter)
: getFormFieldForParameter(tagOrParameter);
}),
};
}, [missingParameters]);
const handleSubmit = useCallback(
params => {
const formattedParams: MappedParameters = {};
Object.keys(params).forEach(paramId => {
const tag = missingParameters.find(tag => tag.id === paramId);
if (tag) {
formattedParams[paramId] = {
value: params[paramId],
type: getActionTemplateTagType(tag),
};
}
});
const [sampleParameter] = missingParameters;
const formattedParams = isTemplateTag(sampleParameter)
? formatTemplateTagsBeforeSubmit(
params,
missingParameters as TemplateTag[],
)
: formatParametersBeforeSubmit(
params,
missingParameters as Parameter[],
);
dispatch(onSubmit(formattedParams));
onSubmitSuccess();
},
......
......@@ -11,7 +11,11 @@ import Field from "metabase-lib/lib/metadata/Field";
import { Database as IDatabase } from "metabase-types/types/Database";
import { TemplateTag } from "metabase-types/types/Query";
import { DashCard } from "metabase-types/types/Dashboard";
import { ParameterId, ParameterTarget } from "metabase-types/types/Parameter";
import {
Parameter,
ParameterId,
ParameterTarget,
} from "metabase-types/types/Parameter";
import { WritebackAction, HttpAction, RowAction } from "./types";
import { ParameterWithTarget } from "metabase/parameters/types";
......@@ -97,15 +101,21 @@ export function getActionTemplateTagType(tag: TemplateTag) {
} else if (type === "number") {
return "number/=";
} else {
return "category";
return "string/=";
}
}
export const getQueryActionParameterMappings = (action: WritebackAction) => {
if (action.type === "http") {
return {};
export function getActionParameterType(parameter: Parameter) {
const { type } = parameter;
if (type === "category") {
return "string/=";
}
return type;
}
export const getQueryActionParameterMappings = (
action: WritebackAction & RowAction,
) => {
const templateTags = Object.values(
action.card.dataset_query.native["template-tags"],
);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment