Add function to download part of the Data tree as a file (#458)
This commit is contained in:
parent
8722e246e0
commit
f7ec5209cf
|
|
@ -49,6 +49,7 @@
|
|||
"codemirror": "^5.55.0",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
"craco-alias": "^2.1.1",
|
||||
"downloadjs": "^1.4.7",
|
||||
"eslint": "^6.4.0",
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"flow-bin": "^0.91.0",
|
||||
|
|
@ -158,6 +159,7 @@
|
|||
"@storybook/preset-create-react-app": "^3.1.4",
|
||||
"@storybook/react": "^5.3.19",
|
||||
"@types/codemirror": "^0.0.96",
|
||||
"@types/downloadjs": "^1.4.2",
|
||||
"@types/jest": "^24.0.22",
|
||||
"@types/react-beautiful-dnd": "^11.0.4",
|
||||
"@types/react-select": "^3.0.5",
|
||||
|
|
|
|||
|
|
@ -32,6 +32,17 @@ const ALERT_STYLE_OPTIONS = [
|
|||
{ label: "Error", value: "'error'", id: "error" },
|
||||
{ label: "Warning", value: "'warning'", id: "warning" },
|
||||
];
|
||||
|
||||
const FILE_TYPE_OPTIONS = [
|
||||
{ label: "Plain text", value: "'text/plain'", id: "text/plain" },
|
||||
{ label: "HTML", value: "'text/html'", id: "text/html" },
|
||||
{ label: "CSV", value: "'text/csv'", id: "text/csv" },
|
||||
{ label: "JSON", value: "'application/json'", id: "application/json" },
|
||||
{ label: "JPEG", value: "'image/jpeg'", id: "image/jpeg" },
|
||||
{ label: "PNG", value: "'image/png'", id: "image/png" },
|
||||
{ label: "SVG", value: "'image/svg+xml'", id: "image/svg+xml" },
|
||||
];
|
||||
|
||||
const ACTION_TRIGGER_REGEX = /^{{([\s\S]*?)\(([\s\S]*?)\)}}$/g;
|
||||
//Old Regex:: /\(\) => ([\s\S]*?)(\([\s\S]*?\))/g;
|
||||
const ACTION_ANONYMOUS_FUNC_REGEX = /\(\) => (({[\s\S]*?})|([\s\S]*?)(\([\s\S]*?\)))/g;
|
||||
|
|
@ -162,6 +173,73 @@ const storeValueTextGetter = (value: string) => {
|
|||
return "";
|
||||
};
|
||||
|
||||
const downloadDataSetter = (changeValue: any, currentValue: string): string => {
|
||||
const matches = [...currentValue.matchAll(ACTION_TRIGGER_REGEX)];
|
||||
const args = matches[0][2].split(",");
|
||||
args[0] = `'${changeValue}'`;
|
||||
const result = currentValue.replace(
|
||||
ACTION_TRIGGER_REGEX,
|
||||
`{{$1(${args.join(",")})}}`,
|
||||
);
|
||||
return result;
|
||||
};
|
||||
|
||||
const downloadDataGetter = (value: string) => {
|
||||
const matches = [...value.matchAll(ACTION_TRIGGER_REGEX)];
|
||||
if (matches.length) {
|
||||
const funcArgs = matches[0][2];
|
||||
const arg = funcArgs.split(",")[0];
|
||||
return arg.substring(1, arg.length - 1);
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const downloadFileNameSetter = (
|
||||
changeValue: any,
|
||||
currentValue: string,
|
||||
): string => {
|
||||
const matches = [...currentValue.matchAll(ACTION_TRIGGER_REGEX)];
|
||||
const args = matches[0][2].split(",");
|
||||
args[1] = `'${changeValue}'`;
|
||||
return currentValue.replace(
|
||||
ACTION_TRIGGER_REGEX,
|
||||
`{{$1(${args.join(",")})}}`,
|
||||
);
|
||||
};
|
||||
|
||||
const downloadFileNameGetter = (value: string) => {
|
||||
const matches = [...value.matchAll(ACTION_TRIGGER_REGEX)];
|
||||
if (matches.length) {
|
||||
const funcArgs = matches[0][2];
|
||||
const arg = funcArgs.split(",")[1];
|
||||
return arg ? arg.substring(1, arg.length - 1) : "";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const downloadFileTypeSetter = (
|
||||
changeValue: any,
|
||||
currentValue: string,
|
||||
): string => {
|
||||
const matches = [...currentValue.matchAll(ACTION_TRIGGER_REGEX)];
|
||||
const args = matches[0][2].split(",");
|
||||
args[2] = changeValue as string;
|
||||
return currentValue.replace(
|
||||
ACTION_TRIGGER_REGEX,
|
||||
`{{$1(${args.join(",")})}}`,
|
||||
);
|
||||
};
|
||||
|
||||
const downloadFileTypeGetter = (value: string) => {
|
||||
const matches = [...value.matchAll(ACTION_TRIGGER_REGEX)];
|
||||
if (matches.length) {
|
||||
const funcArgs = matches[0][2];
|
||||
const arg = funcArgs.split(",")[2];
|
||||
return arg ? arg.trim() : "";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
type ActionCreatorProps = {
|
||||
value: string;
|
||||
isValid: boolean;
|
||||
|
|
@ -178,6 +256,7 @@ const ActionType = {
|
|||
navigateTo: "navigateTo",
|
||||
showAlert: "showAlert",
|
||||
storeValue: "storeValue",
|
||||
download: "download",
|
||||
};
|
||||
type ActionType = typeof ActionType[keyof typeof ActionType];
|
||||
|
||||
|
|
@ -282,6 +361,9 @@ const FieldType = {
|
|||
ALERT_TYPE_SELECTOR_FIELD: "ALERT_TYPE_SELECTOR_FIELD",
|
||||
KEY_TEXT_FIELD: "KEY_TEXT_FIELD",
|
||||
VALUE_TEXT_FIELD: "VALUE_TEXT_FIELD",
|
||||
DOWNLOAD_DATA_FIELD: "DOWNLOAD_DATA_FIELD",
|
||||
DOWNLOAD_FILE_NAME_FIELD: "DOWNLOAD_FILE_NAME_FIELD",
|
||||
DOWNLOAD_FILE_TYPE_FIELD: "DOWNLOAD_FILE_TYPE_FIELD",
|
||||
};
|
||||
type FieldType = typeof FieldType[keyof typeof FieldType];
|
||||
|
||||
|
|
@ -404,6 +486,22 @@ const fieldConfigs: FieldConfigs = {
|
|||
setter: storeValueTextSetter,
|
||||
view: ViewTypes.TEXT_VIEW,
|
||||
},
|
||||
[FieldType.DOWNLOAD_DATA_FIELD]: {
|
||||
getter: downloadDataGetter,
|
||||
setter: downloadDataSetter,
|
||||
view: ViewTypes.TEXT_VIEW,
|
||||
},
|
||||
[FieldType.DOWNLOAD_FILE_NAME_FIELD]: {
|
||||
getter: downloadFileNameGetter,
|
||||
setter: downloadFileNameSetter,
|
||||
view: ViewTypes.TEXT_VIEW,
|
||||
},
|
||||
[FieldType.DOWNLOAD_FILE_TYPE_FIELD]: {
|
||||
getter: downloadFileTypeGetter,
|
||||
setter: (option: any, currentValue: string) =>
|
||||
downloadFileTypeSetter(option.value, currentValue),
|
||||
view: ViewTypes.SELECTOR_VIEW,
|
||||
},
|
||||
};
|
||||
|
||||
const baseOptions: any = [
|
||||
|
|
@ -440,6 +538,10 @@ const baseOptions: any = [
|
|||
label: "Store Value",
|
||||
value: ActionType.storeValue,
|
||||
},
|
||||
{
|
||||
label: "Download",
|
||||
value: ActionType.download,
|
||||
},
|
||||
];
|
||||
function getOptionsWithChildren(
|
||||
options: TreeDropdownOption[],
|
||||
|
|
@ -567,6 +669,19 @@ function getFieldFromValue(
|
|||
},
|
||||
);
|
||||
}
|
||||
if (value.indexOf("download") !== -1) {
|
||||
fields.push(
|
||||
{
|
||||
field: FieldType.DOWNLOAD_DATA_FIELD,
|
||||
},
|
||||
{
|
||||
field: FieldType.DOWNLOAD_FILE_NAME_FIELD,
|
||||
},
|
||||
{
|
||||
field: FieldType.DOWNLOAD_FILE_TYPE_FIELD,
|
||||
},
|
||||
);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
|
@ -606,6 +721,7 @@ function renderField(props: {
|
|||
case FieldType.CLOSE_MODAL_FIELD:
|
||||
case FieldType.PAGE_SELECTOR_FIELD:
|
||||
case FieldType.ALERT_TYPE_SELECTOR_FIELD:
|
||||
case FieldType.DOWNLOAD_FILE_TYPE_FIELD:
|
||||
let label = "";
|
||||
let defaultText = "Select Action";
|
||||
let options = props.apiOptionTree;
|
||||
|
|
@ -655,10 +771,15 @@ function renderField(props: {
|
|||
defaultText = "Select Page";
|
||||
}
|
||||
if (fieldType === FieldType.ALERT_TYPE_SELECTOR_FIELD) {
|
||||
label = "type";
|
||||
label = "Type";
|
||||
options = ALERT_STYLE_OPTIONS;
|
||||
defaultText = "Select type";
|
||||
}
|
||||
if (fieldType === FieldType.DOWNLOAD_FILE_TYPE_FIELD) {
|
||||
label = "Type";
|
||||
options = FILE_TYPE_OPTIONS;
|
||||
defaultText = "Select file type (optional)";
|
||||
}
|
||||
viewElement = (view as (props: SelectorViewProps) => JSX.Element)({
|
||||
options: options,
|
||||
label: label,
|
||||
|
|
@ -695,6 +816,8 @@ function renderField(props: {
|
|||
case FieldType.URL_FIELD:
|
||||
case FieldType.KEY_TEXT_FIELD:
|
||||
case FieldType.VALUE_TEXT_FIELD:
|
||||
case FieldType.DOWNLOAD_DATA_FIELD:
|
||||
case FieldType.DOWNLOAD_FILE_NAME_FIELD:
|
||||
let fieldLabel = "";
|
||||
if (fieldType === FieldType.ALERT_TEXT_FIELD) {
|
||||
fieldLabel = "Message";
|
||||
|
|
@ -704,6 +827,10 @@ function renderField(props: {
|
|||
fieldLabel = "Key";
|
||||
} else if (fieldType === FieldType.VALUE_TEXT_FIELD) {
|
||||
fieldLabel = "Value";
|
||||
} else if (fieldType === FieldType.DOWNLOAD_DATA_FIELD) {
|
||||
fieldLabel = "Data to download";
|
||||
} else if (fieldType === FieldType.DOWNLOAD_FILE_NAME_FIELD) {
|
||||
fieldLabel = "File name with extension";
|
||||
}
|
||||
viewElement = (view as (props: TextViewProps) => JSX.Element)({
|
||||
label: fieldLabel,
|
||||
|
|
|
|||
|
|
@ -197,6 +197,14 @@ export class DataTreeFactory {
|
|||
};
|
||||
};
|
||||
actionPaths.push("storeValue");
|
||||
|
||||
dataTree.download = function(data: string, name: string, type: string) {
|
||||
return {
|
||||
type: "DOWNLOAD",
|
||||
payload: { data, name, type },
|
||||
};
|
||||
};
|
||||
actionPaths.push("download");
|
||||
}
|
||||
|
||||
dataTree.pageList = pageList;
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ import {
|
|||
all,
|
||||
call,
|
||||
put,
|
||||
race,
|
||||
select,
|
||||
take,
|
||||
takeEvery,
|
||||
takeLatest,
|
||||
race,
|
||||
} from "redux-saga/effects";
|
||||
import {
|
||||
evaluateDataTreeWithFunctions,
|
||||
|
|
@ -75,6 +75,8 @@ import { PLUGIN_TYPE_API } from "constants/ApiEditorConstants";
|
|||
import { DEFAULT_EXECUTE_ACTION_TIMEOUT_MS } from "constants/ApiConstants";
|
||||
import { updateAppStore } from "actions/pageActions";
|
||||
import { getAppStoreName } from "constants/AppConstants";
|
||||
import downloadjs from "downloadjs";
|
||||
import { getType, Types } from "utils/TypeHelpers";
|
||||
|
||||
function* navigateActionSaga(
|
||||
action: { pageNameOrUrl: string; params: Record<string, string> },
|
||||
|
|
@ -134,6 +136,36 @@ function* storeValueLocally(
|
|||
}
|
||||
}
|
||||
|
||||
function* downloadSaga(
|
||||
action: { data: any; name: string; type: string },
|
||||
event: ExecuteActionPayloadEvent,
|
||||
) {
|
||||
try {
|
||||
const { data, name, type } = action;
|
||||
if (!name) {
|
||||
AppToaster.show({
|
||||
message: "Download failed. File name was not provided",
|
||||
type: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const dataType = getType(data);
|
||||
if (dataType === Types.ARRAY || dataType === Types.OBJECT) {
|
||||
const jsonString = JSON.stringify(data, null, 2);
|
||||
downloadjs(jsonString, name, type);
|
||||
} else {
|
||||
downloadjs(data, name, type);
|
||||
}
|
||||
if (event.callback) event.callback({ success: true });
|
||||
} catch (err) {
|
||||
AppToaster.show({
|
||||
message: `Download failed. ${err}`,
|
||||
type: "error",
|
||||
});
|
||||
if (event.callback) event.callback({ success: false });
|
||||
}
|
||||
}
|
||||
|
||||
export const getActionTimeout = (
|
||||
state: AppState,
|
||||
actionId: string,
|
||||
|
|
@ -383,6 +415,9 @@ function* executeActionTriggers(
|
|||
case "STORE_VALUE":
|
||||
yield call(storeValueLocally, trigger.payload, event);
|
||||
break;
|
||||
case "DOWNLOAD":
|
||||
yield call(downloadSaga, trigger.payload, event);
|
||||
break;
|
||||
default:
|
||||
yield put(
|
||||
executeActionError({
|
||||
|
|
|
|||
|
|
@ -237,4 +237,8 @@ export const GLOBAL_FUNCTIONS = {
|
|||
"!doc": "Store key value data locally",
|
||||
"!type": "fn(key: string, value: any) -> void",
|
||||
},
|
||||
download: {
|
||||
"!doc": "Download anything as a file",
|
||||
"!type": "fn(data: any, fileName: string, fileType?: string) -> void",
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3590,6 +3590,11 @@
|
|||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.1.tgz#506d5781b9bcab81bd9a878b198aec7dee2a6033"
|
||||
|
||||
"@types/downloadjs@^1.4.2":
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/downloadjs/-/downloadjs-1.4.2.tgz#6734e60840cd8df3f0f8937c80e67efe7de6f886"
|
||||
integrity sha512-9UWO+nrRhwyKcFe45SFc98sWI8RGwpVwtZiZzi0W/dWdrp1SiUWFNANLlAXZb5QCMFDbeRiAQEhRn5btLd4a4w==
|
||||
|
||||
"@types/eslint-visitor-keys@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
||||
|
|
@ -7332,6 +7337,11 @@ dotenv@^6.2.0:
|
|||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064"
|
||||
integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==
|
||||
|
||||
downloadjs@^1.4.7:
|
||||
version "1.4.7"
|
||||
resolved "https://registry.yarnpkg.com/downloadjs/-/downloadjs-1.4.7.tgz#f69f96f940e0d0553dac291139865a3cd0101e3c"
|
||||
integrity sha1-9p+W+UDg0FU9rCkROYZaPNAQHjw=
|
||||
|
||||
duplexer@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user