Skip to content

Commit

Permalink
Add CSV_UPDATE component
Browse files Browse the repository at this point in the history
  • Loading branch information
fttx committed Apr 24, 2021
1 parent 4cf2a24 commit 658a109
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 10 deletions.
51 changes: 49 additions & 2 deletions electron/src/handlers/scans.handler.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import axios from 'axios';
import { exec, execSync } from 'child_process';
import * as parse from 'csv-parse/lib/sync';
import * as stringify from 'csv-stringify';
import { clipboard, dialog, shell } from 'electron';
import * as fs from 'fs';
import * as http from 'http';
import * as os from 'os';
import * as robotjs from 'robotjs';
import { isNumeric } from 'rxjs/util/isNumeric';
import { lt, SemVer } from 'semver';
import { Config } from '../config';
import * as Supplant from 'supplant';
import * as WebSocket from 'ws';
import { requestModel, requestModelHelo, requestModelOnSmartphoneCharge, requestModelPutScanSessions, requestModelRemoteComponent } from '../../../ionic/src/models/request.model';
import { responseModelPutScanAck, responseModelRemoteComponentResponse } from '../../../ionic/src/models/response.model';
import { ScanModel } from '../../../ionic/src/models/scan.model';
import { Config } from '../config';
import { Handler } from '../models/handler.model';
import { SettingsHandler } from './settings.handler';
import { UiHandler } from './ui.handler';
Expand Down Expand Up @@ -60,7 +61,7 @@ export class ScansHandler implements Handler {
// keyboard emulation
for (let outputBlock of scan.outputBlocks) {
if (outputBlock.skipOutput && outputBlock.type != 'http' && outputBlock.type != 'run'
&& outputBlock.type != 'csv_lookup') {
&& outputBlock.type != 'csv_lookup' && outputBlock.type != 'csv_update') {
// for these components the continue; is called inside the switch below (< v3.12.0)
continue;
}
Expand Down Expand Up @@ -155,6 +156,10 @@ export class ScansHandler implements Handler {
}
break;
}
case 'csv_update': {
if (!outputBlock.skipOutput) this.typeString(outputBlock.value)
break;
}
} // end switch(outputBlock.type)
} // end for

Expand Down Expand Up @@ -190,6 +195,7 @@ export class ScansHandler implements Handler {
run: null,
http: null,
csv_lookup: null,
csv_update: null,
};
// Search if there is a corresponding Output component to assign to the NULL variables
let keys = Object.keys(variables);
Expand Down Expand Up @@ -336,6 +342,47 @@ export class ScansHandler implements Handler {

break;
}

case 'csv_update': {

// Try to open the file
let fileContent: string;
try {
fileContent = fs.readFileSync(request.outputBlock.csvFile).toString().replace(/^\ufeff/, '');
} catch (error) {
errorMessage = 'The CSV_UPDATE component failed to access ' + request.outputBlock.csvFile + '<br>Make you sure the path is correct and that the server has the read permissions.<br><br>Error code: ' + error.code; // ENOENT
break;
}

// Try to find the columns
try {
const records: any[] = parse(fileContent, { columns: false, ltrim: true, rtrim: true, delimiter: request.outputBlock.delimiter });
let output = request.outputBlock.notFoundValue;

// Replace the values
const result = records.map(row => {
if (row[request.outputBlock.searchColumn - 1] == request.outputBlock.value) {
row[request.outputBlock.columnToUpdate - 1] = request.outputBlock.newValue
output = request.outputBlock.newValue;
}
return row;
});

// Write the file synchronously
await new Promise<void>((resolve) => {
stringify(result, { delimiter: request.outputBlock.delimiter }, (err: Error | undefined, output: string) => {
fs.writeFileSync(request.outputBlock.csvFile, output);
resolve();
})
});
responseOutputBlock.value = output;
} catch (error) {
responseOutputBlock.value = request.outputBlock.notFoundValue;
break;
}

break;
}
} // end switch(outputBlock.type)

