From 4fbc5bb6bc4265e5c91d2c58eb45d282b4d4f789 Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Thu, 24 Apr 2025 13:51:24 +0700
Subject: [PATCH 1/6] add properties for api process task
---
.../Designer/properties/PropertyManager.js | 1 +
.../process/ABProcessTaskService.js | 5 +
.../process/ABProcessTaskServiceApi.js | 244 ++++++++++++++++++
styles/Designer.css | 8 +-
4 files changed, 257 insertions(+), 1 deletion(-)
create mode 100644 src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
diff --git a/src/rootPages/Designer/properties/PropertyManager.js b/src/rootPages/Designer/properties/PropertyManager.js
index 8527be89..f59651b7 100644
--- a/src/rootPages/Designer/properties/PropertyManager.js
+++ b/src/rootPages/Designer/properties/PropertyManager.js
@@ -50,6 +50,7 @@ export default function (AB) {
require("./process/ABProcessTaskServiceAccountingFPClose.js"),
require("./process/ABProcessTaskServiceAccountingFPYearClose.js"),
require("./process/ABProcessTaskServiceAccountingJEArchive.js"),
+ require("./process/ABProcessTaskServiceApi.js"),
require("./process/ABProcessTaskServiceCalculate.js"),
require("./process/ABProcessTaskServiceGetResetPasswordUrl.js"),
require("./process/ABProcessTaskServiceInsertRecord.js"),
diff --git a/src/rootPages/Designer/properties/process/ABProcessTaskService.js b/src/rootPages/Designer/properties/process/ABProcessTaskService.js
index 39b38905..9d0eefc0 100644
--- a/src/rootPages/Designer/properties/process/ABProcessTaskService.js
+++ b/src/rootPages/Designer/properties/process/ABProcessTaskService.js
@@ -73,6 +73,11 @@ export default function (AB) {
this.switchTo("AccountingJEArchive");
},
},
+ {
+ view: "button",
+ label: L("Api Request"),
+ click: () => this.switchTo("Api"),
+ },
{
view: "button",
label: L("Query Task"),
diff --git a/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js b/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
new file mode 100644
index 00000000..7cae8eeb
--- /dev/null
+++ b/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
@@ -0,0 +1,244 @@
+/*
+ * UIProcessTaskServiceApi
+ *
+ * Display the form for entering the properties for a new
+ * ServiceApi Task
+ *
+ * @return {ClassUI} The Class Definition for this UI widget.
+ */
+import UI_Class from "../../ui_class";
+
+export default function(AB) {
+ const UIClass = UI_Class(AB);
+ const L = UIClass.L();
+ const uiConfig = AB.Config.uiSettings();
+
+ class UIProcessServiceApi extends UIClass {
+ constructor() {
+ super("properties_process_service_api", {
+ form: "",
+ headers: "",
+ suggest: "",
+ });
+
+ this.element = null;
+ // A webix datacollection - used to load process data into our mention suggest
+ this.suggestData = new AB.Webix.DataCollection({});
+ }
+
+ static get key() {
+ return "Api";
+ }
+
+ ui() {
+ const ids = this.ids;
+ return {
+ rows: [
+ {
+ id: ids.form,
+ view: "form",
+ elementsConfig: {
+ labelWidth: uiConfig.labelWidthLarge,
+ },
+ elements: [
+ {
+ view: "text",
+ name: "name",
+ label: L("Name"),
+ },
+ {
+ view: "text",
+ name: "url",
+ label: L("Url"),
+ },
+ {
+ view: "combo",
+ name: "method",
+ label: L("Method"),
+ options: ["GET", "POST", "PUT", "DELETE"],
+ },
+ {
+ cols: [
+ {
+ view: "label",
+ label: L("Headers"),
+ autowidth: true,
+ },
+ {
+ view: "icon",
+ icon: "fa fa-plus",
+ width: 50,
+ on: { onItemClick: () => this.addHeader() },
+ },
+ {},
+ ],
+ },
+ { id: ids.headers, rows: [] },
+ {
+ view: "texthighlight",
+ name: "body",
+ height: 200,
+ label: L("Request Body"),
+ labelPosition: "top",
+ type: "textarea",
+ placeholder: "use ${...} to add process data",
+ css: "monospace",
+ highlight: (text) => {
+ text = text.replaceAll(
+ " ",
+ `·`
+ );
+ text = text.replace(/\${([^}]*)}/g, (m, c) => {
+ const data = this.suggestData.find(
+ { key: c },
+ true
+ );
+ const centerPad = (str, target, pad, right) => {
+ if (str.length === target) return str;
+ if (right)
+ return centerPad(
+ `${str}${pad}`,
+ target,
+ pad
+ );
+ else
+ return centerPad(
+ `${pad}${str}`,
+ target,
+ pad,
+ true
+ );
+ };
+ if (data) {
+ // We save the key in the text, but display the
+ // label. Need to keep the length the same or
+ // the cursor get's messed up.
+ const { key, value } = data;
+ const diff = key.length - value.length;
+ let val = data.value;
+ if (diff > 0) {
+ val = centerPad(val, key.length, "─", true);
+ } else if (diff < 0) {
+ val = `...${val.slice(diff + 3)}`;
+ }
+ return `\${${val}}`;
+ }
+ return `${m}`;
+ });
+ return text;
+ },
+ suggest: {
+ id: ids.suggest,
+ view: "mentionsuggest",
+ symbol: "$",
+ template: "{#key#}",
+ data: this.suggestData,
+ },
+ },
+ {
+ view: "switch",
+ name: "responseJson",
+ value: 1,
+ label: L("Response as"),
+ onLabel: L("JSON"),
+ offLabel: L("Text"),
+ },
+ ],
+ },
+ ],
+ };
+ }
+
+ populate(element) {
+ const { name, url, method, body, responseJson } = element;
+ $$(this.ids.form).setValues({ name, url, method, body, responseJson });
+ element.headers?.forEach?.((header) => {
+ this.addHeader(header);
+ });
+ const processData = element.process.processDataFields(element) ?? [];
+ this.suggestData.parse(
+ processData
+ .filter((i) => !!i)
+ .map?.((i) => ({ value: i.label, key: i.key }))
+ );
+ }
+
+ values() {
+ const values = {};
+ let form = {};
+ try {
+ form = $$(this.ids.form).getValues();
+ } catch (e) {
+ console.log("caught", e);
+ }
+ Object.keys(form).forEach((key) => {
+ key.includes("headers")
+ ? nestValue(key, form[key], values)
+ : (values[key] = form[key]);
+ });
+ // Convert headers to an array
+ if (values.headers) {
+ const headers = [];
+ Object.keys(values.headers).forEach((key) =>
+ headers.push(values.headers[key])
+ );
+ values.headers = headers;
+ }
+ return values;
+ }
+
+ addHeader(header = {}) {
+ const uid = AB.Webix.uid(); //this is unique to the page
+ const row = {
+ id: uid,
+ cols: [
+ {
+ view: "text",
+ name: `headers.${uid}.key`,
+ placeholder: "header",
+ value: header.key,
+ },
+ {
+ view: "text",
+ name: `headers.${uid}.value`,
+ placeholder: "value",
+ value: header.value,
+ gravity: 2,
+ },
+ {
+ view: "icon",
+ icon: "wxi-trash",
+ width: "50",
+ on: {
+ onItemClick: () => $$(this.ids.headers).removeView(uid),
+ },
+ },
+ ],
+ };
+ $$(this.ids.headers).addView(row);
+ }
+ }
+
+ return UIProcessServiceApi;
+}
+
+/**
+ * Recursively nests a value within an object based on a dot-separated key.
+ *
+ * @param {string} key - The dot-separated key specifying the nested path.
+ * @param {*} value - The value to assign at the final nested level.
+ * @param {object} [obj={}] - The object to modify (or a new object if not provided).
+ * @returns {object} The modified object with the nested value.
+ */
+function nestValue(key, value, obj = {}) {
+ const [firstKey, ...remainingKeys] = key.split(".");
+
+ if (remainingKeys.length === 0) {
+ obj[firstKey] = value;
+ } else {
+ obj[firstKey] = obj[firstKey] ?? {};
+ nestValue(remainingKeys.join("."), value, obj[firstKey]);
+ }
+
+ return obj;
+}
diff --git a/styles/Designer.css b/styles/Designer.css
index b6ebbd80..581d1ffc 100644
--- a/styles/Designer.css
+++ b/styles/Designer.css
@@ -264,4 +264,10 @@
.webix_tree_leaves {
display: block !important;
-}
\ No newline at end of file
+}
+
+.monospace > div > textarea,
+.monospace > div > div > .webix_text_highlight_value {
+ word-break: break-all;
+ font-family: monospace;
+}
From 428e17724a49914c5c3d3848e167ef4770bf9404 Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Thu, 24 Apr 2025 13:52:05 +0700
Subject: [PATCH 2/6] fix saving process task name
---
src/rootPages/Designer/ui_work_process_workspace_model.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/rootPages/Designer/ui_work_process_workspace_model.js b/src/rootPages/Designer/ui_work_process_workspace_model.js
index 77c3c0ba..1f3b598a 100644
--- a/src/rootPages/Designer/ui_work_process_workspace_model.js
+++ b/src/rootPages/Designer/ui_work_process_workspace_model.js
@@ -882,7 +882,7 @@ export default function (AB) {
Object.keys(values).forEach((k) => {
objVals[k] = values[k];
});
- if (!thisObj.name) objVals.name = values.label;
+ if (!objVals.name) objVals.name = values.label;
thisObj.fromValues(objVals);
thisObj.warningsEval(); // resets the warnings
From 2dd58c86384b7c696f8363779ffd0ae92204fdd1 Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Wed, 14 May 2025 09:49:40 +0700
Subject: [PATCH 3/6] add secrets and improve templating
---
.../process/ABProcessTaskServiceApi.js | 246 +++++++++++++-----
styles/Designer.css | 3 +-
2 files changed, 184 insertions(+), 65 deletions(-)
diff --git a/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js b/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
index 7cae8eeb..4a16946c 100644
--- a/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
+++ b/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
@@ -18,12 +18,14 @@ export default function(AB) {
super("properties_process_service_api", {
form: "",
headers: "",
+ secrets: "",
suggest: "",
});
this.element = null;
// A webix datacollection - used to load process data into our mention suggest
this.suggestData = new AB.Webix.DataCollection({});
+ this.templateRgx = /<%= (.+?) %>/g;
}
static get key() {
@@ -32,6 +34,13 @@ export default function(AB) {
ui() {
const ids = this.ids;
+ this.AB.Webix.ui({
+ id: ids.suggest,
+ view: "mentionsuggest",
+ symbol: "<",
+ template: "%= #value# %>",
+ data: this.suggestData,
+ });
return {
rows: [
{
@@ -47,9 +56,12 @@ export default function(AB) {
label: L("Name"),
},
{
- view: "text",
+ view: "texthighlight",
name: "url",
label: L("Url"),
+ highlight: (t) => this.highlight(t),
+ suggest: this.ids.suggest,
+ css: "monospace",
},
{
view: "combo",
@@ -83,58 +95,26 @@ export default function(AB) {
type: "textarea",
placeholder: "use ${...} to add process data",
css: "monospace",
- highlight: (text) => {
- text = text.replaceAll(
- " ",
- `·`
- );
- text = text.replace(/\${([^}]*)}/g, (m, c) => {
- const data = this.suggestData.find(
- { key: c },
- true
- );
- const centerPad = (str, target, pad, right) => {
- if (str.length === target) return str;
- if (right)
- return centerPad(
- `${str}${pad}`,
- target,
- pad
- );
- else
- return centerPad(
- `${pad}${str}`,
- target,
- pad,
- true
- );
- };
- if (data) {
- // We save the key in the text, but display the
- // label. Need to keep the length the same or
- // the cursor get's messed up.
- const { key, value } = data;
- const diff = key.length - value.length;
- let val = data.value;
- if (diff > 0) {
- val = centerPad(val, key.length, "─", true);
- } else if (diff < 0) {
- val = `...${val.slice(diff + 3)}`;
- }
- return `\${${val}}`;
- }
- return `${m}`;
- });
- return text;
- },
- suggest: {
- id: ids.suggest,
- view: "mentionsuggest",
- symbol: "$",
- template: "{#key#}",
- data: this.suggestData,
- },
+ highlight: (t) => this.highlight(t),
+ suggest: this.ids.suggest,
+ },
+ {
+ cols: [
+ {
+ view: "label",
+ label: L("Secrets"),
+ autowidth: true,
+ },
+ {
+ view: "icon",
+ icon: "fa fa-plus",
+ width: 50,
+ on: { onItemClick: () => this.addSecret() },
+ },
+ {},
+ ],
},
+ { id: ids.secrets, rows: [] },
{
view: "switch",
name: "responseJson",
@@ -150,29 +130,41 @@ export default function(AB) {
}
populate(element) {
- const { name, url, method, body, responseJson } = element;
- $$(this.ids.form).setValues({ name, url, method, body, responseJson });
- element.headers?.forEach?.((header) => {
- this.addHeader(header);
- });
+ // Reset our suggest data
+ this.suggestData.clearAll();
+ this.suggestData.parse(
+ element.storedSecrets?.map((s) => ({
+ value: `Secret: ${s}`,
+ key: `Secret: ${s}`,
+ }))
+ );
const processData = element.process.processDataFields(element) ?? [];
this.suggestData.parse(
processData
.filter((i) => !!i)
.map?.((i) => ({ value: i.label, key: i.key }))
);
+ let { name, url, method, body, responseJson } = element;
+ // These might have process value placeholders, display the label
+ // instead of ids
+ body = this.convertIDToLabel(body);
+ url = this.convertIDToLabel(url);
+
+ $$(this.ids.form).setValues({ name, url, method, body, responseJson });
+
+ element.headers?.forEach?.((header) => {
+ header.value = this.convertIDToLabel(header.value);
+ this.addHeader(header);
+ });
+ element.storedSecrets?.forEach?.((secret) => this.addSecret(secret));
}
values() {
const values = {};
let form = {};
- try {
- form = $$(this.ids.form).getValues();
- } catch (e) {
- console.log("caught", e);
- }
+ form = $$(this.ids.form).getValues();
Object.keys(form).forEach((key) => {
- key.includes("headers")
+ key.includes("headers") || key.includes("secrets")
? nestValue(key, form[key], values)
: (values[key] = form[key]);
});
@@ -184,9 +176,36 @@ export default function(AB) {
);
values.headers = headers;
}
+ // These might contain process value placeholders, convert the label to
+ // actuall ids before saving
+ values.body = this.convertLabelToID(values.body);
+ values.url = this.convertLabelToID(values.url);
+ values.headers?.forEach(
+ (h) => (h.value = this.convertLabelToID(h.value))
+ );
+ // Convert secrets to an array
+ if (values.secrets) {
+ const secrets = [];
+ Object.keys(values.secrets).forEach((secret) =>
+ secrets.push(values.secrets[secret])
+ );
+ values.secrets = secrets;
+ }
+ if (this.deleteSecrets) {
+ values.deleteSecrets = this.deleteSecrets;
+ delete this.deleteSecrets;
+ }
+ console.log("VALUES", values);
+
return values;
}
+ /**
+ * Add fields to the form for a header
+ * @param {object} [header={}]
+ * @param {string} [header.key]
+ * @param {string} [header.value]
+ */
addHeader(header = {}) {
const uid = AB.Webix.uid(); //this is unique to the page
const row = {
@@ -199,11 +218,14 @@ export default function(AB) {
value: header.key,
},
{
- view: "text",
+ view: "texthighlight",
name: `headers.${uid}.value`,
placeholder: "value",
value: header.value,
gravity: 2,
+ highlight: (t) => this.highlight(t),
+ suggest: this.ids.suggest,
+ css: "monospace",
},
{
view: "icon",
@@ -217,6 +239,102 @@ export default function(AB) {
};
$$(this.ids.headers).addView(row);
}
+
+ /**
+ * Add fields to the form for a secret
+ * @param {string} secret name of an existing secret
+ */
+ addSecret(secret) {
+ const alreadySaved = !!secret;
+ // If the secret is already saved in the db we only allow deleting.
+ // We also don't need it in the from values.
+ const uid = secret ?? AB.Webix.uid(); //this is unique to the page
+ const row = {
+ id: uid,
+ cols: [
+ {
+ view: "text",
+ name: alreadySaved ? undefined : `secrets.${uid}.name`,
+ placeholder: "Name",
+ disabled: alreadySaved,
+ value: secret,
+ },
+ {
+ view: "text",
+ type: "password",
+ name: alreadySaved ? undefined : `secrets.${uid}.value`,
+ placeholder: "Value",
+ disabled: alreadySaved,
+ // We don't actually get the existing secret values so we'll
+ // just mock a value.
+ value: alreadySaved ? ".........." : undefined,
+ gravity: 2,
+ },
+ {
+ view: "icon",
+ icon: "wxi-trash",
+ width: "50",
+ on: {
+ onItemClick: () => {
+ $$(this.ids.secret).removeView(uid);
+ if (alreadySaved) {
+ this.deleteSecrets = this.deleteSecrets ?? [];
+ this.deleteSecrets.push(secret);
+ }
+ },
+ },
+ },
+ ],
+ };
+ $$(this.ids.secrets).addView(row);
+ }
+
+ /**
+ * Highlight function webix texthighlight elements. Highlights secret and
+ * process data in the text.
+ */
+ highlight(text) {
+ // text = text.replaceAll(" ", `·`);
+ text = text.replace(this.templateRgx, (match, value) => {
+ const data = this.suggestData.find({ value }, true);
+ let color = "#FF8C00"; //Not matched - highlight orange
+ let background = "#FFE0B2";
+ if (data) {
+ if (/^Secret:/.test(value)) {
+ color = "#008C8C"; // Matches secret - highlight cyan
+ background = "#A0D7D7";
+ } else {
+ color = "#388E3C"; // Matches process value - highlight green
+ background = "#C4EDC6";
+ }
+ }
+ return `${match}`;
+ });
+ return text;
+ }
+
+ /**
+ * Replace process value labels with ids. Used before saving templates.
+ */
+ convertLabelToID(template) {
+ return template.replace(this.templateRgx, (match, value) => {
+ const data = this.suggestData.find({ value }, true);
+ if (!data) return match;
+ return `<%= ${data.key} %>`;
+ });
+ }
+
+ /**
+ * Replace process value ids with labels. Used before displaying
+ * templates.
+ */
+ convertIDToLabel(template) {
+ return template.replace(this.templateRgx, (match, key) => {
+ const data = this.suggestData.find({ key }, true);
+ if (!data) return match;
+ return `<%= ${data.value} %>`;
+ });
+ }
}
return UIProcessServiceApi;
diff --git a/styles/Designer.css b/styles/Designer.css
index 581d1ffc..bfca69da 100644
--- a/styles/Designer.css
+++ b/styles/Designer.css
@@ -267,7 +267,8 @@
}
.monospace > div > textarea,
-.monospace > div > div > .webix_text_highlight_value {
+.monospace input,
+.monospace .webix_text_highlight_value {
word-break: break-all;
font-family: monospace;
}
From 395f0e193f4192440a2011ae0fd293fc808c6d6e Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Wed, 14 May 2025 09:51:04 +0700
Subject: [PATCH 4/6] fix error loading api object response form
---
.../ui_work_object_list_newObject_api_read_response.js | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_api_read_response.js b/src/rootPages/Designer/ui_work_object_list_newObject_api_read_response.js
index 147f9e85..d2e91791 100644
--- a/src/rootPages/Designer/ui_work_object_list_newObject_api_read_response.js
+++ b/src/rootPages/Designer/ui_work_object_list_newObject_api_read_response.js
@@ -261,12 +261,13 @@ export default function (AB) {
_addFieldItem(key, type) {
const uiItem = this._fieldItem(key, type);
- $$(this.ids.connections).addView(uiItem);
+ $$(this.ids.fields).addView(uiItem);
}
_clearFieldItems() {
- const $connections = $$(this.ids.connections);
- AB.Webix.ui([], $connections);
+ const $fields = $$(this.ids.connections);
+ if (!$fields) return;
+ AB.Webix.ui([], $fields);
}
_populateDataKeys() {
From bc411f749c5a0ce7b96e382130c0547b5baa9632 Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Thu, 5 Jun 2025 13:06:03 +0700
Subject: [PATCH 5/6] ui/ux improvements
---
.../process/ABProcessTaskServiceApi.js | 57 ++++++++++++++++---
1 file changed, 49 insertions(+), 8 deletions(-)
diff --git a/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js b/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
index 4a16946c..6229c637 100644
--- a/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
+++ b/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
@@ -16,6 +16,7 @@ export default function(AB) {
class UIProcessServiceApi extends UIClass {
constructor() {
super("properties_process_service_api", {
+ body: "",
form: "",
headers: "",
secrets: "",
@@ -26,6 +27,7 @@ export default function(AB) {
// A webix datacollection - used to load process data into our mention suggest
this.suggestData = new AB.Webix.DataCollection({});
this.templateRgx = /<%= (.+?) %>/g;
+ this.hint = L("Use <%= ... %> to add process data / secrets");
}
static get key() {
@@ -61,6 +63,7 @@ export default function(AB) {
label: L("Url"),
highlight: (t) => this.highlight(t),
suggest: this.ids.suggest,
+ placeholder: this.hint,
css: "monospace",
},
{
@@ -68,6 +71,13 @@ export default function(AB) {
name: "method",
label: L("Method"),
options: ["GET", "POST", "PUT", "DELETE"],
+ on: {
+ onChange: (val) => {
+ val == "GET"
+ ? $$(ids.body).disable()
+ : $$(ids.body).enable();
+ },
+ },
},
{
cols: [
@@ -89,11 +99,12 @@ export default function(AB) {
{
view: "texthighlight",
name: "body",
+ id: ids.body,
height: 200,
label: L("Request Body"),
labelPosition: "top",
type: "textarea",
- placeholder: "use ${...} to add process data",
+ placeholder: this.hint,
css: "monospace",
highlight: (t) => this.highlight(t),
suggest: this.ids.suggest,
@@ -115,6 +126,9 @@ export default function(AB) {
],
},
{ id: ids.secrets, rows: [] },
+ /**
+ * TODO: Allow the response to be decoded and saved for
+ * future process tasks
{
view: "switch",
name: "responseJson",
@@ -123,6 +137,7 @@ export default function(AB) {
onLabel: L("JSON"),
offLabel: L("Text"),
},
+ */
],
},
],
@@ -214,13 +229,13 @@ export default function(AB) {
{
view: "text",
name: `headers.${uid}.key`,
- placeholder: "header",
+ placeholder: L("header"),
value: header.key,
},
{
view: "texthighlight",
name: `headers.${uid}.value`,
- placeholder: "value",
+ placeholder: `${L("value")} (${this.hint})`,
value: header.value,
gravity: 2,
highlight: (t) => this.highlight(t),
@@ -247,17 +262,41 @@ export default function(AB) {
addSecret(secret) {
const alreadySaved = !!secret;
// If the secret is already saved in the db we only allow deleting.
- // We also don't need it in the from values.
+ // Since secrets aren't saved in the definition, we don't need to send
+ // existing secrets to the server. New one will get encrypted and saved
const uid = secret ?? AB.Webix.uid(); //this is unique to the page
+ const self = this;
const row = {
id: uid,
cols: [
{
view: "text",
name: alreadySaved ? undefined : `secrets.${uid}.name`,
- placeholder: "Name",
+ placeholder: L("Name"),
disabled: alreadySaved,
value: secret,
+ invalidMessage: L("Secret names must be unique!"),
+ validate: (val) => {
+ // Check that the secret name is unique
+ const opts = this.suggestData.find({
+ key: `Secret: ${val}`,
+ });
+ return opts.length === 1;
+ },
+ on: {
+ onChange: function(n, o) {
+ if (n == o) return;
+ // Add the secret to the suggest data
+ const suggest = {
+ id: uid,
+ key: `Secret: ${n}`,
+ value: `Secret: ${n}`,
+ };
+ if (o == "") self.suggestData.parse(suggest);
+ else self.suggestData.updateItem(uid, suggest);
+ this.validate();
+ },
+ },
},
{
view: "text",
@@ -265,8 +304,8 @@ export default function(AB) {
name: alreadySaved ? undefined : `secrets.${uid}.value`,
placeholder: "Value",
disabled: alreadySaved,
- // We don't actually get the existing secret values so we'll
- // just mock a value.
+ // We don't actually get the existing secret values back
+ // so we'll just mock a value.
value: alreadySaved ? ".........." : undefined,
gravity: 2,
},
@@ -290,7 +329,7 @@ export default function(AB) {
}
/**
- * Highlight function webix texthighlight elements. Highlights secret and
+ * Highlight function for webix texthighlight elements. Highlights secret and
* process data in the text.
*/
highlight(text) {
@@ -317,6 +356,7 @@ export default function(AB) {
* Replace process value labels with ids. Used before saving templates.
*/
convertLabelToID(template) {
+ if (!template) return;
return template.replace(this.templateRgx, (match, value) => {
const data = this.suggestData.find({ value }, true);
if (!data) return match;
@@ -329,6 +369,7 @@ export default function(AB) {
* templates.
*/
convertIDToLabel(template) {
+ if (!template) return;
return template.replace(this.templateRgx, (match, key) => {
const data = this.suggestData.find({ key }, true);
if (!data) return match;
From d184c0d758a7f65f988e94cb6e277db51efa6c9d Mon Sep 17 00:00:00 2001
From: Nate <10155226+nh758@users.noreply.github.com>
Date: Mon, 30 Jun 2025 16:02:09 +0700
Subject: [PATCH 6/6] remove debug log
---
.../Designer/properties/process/ABProcessTaskServiceApi.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js b/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
index 6229c637..cfbddf37 100644
--- a/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
+++ b/src/rootPages/Designer/properties/process/ABProcessTaskServiceApi.js
@@ -210,8 +210,7 @@ export default function(AB) {
values.deleteSecrets = this.deleteSecrets;
delete this.deleteSecrets;
}
- console.log("VALUES", values);
-
+
return values;
}