feat: parse CSV data using File Picker Widget (#16689)
* feat: user Papaparser for Parsing csv * feat: enable dynamic typing * Update cypress.env.json * Revert "Update cypress.env.json" This reverts commit 5ca9f43c8ad90c164b4ac68a9b3764eb9c4bd480. * fix: reorder property pane * feat: add helper text for property pane inputs (#16782) * feat: improve helperText * feat: add test for csv parsing in filePicker * fix: proper types * fix: add more test for helperText * fix: type error * fix: props issues * fix: change file name * fix: helper text * fix: test
This commit is contained in:
parent
2088c7e117
commit
42003b97b9
3
app/client/cypress/fixtures/Test_csv.csv
Normal file
3
app/client/cypress/fixtures/Test_csv.csv
Normal file
|
|
@ -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
|
||||||
|
310
app/client/cypress/fixtures/filePickerTableDSL.json
Normal file
310
app/client/cypress/fixtures/filePickerTableDSL.json
Normal file
|
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -125,6 +125,8 @@
|
||||||
"dataType": ".t--property-control-datatype .bp3-popover-target",
|
"dataType": ".t--property-control-datatype .bp3-popover-target",
|
||||||
"recaptchaVersion": ".t--property-control-googlerecaptchaversion .bp3-popover-target",
|
"recaptchaVersion": ".t--property-control-googlerecaptchaversion .bp3-popover-target",
|
||||||
"textOverflowDropdown": ".t--property-control-overflowtext .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",
|
"jsonFormFieldType": ".t--property-control-fieldtype .bp3-popover-target",
|
||||||
"jsonFormAddNewCustomFieldBtn": ".t--property-control-fieldconfiguration .t--add-column-btn",
|
"jsonFormAddNewCustomFieldBtn": ".t--property-control-fieldconfiguration .t--add-column-btn",
|
||||||
"evaluateMsg": ".t--evaluatedPopup-error",
|
"evaluateMsg": ".t--evaluatedPopup-error",
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@
|
||||||
"nanoid": "^2.0.4",
|
"nanoid": "^2.0.4",
|
||||||
"node-forge": "^1.3.0",
|
"node-forge": "^1.3.0",
|
||||||
"normalizr": "^3.3.0",
|
"normalizr": "^3.3.0",
|
||||||
|
"papaparse": "^5.3.2",
|
||||||
"path-to-regexp": "^6.2.0",
|
"path-to-regexp": "^6.2.0",
|
||||||
"popper.js": "^1.15.0",
|
"popper.js": "^1.15.0",
|
||||||
"prettier": "^1.18.2",
|
"prettier": "^1.18.2",
|
||||||
|
|
@ -215,6 +216,7 @@
|
||||||
"@types/nanoid": "^2.0.0",
|
"@types/nanoid": "^2.0.0",
|
||||||
"@types/node": "^10.12.18",
|
"@types/node": "^10.12.18",
|
||||||
"@types/node-forge": "^0.10.0",
|
"@types/node-forge": "^0.10.0",
|
||||||
|
"@types/papaparse": "^5.3.5",
|
||||||
"@types/prismjs": "^1.16.1",
|
"@types/prismjs": "^1.16.1",
|
||||||
"@types/react": "^16.8.2",
|
"@types/react": "^16.8.2",
|
||||||
"@types/react-beautiful-dnd": "^11.0.4",
|
"@types/react-beautiful-dnd": "^11.0.4",
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,10 @@ export type PropertyPaneControlConfig = {
|
||||||
id?: string;
|
id?: string;
|
||||||
label: string | ((props: WidgetProps, propertyPath: string) => string);
|
label: string | ((props: WidgetProps, propertyPath: string) => string);
|
||||||
propertyName: string;
|
propertyName: string;
|
||||||
|
// Serves in the tooltip
|
||||||
helpText?: string;
|
helpText?: string;
|
||||||
|
//Dynamic text serves below the property pane inputs
|
||||||
|
helperText?: ((props: WidgetProps) => string) | string;
|
||||||
isJSConvertible?: boolean;
|
isJSConvertible?: boolean;
|
||||||
customJSControl?: string;
|
customJSControl?: string;
|
||||||
controlType: ControlType;
|
controlType: ControlType;
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ import { TooltipComponent } from "design-system";
|
||||||
import { ReactComponent as ResetIcon } from "assets/icons/control/undo_2.svg";
|
import { ReactComponent as ResetIcon } from "assets/icons/control/undo_2.svg";
|
||||||
import { AppTheme } from "entities/AppTheming";
|
import { AppTheme } from "entities/AppTheming";
|
||||||
import { JS_TOGGLE_DISABLED_MESSAGE } from "@appsmith/constants/messages";
|
import { JS_TOGGLE_DISABLED_MESSAGE } from "@appsmith/constants/messages";
|
||||||
|
import PropertyPaneHelperText from "./PropertyPaneHelperText";
|
||||||
|
|
||||||
type Props = PropertyPaneControlConfig & {
|
type Props = PropertyPaneControlConfig & {
|
||||||
panel: IPanelProps;
|
panel: IPanelProps;
|
||||||
|
|
@ -418,6 +419,9 @@ const PropertyControl = memo((props: Props) => {
|
||||||
const label = isFunction(props.label)
|
const label = isFunction(props.label)
|
||||||
? props.label(widgetProperties, propertyName)
|
? props.label(widgetProperties, propertyName)
|
||||||
: props.label;
|
: props.label;
|
||||||
|
const helperText = isFunction(props.helperText)
|
||||||
|
? props.helperText(widgetProperties)
|
||||||
|
: props.helperText;
|
||||||
|
|
||||||
if (widgetProperties) {
|
if (widgetProperties) {
|
||||||
// get the dataTreePath and apply enhancement if exists
|
// get the dataTreePath and apply enhancement if exists
|
||||||
|
|
@ -618,6 +622,7 @@ const PropertyControl = memo((props: Props) => {
|
||||||
additionAutocomplete,
|
additionAutocomplete,
|
||||||
hideEvaluatedValue(),
|
hideEvaluatedValue(),
|
||||||
)}
|
)}
|
||||||
|
<PropertyPaneHelperText helperText={helperText} />
|
||||||
</ControlWrapper>
|
</ControlWrapper>
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
<StyledHelperText
|
||||||
|
className="t--property-control-helperText"
|
||||||
|
type={TextType.P1}
|
||||||
|
>
|
||||||
|
{props.helperText}
|
||||||
|
</StyledHelperText>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PropertyPaneHelperText;
|
||||||
|
|
@ -18,6 +18,7 @@ export const CONFIG = {
|
||||||
maxNumFiles: 1,
|
maxNumFiles: 1,
|
||||||
maxFileSize: 5,
|
maxFileSize: 5,
|
||||||
fileDataType: FileDataTypes.Base64,
|
fileDataType: FileDataTypes.Base64,
|
||||||
|
dynamicTyping: true,
|
||||||
widgetName: "FilePicker",
|
widgetName: "FilePicker",
|
||||||
isDefaultClickDisabled: true,
|
isDefaultClickDisabled: true,
|
||||||
version: 1,
|
version: 1,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,16 @@ import { createGlobalStyle } from "styled-components";
|
||||||
import UpIcon from "assets/icons/ads/up-arrow.svg";
|
import UpIcon from "assets/icons/ads/up-arrow.svg";
|
||||||
import CloseIcon from "assets/icons/ads/cross.svg";
|
import CloseIcon from "assets/icons/ads/cross.svg";
|
||||||
import { Colors } from "constants/Colors";
|
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<{
|
const FilePickerGlobalStyles = createGlobalStyle<{
|
||||||
borderRadius?: string;
|
borderRadius?: string;
|
||||||
|
|
@ -317,6 +327,10 @@ class FilePickerWidget extends BaseWidget<
|
||||||
label: FileDataTypes.Text,
|
label: FileDataTypes.Text,
|
||||||
value: FileDataTypes.Text,
|
value: FileDataTypes.Text,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: CSV_ARRAY_LABEL,
|
||||||
|
value: FileDataTypes.Array,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
isBindProperty: false,
|
isBindProperty: false,
|
||||||
isTriggerProperty: false,
|
isTriggerProperty: false,
|
||||||
|
|
@ -487,6 +501,11 @@ class FilePickerWidget extends BaseWidget<
|
||||||
propertyName: "fileDataType",
|
propertyName: "fileDataType",
|
||||||
label: "Data Format",
|
label: "Data Format",
|
||||||
controlType: "DROP_DOWN",
|
controlType: "DROP_DOWN",
|
||||||
|
helperText: (props: FilePickerWidgetProps) => {
|
||||||
|
return props.fileDataType === FileDataTypes.Array
|
||||||
|
? ARRAY_CSV_HELPER_TEXT
|
||||||
|
: "";
|
||||||
|
},
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
label: FileDataTypes.Base64,
|
label: FileDataTypes.Base64,
|
||||||
|
|
@ -500,10 +519,29 @@ class FilePickerWidget extends BaseWidget<
|
||||||
label: FileDataTypes.Text,
|
label: FileDataTypes.Text,
|
||||||
value: FileDataTypes.Text,
|
value: FileDataTypes.Text,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: CSV_ARRAY_LABEL,
|
||||||
|
value: FileDataTypes.Array,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
isBindProperty: false,
|
isBindProperty: false,
|
||||||
isTriggerProperty: 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",
|
propertyName: "maxNumFiles",
|
||||||
label: "Max No. of files",
|
label: "Max No. of files",
|
||||||
|
|
@ -831,7 +869,11 @@ class FilePickerWidget extends BaseWidget<
|
||||||
const newFile = {
|
const newFile = {
|
||||||
type: file.type,
|
type: file.type,
|
||||||
id: file.id,
|
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}`,
|
name: file.meta ? file.meta.name : `File-${index + fileCount}`,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
dataFormat: this.props.fileDataType,
|
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<string, string>[] = [];
|
||||||
|
const errors: Papa.ParseError[] = [];
|
||||||
|
|
||||||
|
function chunk(results: Papa.ParseStepResult<any>) {
|
||||||
|
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 {
|
static getWidgetType(): WidgetType {
|
||||||
return "FILE_PICKER_WIDGET_V2";
|
return "FILE_PICKER_WIDGET_V2";
|
||||||
}
|
}
|
||||||
|
|
@ -981,6 +1074,7 @@ interface FilePickerWidgetProps extends WidgetProps {
|
||||||
backgroundColor: string;
|
backgroundColor: string;
|
||||||
borderRadius: string;
|
borderRadius: string;
|
||||||
boxShadow?: string;
|
boxShadow?: string;
|
||||||
|
dynamicTyping?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FilePickerWidgetV2Props = FilePickerWidgetProps;
|
export type FilePickerWidgetV2Props = FilePickerWidgetProps;
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ export enum FileDataTypes {
|
||||||
Base64 = "Base64",
|
Base64 = "Base64",
|
||||||
Text = "Text",
|
Text = "Text",
|
||||||
Binary = "Binary",
|
Binary = "Binary",
|
||||||
|
Array = "Array",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AlignWidget = "LEFT" | "RIGHT";
|
export type AlignWidget = "LEFT" | "RIGHT";
|
||||||
|
|
|
||||||
|
|
@ -3155,6 +3155,13 @@
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz"
|
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":
|
"@types/parse-json@^4.0.0":
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz"
|
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"
|
resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz"
|
||||||
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
|
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:
|
param-case@^3.0.4:
|
||||||
version "3.0.4"
|
version "3.0.4"
|
||||||
resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz"
|
resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user