remoteComponentResponse.fromObject({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ <h2>Modifier keys</h2>
<input type="text" value="http" disabled class="example-variable" /> <br>
<input type="text" value="run" disabled class="example-variable" /> <br>
<input type="text" value="csv_lookup" disabled class="example-variable" /> <br>
<input type="text" value="csv_update" disabled class="example-variable" /> <br>
<!-- Remember to update the other components (6), and the article:
https://barcodetopc.com/tutorial/how-to-use-the-run-output-component/#pass-parameters
https://barcodetopc.com/tutorial/how-to-use-the-csv_lookup-component/
Expand Down Expand Up @@ -233,6 +234,7 @@ <h2 color="dark">Text</h2>
<input type="text" value="http" disabled class="example-variable" /> <br>
<input type="text" value="run" disabled class="example-variable" /> <br>
<input type="text" value="csv_lookup" disabled class="example-variable" /> <br>
<input type="text" value="csv_update" disabled class="example-variable" /> <br>
<!-- Remember to update the other components (6), and the article:
https://barcodetopc.com/tutorial/how-to-use-the-run-output-component/#pass-parameters
https://barcodetopc.com/tutorial/how-to-use-the-csv_lookup-component/ (remove comments)
Expand Down Expand Up @@ -335,6 +337,7 @@ <h2 color="dark">Method</h2>
<input type="text" value="http" disabled class="example-variable" /> <br>
<input type="text" value="run" disabled class="example-variable" /> <br>
<input type="text" value="csv_lookup" disabled class="example-variable" /> <br>
<input type="text" value="csv_update" disabled class="example-variable" /> <br>
<!-- Remember to update the other components (6), and the article:
https://barcodetopc.com/tutorial/how-to-use-the-run-output-component/#pass-parameters
https://barcodetopc.com/tutorial/how-to-use-the-csv_lookup-component/
Expand Down Expand Up @@ -363,7 +366,7 @@ <h2 color="dark">Method</h2>
<div [hidden]="outputBlock.type != 'csv_lookup'">
<ion-item no-lines text-wrap>
<p>
Allows you to match field values inside CSV files and then output the corresponding field value of another column.
CSV_LOOKUP allows you to match field values inside CSV files and then output the corresponding field value of another column.
</p>
</ion-item>

Expand Down Expand Up @@ -394,6 +397,7 @@ <h2 color="dark">Method</h2>
<input type="text" value="http" disabled class="example-variable" /> <br>
<input type="text" value="run" disabled class="example-variable" /> <br>
<input type="text" value="csv_lookup" disabled class="example-variable" /> <br>
<input type="text" value="csv_update" disabled class="example-variable" /> <br>
<!-- Remember to update the other components (6), and the article:
https://barcodetopc.com/tutorial/how-to-use-the-run-output-component/#pass-parameters
https://barcodetopc.com/tutorial/how-to-use-the-csv_lookup-component/
Expand Down Expand Up @@ -430,7 +434,95 @@ <h2 color="dark">Method</h2>
<input id="_delimiter" [(ngModel)]="outputBlock.delimiter" class="inline-input" type="text" placeholder="," />
<p>The field separator character</p>
</ion-item>
</div>
</div> <!-- end csv_lookup -->

<div [hidden]="outputBlock.type != 'csv_update'">
<ion-item no-lines text-wrap>
<p>
CSV_UPDATE allows you to find and edit values inside CSV files.<br>
If the operation is successful the new value will be outputted.
</p>
</ion-item>

<ion-item text-wrap>
<label for="_searchValue">Search value</label>
<input id="_searchValue" [(ngModel)]="outputBlock.value" class="inline-input" type="text" placeholder="Eg. 0" />

<p>
<br>
The text or number to search in the CSV file. You can use the variables listed below to search values coming from other components.
</p>
</ion-item>

<ion-item no-lines text-wrap>
<label for="_newValue">New Value</label>
<input id="_newValue" [(ngModel)]="outputBlock.newValue" class="inline-input" type="text" placeholder="Eg. 1" />

<p>
<br>
The text or number to use to replace the <i>Search value</i> in the CSV file. You can use the variables listed below to search values coming from other components.
</p>
</ion-item>

<ion-item text-wrap>
<p>
<br>
<i>New Value</i> example:<br>
<code ngNonBindable>{{ number }}</code><br><br>

Available variables (lowercase): <br>
<code>
<input type="text" value="barcode" disabled class="example-variable" /> <br>
<input type="text" value="barcodes" disabled class="example-variable" /> <br>
<input type="text" value="number" disabled class="example-variable" /> <br>
<input type="text" value="text" disabled class="example-variable" /> <br>
<input type="text" value="timestamp" disabled class="example-variable" /> <br>
<input type="text" value="date" disabled class="example-variable" /> <br>
<input type="text" value="time" disabled class="example-variable" /> <br>
<input type="text" value="scan_session_name" disabled class="example-variable" /> <br>
<input type="text" value="device_name" disabled class="example-variable" /><br>
<input type="text" value="select_option" disabled class="example-variable" /> <br>
<input type="text" value="http" disabled class="example-variable" /> <br>
<input type="text" value="run" disabled class="example-variable" /> <br>
<input type="text" value="csv_lookup" disabled class="example-variable" /> <br>
<input type="text" value="csv_update" disabled class="example-variable" /> <br>
<!-- Remember to update the other components (6), and the article:
https://barcodetopc.com/tutorial/how-to-use-the-run-output-component/#pass-parameters
https://barcodetopc.com/tutorial/how-to-use-the-csv_lookup-component/
-->
</code>
</p>
</ion-item>

<ion-item text-wrap>
<label for="_csvFilePath">CSV Input File Path</label>
<input id="_csvFilePath" [(ngModel)]="outputBlock.csvFile" class="inline-input" type="text" placeholder="C:&#92;data.csv" />
</ion-item>

<ion-item text-wrap>
<label for="_searchColumnIndex">Search Column Index</label>
<input id="_searchColumnIndex" [(ngModel)]="outputBlock.searchColumn" class="inline-input" type="number" placeholder="1" />
<p>The column number (starting with 1 for the left-most column of the CSV file) where you want to search</p>
</ion-item>

<ion-item text-wrap>
<label for="_columnToUpdateIndex">Column to Edit Index</label>
<input id="_columnToUpdateIndex" [(ngModel)]="outputBlock.columnToUpdate" class="inline-input" type="number" placeholder="2" />
<p>The column number (starting with 1 for the left-most column of the CSV file) that you want to update</p>
</ion-item>

<ion-item text-wrap>
<label for="_notFoundValue">Not Found value</label>
<input id="_notFoundValue" [(ngModel)]="outputBlock.notFoundValue" class="inline-input" type="text" placeholder="" />
<p>The text to output when the lookup doesn't produce results</p>
</ion-item>

<ion-item text-wrap>
<label for="_delimiter">Delimiter character</label>
<input id="_delimiter" [(ngModel)]="outputBlock.delimiter" class="inline-input" type="text" placeholder="," />
<p>The field separator character</p>
</ion-item>
</div> <!-- end csv_update -->

<div [hidden]="outputBlock.type != 'beep'">
<ion-item no-lines text-wrap>
Expand Down Expand Up @@ -504,6 +596,7 @@ <h2 color="dark">Method</h2>
<input type="text" value="http" disabled class="example-variable" /> <br>
<input type="text" value="run" disabled class="example-variable" /> <br>
<input type="text" value="csv_lookup" disabled class="example-variable" /> <br>
<input type="text" value="csv_update" disabled class="example-variable" /> <br>
<!-- Remember to update the other components (6), and the article:
https://barcodetopc.com/tutorial/how-to-use-the-run-output-component/#pass-parameters
https://barcodetopc.com/tutorial/how-to-use-the-csv_lookup-component/
Expand Down Expand Up @@ -543,6 +636,7 @@ <h2 color="dark">Method</h2>
<input type="text" value="http" disabled class="example-variable" /> <br>
<input type="text" value="run" disabled class="example-variable" /> <br>
<input type="text" value="csv_lookup" disabled class="example-variable" /> <br>
<input type="text" value="csv_update" disabled class="example-variable" /> <br>
<!-- Remember to update the other components (6), and the article:
https://barcodetopc.com/tutorial/how-to-use-the-run-output-component/#pass-parameters
https://barcodetopc.com/tutorial/how-to-use-the-csv_lookup-component/
Expand Down Expand Up @@ -596,7 +690,7 @@ <h2 color="dark">Method</h2>
</div>

<!-- Show "Variables dependency" info box only for: function, if, select_option, http, run -->
<ion-item [hidden]="!(outputBlock.type == 'function' || outputBlock.type == 'if' || outputBlock.type == 'select_option' || outputBlock.type == 'http' || outputBlock.type == 'csv_lookup')">
<ion-item [hidden]="!(outputBlock.type == 'function' || outputBlock.type == 'if' || outputBlock.type == 'select_option' || outputBlock.type == 'http' || outputBlock.type == 'csv_lookup' || outputBlock.type == 'csv_update')">
<info-box title="Info">
To access to the variables mentioned above you MUST put a corresponding Output Component in your Output Template that will assign a value to the variable.<br><br>
See <a class="clickable" (click)="electronProvider.shell.openExternal(getUrlTutorialUseVariables())">this example</a>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export class EditOutputBlockPage {
case 'select_option': this.electronProvider.shell.openExternal(Config.URL_TUTORIAL_CREATE_OUTPUT_TEMPLATE); break;
case 'beep': this.electronProvider.shell.openExternal(Config.URL_TUTORIAL_CREATE_OUTPUT_TEMPLATE); break;
case 'csv_lookup': this.electronProvider.shell.openExternal(Config.URL_TUTORIAL_CSV_LOOKUP); break;
case 'csv_update': this.electronProvider.shell.openExternal(Config.URL_TUTORIAL_CREATE_OUTPUT_TEMPLATE); break;
case 'alert': this.electronProvider.shell.openExternal(Config.URL_TUTORIAL_CREATE_OUTPUT_TEMPLATE); break;
default: this.electronProvider.shell.openExternal(Config.URL_TUTORIAL_CREATE_OUTPUT_TEMPLATE); break;
}
Expand Down Expand Up @@ -128,7 +129,7 @@ export class EditOutputBlockPage {
case 'fast': beepSpeed = 250; break;
}
let beep = () => {
return new Promise((resolve, reject) => {
return new Promise<void>((resolve, reject) => {
let audio = new Audio();
audio.src = 'assets/audio/' + this.outputBlock.value + '.ogg';
audio.load();
Expand Down
10 changes: 8 additions & 2 deletions ionic/src/models/output-block.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class OutputBlockModel {
*
* Warning: remeber to update also edit-output-block-pop-over.ts/onHelpClick() method when chaning this field.
*/
type: 'key' | 'text' | 'variable' | 'function' | 'barcode' | 'delay' | 'if' | 'endif' | 'http' | 'run' | 'select_option' | 'beep' | 'csv_lookup' | 'alert';
type: 'key' | 'text' | 'variable' | 'function' | 'barcode' | 'delay' | 'if' | 'endif' | 'http' | 'run' | 'select_option' | 'beep' | 'csv_lookup' | 'csv_update' | 'alert';
/**
* When true means that the user doesn't want to type or append to files
* the component value but instead he wants to acquire the data, and use it
Expand Down Expand Up @@ -99,14 +99,20 @@ export class OutputBlockModel {
errorMessage?: string;

/**
* Parameters for the CSV_LOOKUP component
* Parameters for the CSV_LOOKUP and CSV_UPDATE component
*/
csvFile?: string;
searchColumn?: number;
resultColumn?: number;
notFoundValue?: string;
delimiter?: string;

/**
* Parameters for the CSV_UPDATE component
*/
columnToUpdate?: number;
newValue?: string;

/**
* Parameters for the ALERT component
*/
Expand Down
2 changes: 1 addition & 1 deletion ionic/src/models/output-profile.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class OutputProfileModel {
static ContainsBlockingComponents(outputProfile: OutputProfileModel): boolean {
return outputProfile.outputBlocks.findIndex(x =>
x.value == 'number' || x.value == 'text' || x.type == 'select_option' ||
x.type == 'http' || x.type == 'run' || x.type == 'csv_lookup' ||
x.type == 'http' || x.type == 'run' || x.type == 'csv_lookup' || x.type == 'csv_update' ||
x.type == 'alert' ||
/**
* @deprecated for update transition only
Expand Down
1 change: 1 addition & 0 deletions ionic/src/models/scan.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export class ScanModel {
case 'http': return block.value;
case 'run': return block.value;
case 'csv_lookup': return block.value;
case 'csv_update': return block.value;
case 'barcode': return block.value;
case 'delay': return ''
case 'beep': return ''
Expand Down
1 change: 1 addition & 0 deletions ionic/src/pages/settings/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ <h2 padding-vertical>
<input type="text" value="http" disabled />
<input type="text" value="run" disabled />
<input type="text" value="csv_lookup" disabled />
<input type="text" value="csv_update" disabled />
</code><br>
Note 1:
<p style="margin-left: 13px">To use the variables acquired from the smartphone it's required to put a correspoinding Output Component in the Output template field</p><br>
Expand Down
1 change: 1 addition & 0 deletions ionic/src/pages/settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export class SettingsPage {
{ name: 'HTTP', value: '', type: 'http', httpMethod: 'get', httpData: null, httpParams: null, httpHeaders: null, editable: true, skipOutput: false, timeout: 10000 },
{ name: 'RUN', value: '', type: 'run', editable: true, skipOutput: false, timeout: 10000 },
{ name: 'CSV_LOOKUP', value: '{{ barcode }}', type: 'csv_lookup', skipOutput: false, editable: true, csvFile: '', searchColumn: 1, resultColumn: 2, notFoundValue: '', delimiter: ',' },
{ name: 'CSV_UPDATE', value: '{{ barcode }}', type: 'csv_update', skipOutput: false, editable: true, csvFile: '', searchColumn: 1, columnToUpdate: 2, newValue: '', notFoundValue: '', delimiter: ',' },
{ name: 'BEEP', value: 'beep', type: 'beep', editable: true, beepsNumber: 1, beepSpeed: 'medium' },
{ name: 'ALERT', value: '', type: 'alert', editable: true, alertTitle: 'Alert', alertDiscardScanButton: 'Discard scan', alertScanAgainButton: 'Scan again', alertOkButton: 'Ok' },
];
Expand Down
Loading

0 comments on commit 658a109

Please sign in to comment.