diff --git a/app/client/cypress/fixtures/Test_csv.csv b/app/client/cypress/fixtures/Test_csv.csv
new file mode 100644
index 0000000000..eb988e2a32
--- /dev/null
+++ b/app/client/cypress/fixtures/Test_csv.csv
@@ -0,0 +1,3 @@
+Data Id,String,Number,Boolean,Empty,Date
+hsa-miR-942-5p,Blue,23.788,TRUE,,"Wednesday, 20 January 1999"
+hsa-miR-943,Black,1000,FALSE,,2022-09-15
\ No newline at end of file
diff --git a/app/client/cypress/fixtures/filePickerTableDSL.json b/app/client/cypress/fixtures/filePickerTableDSL.json
new file mode 100644
index 0000000000..ae7a818879
--- /dev/null
+++ b/app/client/cypress/fixtures/filePickerTableDSL.json
@@ -0,0 +1,310 @@
+{
+ "dsl": {
+ "widgetName": "MainContainer",
+ "backgroundColor": "none",
+ "rightColumn": 1280,
+ "snapColumns": 64,
+ "detachFromLayout": true,
+ "widgetId": "0",
+ "topRow": 0,
+ "bottomRow": 1470,
+ "containerStyle": "none",
+ "snapRows": 125,
+ "parentRowSpace": 1,
+ "type": "CANVAS_WIDGET",
+ "canExtend": true,
+ "version": 61,
+ "minHeight": 1292,
+ "parentColumnSpace": 1,
+ "dynamicTriggerPathList": [],
+ "dynamicBindingPathList": [],
+ "leftColumn": 0,
+ "children": [
+ {
+ "boxShadow": "none",
+ "widgetName": "FilePicker1",
+ "buttonColor": "{{appsmith.theme.colors.primaryColor}}",
+ "displayName": "FilePicker",
+ "iconSVG": "/static/media/icon.7c5ad9c357928c6ff5701bf51a56c2e5.svg",
+ "searchTags": [
+ "upload"
+ ],
+ "topRow": 17,
+ "bottomRow": 21,
+ "parentRowSpace": 10,
+ "allowedFileTypes": [],
+ "type": "FILE_PICKER_WIDGET_V2",
+ "hideCard": false,
+ "animateLoading": true,
+ "parentColumnSpace": 29.125,
+ "dynamicTriggerPathList": [],
+ "leftColumn": 21,
+ "dynamicBindingPathList": [
+ {
+ "key": "buttonColor"
+ },
+ {
+ "key": "borderRadius"
+ }
+ ],
+ "isDisabled": false,
+ "key": "ka3ok4t58q",
+ "isRequired": false,
+ "isDeprecated": false,
+ "rightColumn": 37,
+ "isDefaultClickDisabled": true,
+ "widgetId": "tkvh3nxko7",
+ "isVisible": true,
+ "label": "Select Files",
+ "maxFileSize": 5,
+ "dynamicTyping": true,
+ "version": 1,
+ "fileDataType": "Base64",
+ "parentId": "0",
+ "selectedFiles": [],
+ "renderMode": "CANVAS",
+ "isLoading": false,
+ "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
+ "files": [],
+ "maxNumFiles": 1
+ },
+ {
+ "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}",
+ "isVisibleDownload": true,
+ "iconSVG": "/static/media/icon.db8a9cbd2acd22a31ea91cc37ea2a46c.svg",
+ "topRow": 40,
+ "isSortable": true,
+ "type": "TABLE_WIDGET_V2",
+ "inlineEditingSaveOption": "ROW_LEVEL",
+ "animateLoading": true,
+ "dynamicBindingPathList": [
+ {
+ "key": "primaryColumns.step.computedValue"
+ },
+ {
+ "key": "primaryColumns.task.computedValue"
+ },
+ {
+ "key": "primaryColumns.status.computedValue"
+ },
+ {
+ "key": "primaryColumns.action.computedValue"
+ },
+ {
+ "key": "primaryColumns.action.buttonColor"
+ },
+ {
+ "key": "primaryColumns.action.borderRadius"
+ },
+ {
+ "key": "primaryColumns.action.boxShadow"
+ },
+ {
+ "key": "accentColor"
+ },
+ {
+ "key": "borderRadius"
+ },
+ {
+ "key": "boxShadow"
+ },
+ {
+ "key": "childStylesheet.button.buttonColor"
+ },
+ {
+ "key": "childStylesheet.button.borderRadius"
+ },
+ {
+ "key": "childStylesheet.menuButton.menuColor"
+ },
+ {
+ "key": "childStylesheet.menuButton.borderRadius"
+ },
+ {
+ "key": "childStylesheet.iconButton.buttonColor"
+ },
+ {
+ "key": "childStylesheet.iconButton.borderRadius"
+ },
+ {
+ "key": "childStylesheet.editActions.saveButtonColor"
+ },
+ {
+ "key": "childStylesheet.editActions.saveBorderRadius"
+ },
+ {
+ "key": "childStylesheet.editActions.discardButtonColor"
+ },
+ {
+ "key": "childStylesheet.editActions.discardBorderRadius"
+ },
+ {
+ "key": "tableData"
+ }
+ ],
+ "leftColumn": 34,
+ "delimiter": ",",
+ "defaultSelectedRowIndex": 0,
+ "accentColor": "{{appsmith.theme.colors.primaryColor}}",
+ "isVisibleFilters": true,
+ "isVisible": true,
+ "enableClientSideSearch": true,
+ "version": 1,
+ "totalRecordsCount": 0,
+ "isLoading": false,
+ "childStylesheet": {
+ "button": {
+ "buttonColor": "{{appsmith.theme.colors.primaryColor}}",
+ "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
+ "boxShadow": "none"
+ },
+ "menuButton": {
+ "menuColor": "{{appsmith.theme.colors.primaryColor}}",
+ "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
+ "boxShadow": "none"
+ },
+ "iconButton": {
+ "buttonColor": "{{appsmith.theme.colors.primaryColor}}",
+ "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
+ "boxShadow": "none"
+ },
+ "editActions": {
+ "saveButtonColor": "{{appsmith.theme.colors.primaryColor}}",
+ "saveBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
+ "discardButtonColor": "{{appsmith.theme.colors.primaryColor}}",
+ "discardBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}"
+ }
+ },
+ "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
+ "defaultSelectedRowIndices": [
+ 0
+ ],
+ "widgetName": "Table2",
+ "defaultPageSize": 0,
+ "columnOrder": [
+ "step",
+ "task",
+ "status",
+ "action"
+ ],
+ "dynamicPropertyPathList": [],
+ "displayName": "Table",
+ "bottomRow": 72,
+ "columnWidthMap": {
+ "task": 245,
+ "step": 62,
+ "status": 75
+ },
+ "parentRowSpace": 10,
+ "hideCard": false,
+ "parentColumnSpace": 29.125,
+ "dynamicTriggerPathList": [],
+ "primaryColumns": {
+ "step": {
+ "index": 0,
+ "width": 150,
+ "id": "step",
+ "originalId": "step",
+ "alias": "step",
+ "horizontalAlignment": "LEFT",
+ "verticalAlignment": "CENTER",
+ "columnType": "text",
+ "textSize": "0.875rem",
+ "enableFilter": true,
+ "enableSort": true,
+ "isVisible": true,
+ "isCellVisible": true,
+ "isCellEditable": false,
+ "isDerived": false,
+ "label": "step",
+ "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"step\"]))}}",
+ "validation": {},
+ "labelColor": "#FFFFFF"
+ },
+ "task": {
+ "index": 1,
+ "width": 150,
+ "id": "task",
+ "originalId": "task",
+ "alias": "task",
+ "horizontalAlignment": "LEFT",
+ "verticalAlignment": "CENTER",
+ "columnType": "text",
+ "textSize": "0.875rem",
+ "enableFilter": true,
+ "enableSort": true,
+ "isVisible": true,
+ "isCellVisible": true,
+ "isCellEditable": false,
+ "isDerived": false,
+ "label": "task",
+ "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"task\"]))}}",
+ "validation": {},
+ "labelColor": "#FFFFFF"
+ },
+ "status": {
+ "index": 2,
+ "width": 150,
+ "id": "status",
+ "originalId": "status",
+ "alias": "status",
+ "horizontalAlignment": "LEFT",
+ "verticalAlignment": "CENTER",
+ "columnType": "text",
+ "textSize": "0.875rem",
+ "enableFilter": true,
+ "enableSort": true,
+ "isVisible": true,
+ "isCellVisible": true,
+ "isCellEditable": false,
+ "isDerived": false,
+ "label": "status",
+ "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"status\"]))}}",
+ "validation": {},
+ "labelColor": "#FFFFFF"
+ },
+ "action": {
+ "index": 3,
+ "width": 150,
+ "id": "action",
+ "originalId": "action",
+ "alias": "action",
+ "horizontalAlignment": "LEFT",
+ "verticalAlignment": "CENTER",
+ "columnType": "button",
+ "textSize": "0.875rem",
+ "enableFilter": true,
+ "enableSort": true,
+ "isVisible": true,
+ "isCellVisible": true,
+ "isCellEditable": false,
+ "isDisabled": false,
+ "isDerived": false,
+ "label": "action",
+ "onClick": "{{currentRow.step === '#1' ? showAlert('Done', 'success') : currentRow.step === '#2' ? navigateTo('https://docs.appsmith.com/core-concepts/connecting-to-data-sources/querying-a-database',undefined,'NEW_WINDOW') : navigateTo('https://docs.appsmith.com/core-concepts/displaying-data-read/display-data-tables',undefined,'NEW_WINDOW')}}",
+ "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"action\"]))}}",
+ "validation": {},
+ "labelColor": "#FFFFFF",
+ "buttonColor": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( appsmith.theme.colors.primaryColor))}}",
+ "borderRadius": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( appsmith.theme.borderRadius.appBorderRadius))}}",
+ "boxShadow": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( 'none'))}}"
+ }
+ },
+ "key": "8azewxqczt",
+ "isDeprecated": false,
+ "rightColumn": 64,
+ "textSize": "0.875rem",
+ "widgetId": "yyc9usw44s",
+ "tableData": "{{FilePicker1.files[0].data}}",
+ "label": "Data",
+ "searchKey": "",
+ "parentId": "0",
+ "renderMode": "CANVAS",
+ "horizontalAlignment": "LEFT",
+ "isVisibleSearch": true,
+ "isVisiblePagination": true,
+ "verticalAlignment": "CENTER"
+ }
+ ]
+ }
+}
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/Filepicker/FilePickerV2_CSV_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/Filepicker/FilePickerV2_CSV_spec.js
new file mode 100644
index 0000000000..1f5fec703d
--- /dev/null
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/Filepicker/FilePickerV2_CSV_spec.js
@@ -0,0 +1,51 @@
+const commonlocators = require("../../../../../locators/commonlocators.json");
+const dsl = require("../../../../../fixtures/filePickerTableDSL.json");
+
+const widgetName = "filepickerwidgetv2";
+const ARRAY_CSV_HELPER_TEXT = `All non csv filetypes will have an empty value`;
+
+describe("File picker widget v2", () => {
+ before(() => {
+ cy.addDsl(dsl);
+ });
+
+ it("1. Parse CSV data to table Widget", () => {
+ cy.openPropertyPane(widgetName);
+ cy.get(
+ `.t--property-control-dataformat ${commonlocators.helperText}`,
+ ).should("not.exist");
+ cy.selectDropdownValue(
+ commonlocators.filePickerDataFormat,
+ "Array (CSVs only)",
+ );
+ cy.get(commonlocators.filePickerDataFormat)
+ .last()
+ .should("have.text", "Array (CSVs only)");
+ cy.get(
+ `.t--property-control-dataformat ${commonlocators.helperText}`,
+ ).should("exist");
+ cy.get(
+ `.t--property-control-dataformat ${commonlocators.helperText}`,
+ ).contains(ARRAY_CSV_HELPER_TEXT);
+ cy.get(commonlocators.filePickerInput)
+ .first()
+ .attachFile("Test_csv.csv");
+ cy.wait(3000);
+
+ cy.readTableV2dataPublish("1", "1").then((tabData) => {
+ const tabValue = tabData;
+ expect(tabValue).to.be.equal("Black");
+ cy.log("the value is" + tabValue);
+ });
+ cy.readTableV2dataPublish("1", "2").then((tabData) => {
+ const tabValue = tabData;
+ expect(tabValue).to.be.equal("1000");
+ cy.log("the value is" + tabValue);
+ });
+ cy.readTableV2dataPublish("1", "3").then((tabData) => {
+ const tabValue = tabData;
+ expect(tabValue).to.be.equal("false");
+ cy.log("the value is" + tabValue);
+ });
+ });
+});
diff --git a/app/client/cypress/locators/commonlocators.json b/app/client/cypress/locators/commonlocators.json
index 75437f97ae..f4a89c7910 100644
--- a/app/client/cypress/locators/commonlocators.json
+++ b/app/client/cypress/locators/commonlocators.json
@@ -125,6 +125,8 @@
"dataType": ".t--property-control-datatype .bp3-popover-target",
"recaptchaVersion": ".t--property-control-googlerecaptchaversion .bp3-popover-target",
"textOverflowDropdown": ".t--property-control-overflowtext .bp3-popover-target",
+ "filePickerDataFormat": ".t--property-control-dataformat .bp3-popover-target",
+ "helperText": ".t--property-control-helperText",
"jsonFormFieldType": ".t--property-control-fieldtype .bp3-popover-target",
"jsonFormAddNewCustomFieldBtn": ".t--property-control-fieldconfiguration .t--add-column-btn",
"evaluateMsg": ".t--evaluatedPopup-error",
diff --git a/app/client/package.json b/app/client/package.json
index 798e4762d3..472d517bf3 100644
--- a/app/client/package.json
+++ b/app/client/package.json
@@ -89,6 +89,7 @@
"nanoid": "^2.0.4",
"node-forge": "^1.3.0",
"normalizr": "^3.3.0",
+ "papaparse": "^5.3.2",
"path-to-regexp": "^6.2.0",
"popper.js": "^1.15.0",
"prettier": "^1.18.2",
@@ -215,6 +216,7 @@
"@types/nanoid": "^2.0.0",
"@types/node": "^10.12.18",
"@types/node-forge": "^0.10.0",
+ "@types/papaparse": "^5.3.5",
"@types/prismjs": "^1.16.1",
"@types/react": "^16.8.2",
"@types/react-beautiful-dnd": "^11.0.4",
diff --git a/app/client/src/constants/PropertyControlConstants.tsx b/app/client/src/constants/PropertyControlConstants.tsx
index 9cc3f3c741..8136ebf9a6 100644
--- a/app/client/src/constants/PropertyControlConstants.tsx
+++ b/app/client/src/constants/PropertyControlConstants.tsx
@@ -47,7 +47,10 @@ export type PropertyPaneControlConfig = {
id?: string;
label: string | ((props: WidgetProps, propertyPath: string) => string);
propertyName: string;
+ // Serves in the tooltip
helpText?: string;
+ //Dynamic text serves below the property pane inputs
+ helperText?: ((props: WidgetProps) => string) | string;
isJSConvertible?: boolean;
customJSControl?: string;
controlType: ControlType;
diff --git a/app/client/src/pages/Editor/PropertyPane/PropertyControl.tsx b/app/client/src/pages/Editor/PropertyPane/PropertyControl.tsx
index 20580bb16a..7136cbf292 100644
--- a/app/client/src/pages/Editor/PropertyPane/PropertyControl.tsx
+++ b/app/client/src/pages/Editor/PropertyPane/PropertyControl.tsx
@@ -50,6 +50,7 @@ import { TooltipComponent } from "design-system";
import { ReactComponent as ResetIcon } from "assets/icons/control/undo_2.svg";
import { AppTheme } from "entities/AppTheming";
import { JS_TOGGLE_DISABLED_MESSAGE } from "@appsmith/constants/messages";
+import PropertyPaneHelperText from "./PropertyPaneHelperText";
type Props = PropertyPaneControlConfig & {
panel: IPanelProps;
@@ -418,6 +419,9 @@ const PropertyControl = memo((props: Props) => {
const label = isFunction(props.label)
? props.label(widgetProperties, propertyName)
: props.label;
+ const helperText = isFunction(props.helperText)
+ ? props.helperText(widgetProperties)
+ : props.helperText;
if (widgetProperties) {
// get the dataTreePath and apply enhancement if exists
@@ -618,6 +622,7 @@ const PropertyControl = memo((props: Props) => {
additionAutocomplete,
hideEvaluatedValue(),
)}
+
);
} catch (e) {
diff --git a/app/client/src/pages/Editor/PropertyPane/PropertyPaneHelperText.tsx b/app/client/src/pages/Editor/PropertyPane/PropertyPaneHelperText.tsx
new file mode 100644
index 0000000000..830aa59967
--- /dev/null
+++ b/app/client/src/pages/Editor/PropertyPane/PropertyPaneHelperText.tsx
@@ -0,0 +1,31 @@
+import { Text, TextType } from "design-system";
+import React from "react";
+import { Colors } from "constants/Colors";
+import styled from "styled-components";
+
+type Props = {
+ helperText?: string;
+};
+const StyledHelperText = styled(Text)`
+ font-weight: 400;
+ font-size: 12px;
+ color: ${Colors.GRAY};
+ line-height: 14px;
+`;
+
+const PropertyPaneHelperText = (props: Props) => {
+ if (!props.helperText) {
+ return null;
+ }
+
+ return (
+
+ {props.helperText}
+
+ );
+};
+
+export default PropertyPaneHelperText;
diff --git a/app/client/src/widgets/FilePickerWidgetV2/index.ts b/app/client/src/widgets/FilePickerWidgetV2/index.ts
index 3857342583..5f8c2e1faa 100644
--- a/app/client/src/widgets/FilePickerWidgetV2/index.ts
+++ b/app/client/src/widgets/FilePickerWidgetV2/index.ts
@@ -18,6 +18,7 @@ export const CONFIG = {
maxNumFiles: 1,
maxFileSize: 5,
fileDataType: FileDataTypes.Base64,
+ dynamicTyping: true,
widgetName: "FilePicker",
isDefaultClickDisabled: true,
version: 1,
diff --git a/app/client/src/widgets/FilePickerWidgetV2/widget/index.tsx b/app/client/src/widgets/FilePickerWidgetV2/widget/index.tsx
index a4d47a3425..319917a145 100644
--- a/app/client/src/widgets/FilePickerWidgetV2/widget/index.tsx
+++ b/app/client/src/widgets/FilePickerWidgetV2/widget/index.tsx
@@ -21,6 +21,16 @@ import { createGlobalStyle } from "styled-components";
import UpIcon from "assets/icons/ads/up-arrow.svg";
import CloseIcon from "assets/icons/ads/cross.svg";
import { Colors } from "constants/Colors";
+import Papa from "papaparse";
+
+const CSV_ARRAY_LABEL = "Array (CSVs only)";
+const CSV_FILE_TYPE_REGEX = /.+(\/csv)$/;
+
+const ARRAY_CSV_HELPER_TEXT = `All non csv filetypes will have an empty value. \n Large files used in widgets directly might slow down the app.`;
+
+const isCSVFileType = (str: string) => CSV_FILE_TYPE_REGEX.test(str);
+
+type Result = string | Buffer | ArrayBuffer | null;
const FilePickerGlobalStyles = createGlobalStyle<{
borderRadius?: string;
@@ -317,6 +327,10 @@ class FilePickerWidget extends BaseWidget<
label: FileDataTypes.Text,
value: FileDataTypes.Text,
},
+ {
+ label: CSV_ARRAY_LABEL,
+ value: FileDataTypes.Array,
+ },
],
isBindProperty: false,
isTriggerProperty: false,
@@ -487,6 +501,11 @@ class FilePickerWidget extends BaseWidget<
propertyName: "fileDataType",
label: "Data Format",
controlType: "DROP_DOWN",
+ helperText: (props: FilePickerWidgetProps) => {
+ return props.fileDataType === FileDataTypes.Array
+ ? ARRAY_CSV_HELPER_TEXT
+ : "";
+ },
options: [
{
label: FileDataTypes.Base64,
@@ -500,10 +519,29 @@ class FilePickerWidget extends BaseWidget<
label: FileDataTypes.Text,
value: FileDataTypes.Text,
},
+ {
+ label: CSV_ARRAY_LABEL,
+ value: FileDataTypes.Array,
+ },
],
isBindProperty: false,
isTriggerProperty: false,
},
+ {
+ propertyName: "dynamicTyping",
+ label: "Infer data-types from CSV",
+ helpText:
+ "Controls if the arrays should try to infer the best possible data type based on the values in csv files",
+ controlType: "SWITCH",
+ isJSConvertible: false,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ hidden: (props: FilePickerWidgetProps) => {
+ return props.fileDataType !== FileDataTypes.Array;
+ },
+ dependencies: ["fileDataType"],
+ validation: { type: ValidationTypes.BOOLEAN },
+ },
{
propertyName: "maxNumFiles",
label: "Max No. of files",
@@ -831,7 +869,11 @@ class FilePickerWidget extends BaseWidget<
const newFile = {
type: file.type,
id: file.id,
- data: reader.result,
+ data: this.parseUploadResult(
+ reader.result,
+ file.type,
+ this.props.fileDataType,
+ ),
name: file.meta ? file.meta.name : `File-${index + fileCount}`,
size: file.size,
dataFormat: this.props.fileDataType,
@@ -959,6 +1001,57 @@ class FilePickerWidget extends BaseWidget<
);
}
+ parseUploadResult(
+ result: Result,
+ fileType: string,
+ dataFormat: FileDataTypes,
+ ) {
+ if (
+ dataFormat !== FileDataTypes.Array ||
+ !isCSVFileType(fileType) ||
+ !result
+ ) {
+ return result;
+ }
+
+ const data: Record[] = [];
+ const errors: Papa.ParseError[] = [];
+
+ function chunk(results: Papa.ParseStepResult) {
+ if (results?.errors?.length) {
+ errors.push(...results.errors);
+ }
+ data.push(...results.data);
+ }
+
+ if (typeof result === "string") {
+ const config = {
+ header: true,
+ dynamicTyping: this.props.dynamicTyping,
+ chunk,
+ };
+ try {
+ const startParsing = performance.now();
+
+ Papa.parse(result, config);
+
+ const endParsing = performance.now();
+
+ log.debug(
+ `### FILE_PICKER_WIDGET_V2 - ${this.props.widgetName} - CSV PARSING `,
+ `${endParsing - startParsing} ms`,
+ );
+
+ return data;
+ } catch (error) {
+ log.error(errors);
+ return [];
+ }
+ } else {
+ return [];
+ }
+ }
+
static getWidgetType(): WidgetType {
return "FILE_PICKER_WIDGET_V2";
}
@@ -981,6 +1074,7 @@ interface FilePickerWidgetProps extends WidgetProps {
backgroundColor: string;
borderRadius: string;
boxShadow?: string;
+ dynamicTyping?: boolean;
}
export type FilePickerWidgetV2Props = FilePickerWidgetProps;
diff --git a/app/client/src/widgets/constants.ts b/app/client/src/widgets/constants.ts
index a32422565f..4939c12a86 100644
--- a/app/client/src/widgets/constants.ts
+++ b/app/client/src/widgets/constants.ts
@@ -58,6 +58,7 @@ export enum FileDataTypes {
Base64 = "Base64",
Text = "Text",
Binary = "Binary",
+ Array = "Array",
}
export type AlignWidget = "LEFT" | "RIGHT";
diff --git a/app/client/yarn.lock b/app/client/yarn.lock
index fcb4ced65c..c129bbbcce 100644
--- a/app/client/yarn.lock
+++ b/app/client/yarn.lock
@@ -3155,6 +3155,13 @@
version "2.4.0"
resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz"
+"@types/papaparse@^5.3.5":
+ version "5.3.5"
+ resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-5.3.5.tgz#e5ad94b1fe98e2a8ea0b03284b83d2cb252bbf39"
+ integrity sha512-R1icl/hrJPFRpuYj9PVG03WBAlghJj4JW9Py5QdR8FFSxaLmZRyu7xYDCCBZIJNfUv3MYaeBbhBoX958mUTAaw==
+ dependencies:
+ "@types/node" "*"
+
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz"
@@ -11242,6 +11249,11 @@ pako@~1.0.2:
resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
+papaparse@^5.3.2:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.3.2.tgz#d1abed498a0ee299f103130a6109720404fbd467"
+ integrity sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw==
+
param-case@^3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz"