feat(server): enhance workflow and script handling with new features
- Added `workflowLastModifiedAt` function to retrieve the last modified timestamp of workflow YAML files. - Introduced `encodeBinaryForWire` and `reviveBinaryFromWire` functions for better handling of binary data in JSON. - Implemented `useDeleteKv` hook for deleting key-value pairs in the web API. - Enhanced `scriptsPluginFactory` to support dry-run evaluations with JSONata expressions. - Added `set-dry-run-smoke.js` test to validate dry-run functionality. - Updated profile configuration to include `overlayFromMerged` for better profile management. - Introduced try-session management in the web components to handle step execution states. - Improved various components to support new try-session features and maintain UI consistency. Co-authored-by: Nasyarobby Putra <nasyarobby@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
export { isPlainObject } from "./is-plain-object.js";
|
||||
export { mergeProfileConfig, configHasOverlay } from "./profile-config.js";
|
||||
export { mergeProfileConfig, overlayFromMerged, configHasOverlay } from "./profile-config.js";
|
||||
export { ensureWorkflowFilename, suggestCopyFilename } from "./workflow-filename.js";
|
||||
export { HTTP_METHODS, namespacedPath, hasWorkflowTrigger } from "./workflow-path.js";
|
||||
|
||||
@@ -17,6 +17,45 @@ export function mergeProfileConfig(profileConfig, stepConfig) {
|
||||
return { ...base, ...stepConfig };
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse of merge for Apply-to-card: keep only keys whose values differ from the profile.
|
||||
* No profile → return the merged object as-is (full step config).
|
||||
*
|
||||
* @param {unknown} profileConfig
|
||||
* @param {unknown} mergedConfig
|
||||
* @returns {Record<string, unknown>}
|
||||
*/
|
||||
export function overlayFromMerged(profileConfig, mergedConfig) {
|
||||
const merged =
|
||||
mergedConfig != null && typeof mergedConfig === "object" && !Array.isArray(mergedConfig)
|
||||
? { ...mergedConfig }
|
||||
: {};
|
||||
const base =
|
||||
profileConfig != null && typeof profileConfig === "object" && !Array.isArray(profileConfig)
|
||||
? profileConfig
|
||||
: null;
|
||||
if (!base) return merged;
|
||||
|
||||
const overlay = {};
|
||||
for (const [key, value] of Object.entries(merged)) {
|
||||
if (!Object.prototype.hasOwnProperty.call(base, key) || !sameConfigValue(base[key], value)) {
|
||||
overlay[key] = value;
|
||||
}
|
||||
}
|
||||
return overlay;
|
||||
}
|
||||
|
||||
function sameConfigValue(a, b) {
|
||||
if (Object.is(a, b)) return true;
|
||||
if (a == null || b == null) return a === b;
|
||||
if (typeof a !== "object" || typeof b !== "object") return false;
|
||||
try {
|
||||
return JSON.stringify(a) === JSON.stringify(b);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} config
|
||||
* @returns {boolean}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
isPlainObject,
|
||||
mergeProfileConfig,
|
||||
namespacedPath,
|
||||
overlayFromMerged,
|
||||
} from "./index.js";
|
||||
|
||||
describe("isPlainObject", () => {
|
||||
@@ -32,6 +33,29 @@ describe("mergeProfileConfig", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("overlayFromMerged", () => {
|
||||
it("returns full merged when there is no profile", () => {
|
||||
expect(overlayFromMerged(null, { a: 1, b: 2 })).toEqual({ a: 1, b: 2 });
|
||||
expect(overlayFromMerged(undefined, { x: 1 })).toEqual({ x: 1 });
|
||||
});
|
||||
|
||||
it("keeps only keys that differ from the profile", () => {
|
||||
expect(overlayFromMerged({ a: 1, b: 2 }, { a: 1, b: 3, c: 4 })).toEqual({
|
||||
b: 3,
|
||||
c: 4,
|
||||
});
|
||||
expect(overlayFromMerged({ a: 1 }, { a: 1 })).toEqual({});
|
||||
expect(overlayFromMerged({ nested: { a: 1 } }, { nested: { a: 1 } })).toEqual({});
|
||||
expect(overlayFromMerged({ nested: { a: 1 } }, { nested: { b: 2 } })).toEqual({
|
||||
nested: { b: 2 },
|
||||
});
|
||||
});
|
||||
|
||||
it("treats empty-string override as a real overlay key", () => {
|
||||
expect(overlayFromMerged({ url: "http://a" }, { url: "" })).toEqual({ url: "" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("configHasOverlay", () => {
|
||||
it("is true only for non-empty plain objects", () => {
|
||||
expect(configHasOverlay({ a: 1 })).toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user