kintone-migrator 0.25.0 → 0.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +1140 -954
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -497,6 +497,236 @@ async function applyAction({ container }) {
|
|
|
497
497
|
});
|
|
498
498
|
}
|
|
499
499
|
//#endregion
|
|
500
|
+
//#region src/lib/deepEqual.ts
|
|
501
|
+
function isArrayEqual(a, b, stack) {
|
|
502
|
+
if (!Array.isArray(b)) return false;
|
|
503
|
+
if (a.length !== b.length) return false;
|
|
504
|
+
for (let i = 0; i < a.length; i++) if (!deepEqualInner(a[i], b[i], stack)) return false;
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Compare two objects by own enumerable string keys (via `Object.keys`).
|
|
509
|
+
*
|
|
510
|
+
* Note: Custom class instances (e.g. `new Error()`) that pass `isRecord` are
|
|
511
|
+
* accepted. Because `Error.prototype.message` is non-enumerable, two Error
|
|
512
|
+
* objects with different messages will compare as equal. Callers should not
|
|
513
|
+
* rely on this function for types with non-enumerable significant state.
|
|
514
|
+
*/
|
|
515
|
+
function isRecordEqual(a, b, stack) {
|
|
516
|
+
if (!isRecord(b)) return false;
|
|
517
|
+
const keysA = Object.keys(a);
|
|
518
|
+
const keysB = Object.keys(b);
|
|
519
|
+
if (keysA.length !== keysB.length) return false;
|
|
520
|
+
for (const key of keysA) {
|
|
521
|
+
if (!Object.hasOwn(b, key)) return false;
|
|
522
|
+
if (!deepEqualInner(a[key], b[key], stack)) return false;
|
|
523
|
+
}
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Map keys are compared by reference (SameValueZero), not by deep equality.
|
|
528
|
+
* Two Maps with structurally equal but referentially different object keys
|
|
529
|
+
* will be considered unequal.
|
|
530
|
+
*/
|
|
531
|
+
function isMapEqual$1(a, b, stack) {
|
|
532
|
+
if (!(b instanceof Map)) return false;
|
|
533
|
+
if (a.size !== b.size) return false;
|
|
534
|
+
for (const [key, valA] of a) {
|
|
535
|
+
if (!b.has(key)) return false;
|
|
536
|
+
if (!deepEqualInner(valA, b.get(key), stack)) return false;
|
|
537
|
+
}
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
function isPrimitiveSet(s) {
|
|
541
|
+
for (const val of s) {
|
|
542
|
+
if (val !== null && typeof val === "object") return false;
|
|
543
|
+
if (typeof val === "function") return false;
|
|
544
|
+
}
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
function isSetEqual(a, b, stack) {
|
|
548
|
+
if (!(b instanceof Set)) return false;
|
|
549
|
+
if (a.size !== b.size) return false;
|
|
550
|
+
if (isPrimitiveSet(a) && isPrimitiveSet(b)) {
|
|
551
|
+
for (const val of a) if (!b.has(val)) return false;
|
|
552
|
+
return true;
|
|
553
|
+
}
|
|
554
|
+
const remaining = [...b];
|
|
555
|
+
for (const valA of a) {
|
|
556
|
+
const stackLen = stack.length;
|
|
557
|
+
const idx = remaining.findIndex((valB) => {
|
|
558
|
+
const result = deepEqualInner(valA, valB, stack);
|
|
559
|
+
if (!result) stack.length = stackLen;
|
|
560
|
+
return result;
|
|
561
|
+
});
|
|
562
|
+
if (idx === -1) return false;
|
|
563
|
+
remaining.splice(idx, 1);
|
|
564
|
+
}
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
function compareDateOrRegExp(objA, objB) {
|
|
568
|
+
if (objA instanceof Date && objB instanceof Date) {
|
|
569
|
+
const ta = objA.getTime();
|
|
570
|
+
const tb = objB.getTime();
|
|
571
|
+
return ta === tb || Number.isNaN(ta) && Number.isNaN(tb);
|
|
572
|
+
}
|
|
573
|
+
if (objA instanceof Date || objB instanceof Date) return false;
|
|
574
|
+
if (objA instanceof RegExp && objB instanceof RegExp) return String(objA) === String(objB);
|
|
575
|
+
if (objA instanceof RegExp || objB instanceof RegExp) return false;
|
|
576
|
+
}
|
|
577
|
+
function compareCollectionOrRecord(objA, objB, stack) {
|
|
578
|
+
if (Array.isArray(objA)) return isArrayEqual(objA, objB, stack);
|
|
579
|
+
if (objA instanceof Map) return isMapEqual$1(objA, objB, stack);
|
|
580
|
+
if (objB instanceof Map) return false;
|
|
581
|
+
if (objA instanceof Set) return isSetEqual(objA, objB, stack);
|
|
582
|
+
if (objB instanceof Set) return false;
|
|
583
|
+
if (isRecord(objA)) return isRecordEqual(objA, objB, stack);
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
function deepEqualInner(a, b, stack) {
|
|
587
|
+
if (a === b) return true;
|
|
588
|
+
if (typeof a === "number" && typeof b === "number" && Number.isNaN(a) && Number.isNaN(b)) return true;
|
|
589
|
+
if (a === null || b === null) return a === b;
|
|
590
|
+
if (typeof a !== typeof b) return false;
|
|
591
|
+
if (typeof a !== "object") return false;
|
|
592
|
+
const objA = a;
|
|
593
|
+
const objB = b;
|
|
594
|
+
const dateRegExpResult = compareDateOrRegExp(objA, objB);
|
|
595
|
+
if (dateRegExpResult !== void 0) return dateRegExpResult;
|
|
596
|
+
for (const [sa, sb] of stack) if (sa === objA && sb === objB) return true;
|
|
597
|
+
stack.push([objA, objB]);
|
|
598
|
+
try {
|
|
599
|
+
return compareCollectionOrRecord(objA, objB, stack);
|
|
600
|
+
} finally {
|
|
601
|
+
stack.pop();
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Deep equality comparison for structured data.
|
|
606
|
+
* Supports primitives, plain objects, arrays, Date, RegExp, Map, and Set.
|
|
607
|
+
*
|
|
608
|
+
* Note: `{ a: undefined }` and `{}` are NOT considered equal. This differs from
|
|
609
|
+
* JSON.stringify behavior but is intentional — explicit undefined properties are
|
|
610
|
+
* semantically distinct from absent properties.
|
|
611
|
+
*
|
|
612
|
+
* Set comparison is order-independent: each element in one set is matched to an
|
|
613
|
+
* element in the other using deep equality (O(n²) for non-primitive elements,
|
|
614
|
+
* O(n) fast path for primitive-only sets).
|
|
615
|
+
*
|
|
616
|
+
* Map keys are compared by reference (SameValueZero), not by deep equality.
|
|
617
|
+
* Two Maps with structurally equal but referentially different object keys
|
|
618
|
+
* will be considered unequal.
|
|
619
|
+
*
|
|
620
|
+
* NaN handling: `deepEqual(NaN, NaN)` returns `true`. Invalid Date objects
|
|
621
|
+
* (whose `getTime()` returns NaN) are also considered equal to each other.
|
|
622
|
+
*
|
|
623
|
+
* Signed zero: `-0` and `0` are considered equal (`-0 === 0` is `true`).
|
|
624
|
+
*
|
|
625
|
+
* Circular reference handling: uses a stack-based pair tracker. When the same
|
|
626
|
+
* `(objA, objB)` pair is encountered again on the current comparison path,
|
|
627
|
+
* structural equality is assumed to break the cycle. Shared references (DAG
|
|
628
|
+
* structures) are correctly handled — the same sub-object appearing in multiple
|
|
629
|
+
* properties does not cause false negatives.
|
|
630
|
+
*/
|
|
631
|
+
function deepEqual(a, b) {
|
|
632
|
+
return deepEqualInner(a, b, []);
|
|
633
|
+
}
|
|
634
|
+
//#endregion
|
|
635
|
+
//#region src/core/domain/diff.ts
|
|
636
|
+
const typeOrder = {
|
|
637
|
+
added: 0,
|
|
638
|
+
modified: 1,
|
|
639
|
+
deleted: 2
|
|
640
|
+
};
|
|
641
|
+
function buildDiffResult(entries, warnings = []) {
|
|
642
|
+
const sorted = [...entries].sort((a, b) => typeOrder[a.type] - typeOrder[b.type]);
|
|
643
|
+
let added = 0;
|
|
644
|
+
let modified = 0;
|
|
645
|
+
let deleted = 0;
|
|
646
|
+
for (const e of sorted) if (e.type === "added") added++;
|
|
647
|
+
else if (e.type === "modified") modified++;
|
|
648
|
+
else deleted++;
|
|
649
|
+
return {
|
|
650
|
+
entries: sorted,
|
|
651
|
+
summary: {
|
|
652
|
+
added,
|
|
653
|
+
modified,
|
|
654
|
+
deleted,
|
|
655
|
+
total: sorted.length
|
|
656
|
+
},
|
|
657
|
+
isEmpty: sorted.length === 0,
|
|
658
|
+
warnings
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region src/core/domain/services/recordDiffDetector.ts
|
|
663
|
+
function detectRecordDiff(localRecord, remoteRecord, callbacks) {
|
|
664
|
+
const entries = [];
|
|
665
|
+
for (const [key, localValue] of Object.entries(localRecord)) if (!Object.hasOwn(remoteRecord, key)) entries.push(callbacks.onAdded(key, localValue));
|
|
666
|
+
else {
|
|
667
|
+
const entry = callbacks.onModified(key, localValue, remoteRecord[key]);
|
|
668
|
+
if (entry !== void 0) entries.push(entry);
|
|
669
|
+
}
|
|
670
|
+
for (const [key, remoteValue] of Object.entries(remoteRecord)) if (!Object.hasOwn(localRecord, key)) entries.push(callbacks.onDeleted(key, remoteValue));
|
|
671
|
+
return entries;
|
|
672
|
+
}
|
|
673
|
+
//#endregion
|
|
674
|
+
//#region src/core/domain/action/services/diffDetector.ts
|
|
675
|
+
function compareActions$1(local, remote) {
|
|
676
|
+
const diffs = [];
|
|
677
|
+
if (local.index !== remote.index) diffs.push(`index: ${remote.index} -> ${local.index}`);
|
|
678
|
+
if (!deepEqual(local.destApp, remote.destApp)) diffs.push("destApp changed");
|
|
679
|
+
if (local.filterCond !== remote.filterCond) diffs.push("filterCond changed");
|
|
680
|
+
if (!deepEqual(local.mappings, remote.mappings)) if (local.mappings.length !== remote.mappings.length) diffs.push(`mappings: ${remote.mappings.length} -> ${local.mappings.length}`);
|
|
681
|
+
else diffs.push("mappings changed");
|
|
682
|
+
if (!deepEqual(local.entities, remote.entities)) diffs.push("entities changed");
|
|
683
|
+
return diffs;
|
|
684
|
+
}
|
|
685
|
+
function destAppLabel(action) {
|
|
686
|
+
return `dest: ${action.destApp.app ?? action.destApp.code ?? "(unspecified)"}`;
|
|
687
|
+
}
|
|
688
|
+
const ActionDiffDetector = { detect: (local, remote) => {
|
|
689
|
+
return buildDiffResult(detectRecordDiff(local.actions, remote.actions, {
|
|
690
|
+
onAdded: (name, localAction) => ({
|
|
691
|
+
type: "added",
|
|
692
|
+
actionName: name,
|
|
693
|
+
details: destAppLabel(localAction)
|
|
694
|
+
}),
|
|
695
|
+
onModified: (name, localAction, remoteAction) => {
|
|
696
|
+
const diffs = compareActions$1(localAction, remoteAction);
|
|
697
|
+
if (diffs.length > 0) return {
|
|
698
|
+
type: "modified",
|
|
699
|
+
actionName: name,
|
|
700
|
+
details: diffs.join(", ")
|
|
701
|
+
};
|
|
702
|
+
},
|
|
703
|
+
onDeleted: (name, remoteAction) => ({
|
|
704
|
+
type: "deleted",
|
|
705
|
+
actionName: name,
|
|
706
|
+
details: destAppLabel(remoteAction)
|
|
707
|
+
})
|
|
708
|
+
}));
|
|
709
|
+
} };
|
|
710
|
+
//#endregion
|
|
711
|
+
//#region src/core/application/detectDiffBase.ts
|
|
712
|
+
async function detectDiffFromConfig(config) {
|
|
713
|
+
const [storageResult, remote] = await Promise.all([config.getStorage(), config.fetchRemote()]);
|
|
714
|
+
if (!storageResult.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, config.notFoundMessage);
|
|
715
|
+
const local = config.parseConfig(storageResult.content);
|
|
716
|
+
return config.detect(local, remote);
|
|
717
|
+
}
|
|
718
|
+
//#endregion
|
|
719
|
+
//#region src/core/application/action/detectActionDiff.ts
|
|
720
|
+
async function detectActionDiff({ container }) {
|
|
721
|
+
return detectDiffFromConfig({
|
|
722
|
+
getStorage: () => container.actionStorage.get(),
|
|
723
|
+
fetchRemote: () => container.actionConfigurator.getActions(),
|
|
724
|
+
parseConfig: (content) => parseActionConfigText(container.configCodec, content),
|
|
725
|
+
detect: (local, remote) => ActionDiffDetector.detect(local, { actions: remote.actions }),
|
|
726
|
+
notFoundMessage: "Action config file not found"
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
//#endregion
|
|
500
730
|
//#region src/core/adapters/kintone/wrapKintoneError.ts
|
|
501
731
|
const KINTONE_REVISION_CONFLICT_CODE = "GAIA_CO02";
|
|
502
732
|
const KINTONE_MAINTENANCE_MODE_CODE = "GAIA_NO02";
|
|
@@ -2508,9 +2738,27 @@ const { resolveFilePath: resolveActionFilePath, resolveContainerConfig: resolveA
|
|
|
2508
2738
|
//#endregion
|
|
2509
2739
|
//#region src/cli/commands/applyCommandFactory.ts
|
|
2510
2740
|
function createApplyCommand(config) {
|
|
2511
|
-
async function
|
|
2741
|
+
async function runDiffPreview(containerConfig, diffPreview) {
|
|
2512
2742
|
const container = config.createContainer(containerConfig);
|
|
2513
2743
|
const s = p.spinner();
|
|
2744
|
+
s.start("Detecting changes...");
|
|
2745
|
+
let result;
|
|
2746
|
+
try {
|
|
2747
|
+
result = await diffPreview.detectDiff({ container });
|
|
2748
|
+
} catch (error) {
|
|
2749
|
+
s.stop("Comparison failed.");
|
|
2750
|
+
throw error;
|
|
2751
|
+
}
|
|
2752
|
+
s.stop("Comparison complete.");
|
|
2753
|
+
diffPreview.printResult(result);
|
|
2754
|
+
return {
|
|
2755
|
+
container,
|
|
2756
|
+
hasChanges: !result.isEmpty
|
|
2757
|
+
};
|
|
2758
|
+
}
|
|
2759
|
+
async function runApply(containerConfig, existingContainer) {
|
|
2760
|
+
const container = existingContainer ?? config.createContainer(containerConfig);
|
|
2761
|
+
const s = p.spinner();
|
|
2514
2762
|
s.start(config.spinnerMessage);
|
|
2515
2763
|
let result;
|
|
2516
2764
|
try {
|
|
@@ -2537,21 +2785,91 @@ function createApplyCommand(config) {
|
|
|
2537
2785
|
const skipConfirm = ctx.values.yes === true;
|
|
2538
2786
|
await routeMultiApp(values, {
|
|
2539
2787
|
singleLegacy: async () => {
|
|
2540
|
-
|
|
2788
|
+
const containerConfig = config.resolveContainerConfig(values);
|
|
2789
|
+
if (config.diffPreview) {
|
|
2790
|
+
const { container, hasChanges } = await runDiffPreview(containerConfig, config.diffPreview);
|
|
2791
|
+
if (!hasChanges) {
|
|
2792
|
+
p.log.success("No changes detected.");
|
|
2793
|
+
return;
|
|
2794
|
+
}
|
|
2795
|
+
if (!skipConfirm) {
|
|
2796
|
+
const shouldContinue = await p.confirm({ message: "Apply these changes?" });
|
|
2797
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
2798
|
+
p.cancel("Apply cancelled.");
|
|
2799
|
+
return;
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
await confirmAndDeploy([await runApply(containerConfig, container)], skipConfirm);
|
|
2803
|
+
} else await confirmAndDeploy([await runApply(containerConfig)], skipConfirm);
|
|
2541
2804
|
},
|
|
2542
2805
|
singleApp: async (app, projectConfig) => {
|
|
2543
|
-
|
|
2806
|
+
const containerConfig = config.resolveAppContainerConfig(app, projectConfig, values);
|
|
2807
|
+
if (config.diffPreview) {
|
|
2808
|
+
const { container, hasChanges } = await runDiffPreview(containerConfig, config.diffPreview);
|
|
2809
|
+
if (!hasChanges) {
|
|
2810
|
+
p.log.success("No changes detected.");
|
|
2811
|
+
return;
|
|
2812
|
+
}
|
|
2813
|
+
if (!skipConfirm) {
|
|
2814
|
+
const shouldContinue = await p.confirm({ message: "Apply these changes?" });
|
|
2815
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
2816
|
+
p.cancel("Apply cancelled.");
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
await confirmAndDeploy([await runApply(containerConfig, container)], skipConfirm);
|
|
2821
|
+
} else await confirmAndDeploy([await runApply(containerConfig)], skipConfirm);
|
|
2544
2822
|
},
|
|
2545
2823
|
multiApp: async (plan, projectConfig) => {
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
const
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2824
|
+
if (config.diffPreview) {
|
|
2825
|
+
const appDiffResults = [];
|
|
2826
|
+
for (const app of plan.orderedApps) {
|
|
2827
|
+
const containerConfig = config.resolveAppContainerConfig(app, projectConfig, values);
|
|
2828
|
+
printAppHeader(app.name, app.appId);
|
|
2829
|
+
const { container, hasChanges } = await runDiffPreview(containerConfig, config.diffPreview);
|
|
2830
|
+
appDiffResults.push({
|
|
2831
|
+
app,
|
|
2832
|
+
container,
|
|
2833
|
+
hasChanges
|
|
2834
|
+
});
|
|
2835
|
+
}
|
|
2836
|
+
if (!appDiffResults.some((a) => a.hasChanges)) {
|
|
2837
|
+
p.log.success("No changes detected in any app.");
|
|
2838
|
+
return;
|
|
2839
|
+
}
|
|
2840
|
+
if (!skipConfirm) {
|
|
2841
|
+
const shouldContinue = await p.confirm({ message: "Apply these changes to all apps?" });
|
|
2842
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
2843
|
+
p.cancel("Apply cancelled.");
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
const containers = [];
|
|
2848
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
2849
|
+
const entry = appDiffResults.find((a) => a.app.name === app.name);
|
|
2850
|
+
if (!entry) throw new SystemError(SystemErrorCode.InternalServerError, `App container not found for "${app.name}"`);
|
|
2851
|
+
if (!entry.hasChanges) {
|
|
2852
|
+
p.log.info("No changes. Skipping.");
|
|
2853
|
+
return;
|
|
2854
|
+
}
|
|
2855
|
+
await runApply(config.resolveAppContainerConfig(app, projectConfig, values), entry.container);
|
|
2856
|
+
containers.push({
|
|
2857
|
+
appDeployer: entry.container.appDeployer,
|
|
2858
|
+
appName: app.name
|
|
2859
|
+
});
|
|
2552
2860
|
});
|
|
2553
|
-
|
|
2554
|
-
|
|
2861
|
+
await confirmAndDeploy(containers, skipConfirm);
|
|
2862
|
+
} else {
|
|
2863
|
+
const containers = [];
|
|
2864
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
2865
|
+
const container = await runApply(config.resolveAppContainerConfig(app, projectConfig, values));
|
|
2866
|
+
containers.push({
|
|
2867
|
+
appDeployer: container.appDeployer,
|
|
2868
|
+
appName: app.name
|
|
2869
|
+
});
|
|
2870
|
+
});
|
|
2871
|
+
await confirmAndDeploy(containers, skipConfirm);
|
|
2872
|
+
}
|
|
2555
2873
|
}
|
|
2556
2874
|
});
|
|
2557
2875
|
} catch (error) {
|
|
@@ -2570,6 +2888,10 @@ var apply_default$12 = createApplyCommand({
|
|
|
2570
2888
|
successMessage: "Action settings applied successfully.",
|
|
2571
2889
|
createContainer: createActionCliContainer,
|
|
2572
2890
|
applyFn: applyAction,
|
|
2891
|
+
diffPreview: {
|
|
2892
|
+
detectDiff: detectActionDiff,
|
|
2893
|
+
printResult: printActionDiffResult
|
|
2894
|
+
},
|
|
2573
2895
|
resolveContainerConfig: resolveActionContainerConfig,
|
|
2574
2896
|
resolveAppContainerConfig: resolveActionAppContainerConfig
|
|
2575
2897
|
});
|
|
@@ -2710,236 +3032,6 @@ var capture_default$13 = createCaptureCommand({
|
|
|
2710
3032
|
resolveAppContainerConfig: resolveActionAppContainerConfig
|
|
2711
3033
|
});
|
|
2712
3034
|
//#endregion
|
|
2713
|
-
//#region src/lib/deepEqual.ts
|
|
2714
|
-
function isArrayEqual(a, b, stack) {
|
|
2715
|
-
if (!Array.isArray(b)) return false;
|
|
2716
|
-
if (a.length !== b.length) return false;
|
|
2717
|
-
for (let i = 0; i < a.length; i++) if (!deepEqualInner(a[i], b[i], stack)) return false;
|
|
2718
|
-
return true;
|
|
2719
|
-
}
|
|
2720
|
-
/**
|
|
2721
|
-
* Compare two objects by own enumerable string keys (via `Object.keys`).
|
|
2722
|
-
*
|
|
2723
|
-
* Note: Custom class instances (e.g. `new Error()`) that pass `isRecord` are
|
|
2724
|
-
* accepted. Because `Error.prototype.message` is non-enumerable, two Error
|
|
2725
|
-
* objects with different messages will compare as equal. Callers should not
|
|
2726
|
-
* rely on this function for types with non-enumerable significant state.
|
|
2727
|
-
*/
|
|
2728
|
-
function isRecordEqual(a, b, stack) {
|
|
2729
|
-
if (!isRecord(b)) return false;
|
|
2730
|
-
const keysA = Object.keys(a);
|
|
2731
|
-
const keysB = Object.keys(b);
|
|
2732
|
-
if (keysA.length !== keysB.length) return false;
|
|
2733
|
-
for (const key of keysA) {
|
|
2734
|
-
if (!Object.hasOwn(b, key)) return false;
|
|
2735
|
-
if (!deepEqualInner(a[key], b[key], stack)) return false;
|
|
2736
|
-
}
|
|
2737
|
-
return true;
|
|
2738
|
-
}
|
|
2739
|
-
/**
|
|
2740
|
-
* Map keys are compared by reference (SameValueZero), not by deep equality.
|
|
2741
|
-
* Two Maps with structurally equal but referentially different object keys
|
|
2742
|
-
* will be considered unequal.
|
|
2743
|
-
*/
|
|
2744
|
-
function isMapEqual$1(a, b, stack) {
|
|
2745
|
-
if (!(b instanceof Map)) return false;
|
|
2746
|
-
if (a.size !== b.size) return false;
|
|
2747
|
-
for (const [key, valA] of a) {
|
|
2748
|
-
if (!b.has(key)) return false;
|
|
2749
|
-
if (!deepEqualInner(valA, b.get(key), stack)) return false;
|
|
2750
|
-
}
|
|
2751
|
-
return true;
|
|
2752
|
-
}
|
|
2753
|
-
function isPrimitiveSet(s) {
|
|
2754
|
-
for (const val of s) {
|
|
2755
|
-
if (val !== null && typeof val === "object") return false;
|
|
2756
|
-
if (typeof val === "function") return false;
|
|
2757
|
-
}
|
|
2758
|
-
return true;
|
|
2759
|
-
}
|
|
2760
|
-
function isSetEqual(a, b, stack) {
|
|
2761
|
-
if (!(b instanceof Set)) return false;
|
|
2762
|
-
if (a.size !== b.size) return false;
|
|
2763
|
-
if (isPrimitiveSet(a) && isPrimitiveSet(b)) {
|
|
2764
|
-
for (const val of a) if (!b.has(val)) return false;
|
|
2765
|
-
return true;
|
|
2766
|
-
}
|
|
2767
|
-
const remaining = [...b];
|
|
2768
|
-
for (const valA of a) {
|
|
2769
|
-
const stackLen = stack.length;
|
|
2770
|
-
const idx = remaining.findIndex((valB) => {
|
|
2771
|
-
const result = deepEqualInner(valA, valB, stack);
|
|
2772
|
-
if (!result) stack.length = stackLen;
|
|
2773
|
-
return result;
|
|
2774
|
-
});
|
|
2775
|
-
if (idx === -1) return false;
|
|
2776
|
-
remaining.splice(idx, 1);
|
|
2777
|
-
}
|
|
2778
|
-
return true;
|
|
2779
|
-
}
|
|
2780
|
-
function compareDateOrRegExp(objA, objB) {
|
|
2781
|
-
if (objA instanceof Date && objB instanceof Date) {
|
|
2782
|
-
const ta = objA.getTime();
|
|
2783
|
-
const tb = objB.getTime();
|
|
2784
|
-
return ta === tb || Number.isNaN(ta) && Number.isNaN(tb);
|
|
2785
|
-
}
|
|
2786
|
-
if (objA instanceof Date || objB instanceof Date) return false;
|
|
2787
|
-
if (objA instanceof RegExp && objB instanceof RegExp) return String(objA) === String(objB);
|
|
2788
|
-
if (objA instanceof RegExp || objB instanceof RegExp) return false;
|
|
2789
|
-
}
|
|
2790
|
-
function compareCollectionOrRecord(objA, objB, stack) {
|
|
2791
|
-
if (Array.isArray(objA)) return isArrayEqual(objA, objB, stack);
|
|
2792
|
-
if (objA instanceof Map) return isMapEqual$1(objA, objB, stack);
|
|
2793
|
-
if (objB instanceof Map) return false;
|
|
2794
|
-
if (objA instanceof Set) return isSetEqual(objA, objB, stack);
|
|
2795
|
-
if (objB instanceof Set) return false;
|
|
2796
|
-
if (isRecord(objA)) return isRecordEqual(objA, objB, stack);
|
|
2797
|
-
return false;
|
|
2798
|
-
}
|
|
2799
|
-
function deepEqualInner(a, b, stack) {
|
|
2800
|
-
if (a === b) return true;
|
|
2801
|
-
if (typeof a === "number" && typeof b === "number" && Number.isNaN(a) && Number.isNaN(b)) return true;
|
|
2802
|
-
if (a === null || b === null) return a === b;
|
|
2803
|
-
if (typeof a !== typeof b) return false;
|
|
2804
|
-
if (typeof a !== "object") return false;
|
|
2805
|
-
const objA = a;
|
|
2806
|
-
const objB = b;
|
|
2807
|
-
const dateRegExpResult = compareDateOrRegExp(objA, objB);
|
|
2808
|
-
if (dateRegExpResult !== void 0) return dateRegExpResult;
|
|
2809
|
-
for (const [sa, sb] of stack) if (sa === objA && sb === objB) return true;
|
|
2810
|
-
stack.push([objA, objB]);
|
|
2811
|
-
try {
|
|
2812
|
-
return compareCollectionOrRecord(objA, objB, stack);
|
|
2813
|
-
} finally {
|
|
2814
|
-
stack.pop();
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
|
-
/**
|
|
2818
|
-
* Deep equality comparison for structured data.
|
|
2819
|
-
* Supports primitives, plain objects, arrays, Date, RegExp, Map, and Set.
|
|
2820
|
-
*
|
|
2821
|
-
* Note: `{ a: undefined }` and `{}` are NOT considered equal. This differs from
|
|
2822
|
-
* JSON.stringify behavior but is intentional — explicit undefined properties are
|
|
2823
|
-
* semantically distinct from absent properties.
|
|
2824
|
-
*
|
|
2825
|
-
* Set comparison is order-independent: each element in one set is matched to an
|
|
2826
|
-
* element in the other using deep equality (O(n²) for non-primitive elements,
|
|
2827
|
-
* O(n) fast path for primitive-only sets).
|
|
2828
|
-
*
|
|
2829
|
-
* Map keys are compared by reference (SameValueZero), not by deep equality.
|
|
2830
|
-
* Two Maps with structurally equal but referentially different object keys
|
|
2831
|
-
* will be considered unequal.
|
|
2832
|
-
*
|
|
2833
|
-
* NaN handling: `deepEqual(NaN, NaN)` returns `true`. Invalid Date objects
|
|
2834
|
-
* (whose `getTime()` returns NaN) are also considered equal to each other.
|
|
2835
|
-
*
|
|
2836
|
-
* Signed zero: `-0` and `0` are considered equal (`-0 === 0` is `true`).
|
|
2837
|
-
*
|
|
2838
|
-
* Circular reference handling: uses a stack-based pair tracker. When the same
|
|
2839
|
-
* `(objA, objB)` pair is encountered again on the current comparison path,
|
|
2840
|
-
* structural equality is assumed to break the cycle. Shared references (DAG
|
|
2841
|
-
* structures) are correctly handled — the same sub-object appearing in multiple
|
|
2842
|
-
* properties does not cause false negatives.
|
|
2843
|
-
*/
|
|
2844
|
-
function deepEqual(a, b) {
|
|
2845
|
-
return deepEqualInner(a, b, []);
|
|
2846
|
-
}
|
|
2847
|
-
//#endregion
|
|
2848
|
-
//#region src/core/domain/diff.ts
|
|
2849
|
-
const typeOrder = {
|
|
2850
|
-
added: 0,
|
|
2851
|
-
modified: 1,
|
|
2852
|
-
deleted: 2
|
|
2853
|
-
};
|
|
2854
|
-
function buildDiffResult(entries, warnings = []) {
|
|
2855
|
-
const sorted = [...entries].sort((a, b) => typeOrder[a.type] - typeOrder[b.type]);
|
|
2856
|
-
let added = 0;
|
|
2857
|
-
let modified = 0;
|
|
2858
|
-
let deleted = 0;
|
|
2859
|
-
for (const e of sorted) if (e.type === "added") added++;
|
|
2860
|
-
else if (e.type === "modified") modified++;
|
|
2861
|
-
else deleted++;
|
|
2862
|
-
return {
|
|
2863
|
-
entries: sorted,
|
|
2864
|
-
summary: {
|
|
2865
|
-
added,
|
|
2866
|
-
modified,
|
|
2867
|
-
deleted,
|
|
2868
|
-
total: sorted.length
|
|
2869
|
-
},
|
|
2870
|
-
isEmpty: sorted.length === 0,
|
|
2871
|
-
warnings
|
|
2872
|
-
};
|
|
2873
|
-
}
|
|
2874
|
-
//#endregion
|
|
2875
|
-
//#region src/core/domain/services/recordDiffDetector.ts
|
|
2876
|
-
function detectRecordDiff(localRecord, remoteRecord, callbacks) {
|
|
2877
|
-
const entries = [];
|
|
2878
|
-
for (const [key, localValue] of Object.entries(localRecord)) if (!Object.hasOwn(remoteRecord, key)) entries.push(callbacks.onAdded(key, localValue));
|
|
2879
|
-
else {
|
|
2880
|
-
const entry = callbacks.onModified(key, localValue, remoteRecord[key]);
|
|
2881
|
-
if (entry !== void 0) entries.push(entry);
|
|
2882
|
-
}
|
|
2883
|
-
for (const [key, remoteValue] of Object.entries(remoteRecord)) if (!Object.hasOwn(localRecord, key)) entries.push(callbacks.onDeleted(key, remoteValue));
|
|
2884
|
-
return entries;
|
|
2885
|
-
}
|
|
2886
|
-
//#endregion
|
|
2887
|
-
//#region src/core/domain/action/services/diffDetector.ts
|
|
2888
|
-
function compareActions$1(local, remote) {
|
|
2889
|
-
const diffs = [];
|
|
2890
|
-
if (local.index !== remote.index) diffs.push(`index: ${remote.index} -> ${local.index}`);
|
|
2891
|
-
if (!deepEqual(local.destApp, remote.destApp)) diffs.push("destApp changed");
|
|
2892
|
-
if (local.filterCond !== remote.filterCond) diffs.push("filterCond changed");
|
|
2893
|
-
if (!deepEqual(local.mappings, remote.mappings)) if (local.mappings.length !== remote.mappings.length) diffs.push(`mappings: ${remote.mappings.length} -> ${local.mappings.length}`);
|
|
2894
|
-
else diffs.push("mappings changed");
|
|
2895
|
-
if (!deepEqual(local.entities, remote.entities)) diffs.push("entities changed");
|
|
2896
|
-
return diffs;
|
|
2897
|
-
}
|
|
2898
|
-
function destAppLabel(action) {
|
|
2899
|
-
return `dest: ${action.destApp.app ?? action.destApp.code ?? "(unspecified)"}`;
|
|
2900
|
-
}
|
|
2901
|
-
const ActionDiffDetector = { detect: (local, remote) => {
|
|
2902
|
-
return buildDiffResult(detectRecordDiff(local.actions, remote.actions, {
|
|
2903
|
-
onAdded: (name, localAction) => ({
|
|
2904
|
-
type: "added",
|
|
2905
|
-
actionName: name,
|
|
2906
|
-
details: destAppLabel(localAction)
|
|
2907
|
-
}),
|
|
2908
|
-
onModified: (name, localAction, remoteAction) => {
|
|
2909
|
-
const diffs = compareActions$1(localAction, remoteAction);
|
|
2910
|
-
if (diffs.length > 0) return {
|
|
2911
|
-
type: "modified",
|
|
2912
|
-
actionName: name,
|
|
2913
|
-
details: diffs.join(", ")
|
|
2914
|
-
};
|
|
2915
|
-
},
|
|
2916
|
-
onDeleted: (name, remoteAction) => ({
|
|
2917
|
-
type: "deleted",
|
|
2918
|
-
actionName: name,
|
|
2919
|
-
details: destAppLabel(remoteAction)
|
|
2920
|
-
})
|
|
2921
|
-
}));
|
|
2922
|
-
} };
|
|
2923
|
-
//#endregion
|
|
2924
|
-
//#region src/core/application/detectDiffBase.ts
|
|
2925
|
-
async function detectDiffFromConfig(config) {
|
|
2926
|
-
const [storageResult, remote] = await Promise.all([config.getStorage(), config.fetchRemote()]);
|
|
2927
|
-
if (!storageResult.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, config.notFoundMessage);
|
|
2928
|
-
const local = config.parseConfig(storageResult.content);
|
|
2929
|
-
return config.detect(local, remote);
|
|
2930
|
-
}
|
|
2931
|
-
//#endregion
|
|
2932
|
-
//#region src/core/application/action/detectActionDiff.ts
|
|
2933
|
-
async function detectActionDiff({ container }) {
|
|
2934
|
-
return detectDiffFromConfig({
|
|
2935
|
-
getStorage: () => container.actionStorage.get(),
|
|
2936
|
-
fetchRemote: () => container.actionConfigurator.getActions(),
|
|
2937
|
-
parseConfig: (content) => parseActionConfigText(container.configCodec, content),
|
|
2938
|
-
detect: (local, remote) => ActionDiffDetector.detect(local, { actions: remote.actions }),
|
|
2939
|
-
notFoundMessage: "Action config file not found"
|
|
2940
|
-
});
|
|
2941
|
-
}
|
|
2942
|
-
//#endregion
|
|
2943
3035
|
//#region src/cli/commands/diffCommandFactory.ts
|
|
2944
3036
|
function createDiffCommand(config) {
|
|
2945
3037
|
async function runDiff(containerConfig) {
|
|
@@ -3040,6 +3132,41 @@ async function applyAdminNotes({ container }) {
|
|
|
3040
3132
|
});
|
|
3041
3133
|
}
|
|
3042
3134
|
//#endregion
|
|
3135
|
+
//#region src/core/domain/adminNotes/services/diffDetector.ts
|
|
3136
|
+
const CONTENT_TRUNCATE_LENGTH = 30;
|
|
3137
|
+
function truncate(text, maxLength) {
|
|
3138
|
+
if (text.length <= maxLength) return text;
|
|
3139
|
+
return `${text.slice(0, maxLength)}...`;
|
|
3140
|
+
}
|
|
3141
|
+
function compareConfigs$2(local, remote) {
|
|
3142
|
+
const entries = [];
|
|
3143
|
+
if (local.content !== remote.content) entries.push({
|
|
3144
|
+
type: "modified",
|
|
3145
|
+
field: "content",
|
|
3146
|
+
details: `"${truncate(remote.content, CONTENT_TRUNCATE_LENGTH)}" -> "${truncate(local.content, CONTENT_TRUNCATE_LENGTH)}"`
|
|
3147
|
+
});
|
|
3148
|
+
if (local.includeInTemplateAndDuplicates !== remote.includeInTemplateAndDuplicates) entries.push({
|
|
3149
|
+
type: "modified",
|
|
3150
|
+
field: "includeInTemplateAndDuplicates",
|
|
3151
|
+
details: `${String(remote.includeInTemplateAndDuplicates)} -> ${String(local.includeInTemplateAndDuplicates)}`
|
|
3152
|
+
});
|
|
3153
|
+
return entries;
|
|
3154
|
+
}
|
|
3155
|
+
const AdminNotesDiffDetector = { detect: (local, remote) => {
|
|
3156
|
+
return buildDiffResult(compareConfigs$2(local, remote));
|
|
3157
|
+
} };
|
|
3158
|
+
//#endregion
|
|
3159
|
+
//#region src/core/application/adminNotes/detectAdminNotesDiff.ts
|
|
3160
|
+
async function detectAdminNotesDiff({ container }) {
|
|
3161
|
+
return detectDiffFromConfig({
|
|
3162
|
+
getStorage: () => container.adminNotesStorage.get(),
|
|
3163
|
+
fetchRemote: () => container.adminNotesConfigurator.getAdminNotes(),
|
|
3164
|
+
parseConfig: (content) => parseAdminNotesConfigText(container.configCodec, content),
|
|
3165
|
+
detect: (local, remote) => AdminNotesDiffDetector.detect(local, remote.config),
|
|
3166
|
+
notFoundMessage: "Admin notes config file not found"
|
|
3167
|
+
});
|
|
3168
|
+
}
|
|
3169
|
+
//#endregion
|
|
3043
3170
|
//#region src/core/adapters/kintone/adminNotesConfigurator.ts
|
|
3044
3171
|
var KintoneAdminNotesConfigurator = class {
|
|
3045
3172
|
constructor(client, appId) {
|
|
@@ -3124,6 +3251,10 @@ var apply_default$11 = createApplyCommand({
|
|
|
3124
3251
|
successMessage: "Admin notes applied successfully.",
|
|
3125
3252
|
createContainer: createAdminNotesCliContainer,
|
|
3126
3253
|
applyFn: applyAdminNotes,
|
|
3254
|
+
diffPreview: {
|
|
3255
|
+
detectDiff: detectAdminNotesDiff,
|
|
3256
|
+
printResult: printAdminNotesDiffResult
|
|
3257
|
+
},
|
|
3127
3258
|
resolveContainerConfig: resolveAdminNotesContainerConfig,
|
|
3128
3259
|
resolveAppContainerConfig: resolveAdminNotesAppContainerConfig
|
|
3129
3260
|
});
|
|
@@ -3150,59 +3281,26 @@ async function saveAdminNotes({ container, input }) {
|
|
|
3150
3281
|
await container.adminNotesStorage.update(input.configText);
|
|
3151
3282
|
}
|
|
3152
3283
|
//#endregion
|
|
3153
|
-
//#region src/cli/commands/admin-notes/capture.ts
|
|
3154
|
-
var capture_default$12 = createCaptureCommand({
|
|
3155
|
-
description: "Capture current admin notes from kintone app to file",
|
|
3156
|
-
args: adminNotesArgs,
|
|
3157
|
-
spinnerMessage: "Capturing admin notes...",
|
|
3158
|
-
spinnerStopMessage: "Admin notes captured.",
|
|
3159
|
-
domainLabel: "Admin notes",
|
|
3160
|
-
multiAppSuccessMessage: "All admin notes captures completed successfully.",
|
|
3161
|
-
createContainer: createAdminNotesCliContainer,
|
|
3162
|
-
captureFn: captureAdminNotes,
|
|
3163
|
-
saveFn: saveAdminNotes,
|
|
3164
|
-
getConfigFilePath: (config) => config.adminNotesFilePath,
|
|
3165
|
-
resolveContainerConfig: resolveAdminNotesContainerConfig,
|
|
3166
|
-
resolveAppContainerConfig: resolveAdminNotesAppContainerConfig
|
|
3167
|
-
});
|
|
3168
|
-
//#endregion
|
|
3169
|
-
//#region src/core/domain/adminNotes/services/diffDetector.ts
|
|
3170
|
-
function compareConfigs$2(local, remote) {
|
|
3171
|
-
const entries = [];
|
|
3172
|
-
if (local.content !== remote.content) entries.push({
|
|
3173
|
-
type: "modified",
|
|
3174
|
-
field: "content",
|
|
3175
|
-
details: "content changed"
|
|
3176
|
-
});
|
|
3177
|
-
if (local.includeInTemplateAndDuplicates !== remote.includeInTemplateAndDuplicates) entries.push({
|
|
3178
|
-
type: "modified",
|
|
3179
|
-
field: "includeInTemplateAndDuplicates",
|
|
3180
|
-
details: `${String(remote.includeInTemplateAndDuplicates)} -> ${String(local.includeInTemplateAndDuplicates)}`
|
|
3181
|
-
});
|
|
3182
|
-
return entries;
|
|
3183
|
-
}
|
|
3184
|
-
const AdminNotesDiffDetector = { detect: (local, remote) => {
|
|
3185
|
-
return buildDiffResult(compareConfigs$2(local, remote));
|
|
3186
|
-
} };
|
|
3187
|
-
//#endregion
|
|
3188
|
-
//#region src/core/application/adminNotes/detectAdminNotesDiff.ts
|
|
3189
|
-
async function detectAdminNotesDiff({ container }) {
|
|
3190
|
-
return detectDiffFromConfig({
|
|
3191
|
-
getStorage: () => container.adminNotesStorage.get(),
|
|
3192
|
-
fetchRemote: () => container.adminNotesConfigurator.getAdminNotes(),
|
|
3193
|
-
parseConfig: (content) => parseAdminNotesConfigText(container.configCodec, content),
|
|
3194
|
-
detect: (local, remote) => AdminNotesDiffDetector.detect(local, remote.config),
|
|
3195
|
-
notFoundMessage: "Admin notes config file not found"
|
|
3196
|
-
});
|
|
3197
|
-
}
|
|
3198
|
-
//#endregion
|
|
3199
3284
|
//#region src/cli/commands/admin-notes/index.ts
|
|
3200
3285
|
var admin_notes_default = define({
|
|
3201
3286
|
name: "admin-notes",
|
|
3202
3287
|
description: "Manage kintone admin notes",
|
|
3203
3288
|
subCommands: {
|
|
3204
3289
|
apply: apply_default$11,
|
|
3205
|
-
capture:
|
|
3290
|
+
capture: createCaptureCommand({
|
|
3291
|
+
description: "Capture current admin notes from kintone app to file",
|
|
3292
|
+
args: adminNotesArgs,
|
|
3293
|
+
spinnerMessage: "Capturing admin notes...",
|
|
3294
|
+
spinnerStopMessage: "Admin notes captured.",
|
|
3295
|
+
domainLabel: "Admin notes",
|
|
3296
|
+
multiAppSuccessMessage: "All admin notes captures completed successfully.",
|
|
3297
|
+
createContainer: createAdminNotesCliContainer,
|
|
3298
|
+
captureFn: captureAdminNotes,
|
|
3299
|
+
saveFn: saveAdminNotes,
|
|
3300
|
+
getConfigFilePath: (config) => config.adminNotesFilePath,
|
|
3301
|
+
resolveContainerConfig: resolveAdminNotesContainerConfig,
|
|
3302
|
+
resolveAppContainerConfig: resolveAdminNotesAppContainerConfig
|
|
3303
|
+
}),
|
|
3206
3304
|
diff: createDiffCommand({
|
|
3207
3305
|
description: "Compare local admin notes config with remote kintone app",
|
|
3208
3306
|
args: adminNotesArgs,
|
|
@@ -3281,6 +3379,68 @@ async function applyAppPermission({ container }) {
|
|
|
3281
3379
|
});
|
|
3282
3380
|
}
|
|
3283
3381
|
//#endregion
|
|
3382
|
+
//#region src/core/domain/appPermission/services/diffDetector.ts
|
|
3383
|
+
const BOOLEAN_FLAGS = [
|
|
3384
|
+
"includeSubs",
|
|
3385
|
+
"appEditable",
|
|
3386
|
+
"recordViewable",
|
|
3387
|
+
"recordAddable",
|
|
3388
|
+
"recordEditable",
|
|
3389
|
+
"recordDeletable",
|
|
3390
|
+
"recordImportable",
|
|
3391
|
+
"recordExportable"
|
|
3392
|
+
];
|
|
3393
|
+
function entityKey(right) {
|
|
3394
|
+
return `${right.entity.type}:${right.entity.code}`;
|
|
3395
|
+
}
|
|
3396
|
+
function describeRight$1(right) {
|
|
3397
|
+
const flags = BOOLEAN_FLAGS.filter((f) => f !== "includeSubs" && right[f]);
|
|
3398
|
+
return flags.length > 0 ? flags.join(", ") : "no permissions";
|
|
3399
|
+
}
|
|
3400
|
+
function compareRights(local, remote) {
|
|
3401
|
+
const diffs = [];
|
|
3402
|
+
for (const flag of BOOLEAN_FLAGS) if (local[flag] !== remote[flag]) diffs.push(`${flag}: ${String(remote[flag])} -> ${String(local[flag])}`);
|
|
3403
|
+
return diffs;
|
|
3404
|
+
}
|
|
3405
|
+
const AppPermissionDiffDetector = { detect: (local, remote) => {
|
|
3406
|
+
const entries = [];
|
|
3407
|
+
const localMap = new Map(local.rights.map((r) => [entityKey(r), r]));
|
|
3408
|
+
const remoteMap = new Map(remote.rights.map((r) => [entityKey(r), r]));
|
|
3409
|
+
for (const [key, localRight] of localMap) {
|
|
3410
|
+
const remoteRight = remoteMap.get(key);
|
|
3411
|
+
if (!remoteRight) entries.push({
|
|
3412
|
+
type: "added",
|
|
3413
|
+
entityKey: key,
|
|
3414
|
+
details: describeRight$1(localRight)
|
|
3415
|
+
});
|
|
3416
|
+
else {
|
|
3417
|
+
const diffs = compareRights(localRight, remoteRight);
|
|
3418
|
+
if (diffs.length > 0) entries.push({
|
|
3419
|
+
type: "modified",
|
|
3420
|
+
entityKey: key,
|
|
3421
|
+
details: diffs.join(", ")
|
|
3422
|
+
});
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
for (const [key, remoteRight] of remoteMap) if (!localMap.has(key)) entries.push({
|
|
3426
|
+
type: "deleted",
|
|
3427
|
+
entityKey: key,
|
|
3428
|
+
details: describeRight$1(remoteRight)
|
|
3429
|
+
});
|
|
3430
|
+
return buildDiffResult(entries);
|
|
3431
|
+
} };
|
|
3432
|
+
//#endregion
|
|
3433
|
+
//#region src/core/application/appPermission/detectAppPermissionDiff.ts
|
|
3434
|
+
async function detectAppPermissionDiff({ container }) {
|
|
3435
|
+
return detectDiffFromConfig({
|
|
3436
|
+
getStorage: () => container.appPermissionStorage.get(),
|
|
3437
|
+
fetchRemote: () => container.appPermissionConfigurator.getAppPermissions(),
|
|
3438
|
+
parseConfig: (content) => parseAppPermissionConfigText(container.configCodec, content),
|
|
3439
|
+
detect: (local, remote) => AppPermissionDiffDetector.detect(local, { rights: remote.rights }),
|
|
3440
|
+
notFoundMessage: "App permission config file not found"
|
|
3441
|
+
});
|
|
3442
|
+
}
|
|
3443
|
+
//#endregion
|
|
3284
3444
|
//#region src/core/adapters/kintone/appPermissionConfigurator.ts
|
|
3285
3445
|
const VALID_ENTITY_TYPES$7 = new Set([
|
|
3286
3446
|
"USER",
|
|
@@ -3407,6 +3567,10 @@ var apply_default$10 = createApplyCommand({
|
|
|
3407
3567
|
successMessage: "App access permissions applied successfully.",
|
|
3408
3568
|
createContainer: createAppPermissionCliContainer,
|
|
3409
3569
|
applyFn: applyAppPermission,
|
|
3570
|
+
diffPreview: {
|
|
3571
|
+
detectDiff: detectAppPermissionDiff,
|
|
3572
|
+
printResult: printAppPermissionDiffResult
|
|
3573
|
+
},
|
|
3410
3574
|
resolveContainerConfig: resolveAppAclContainerConfig,
|
|
3411
3575
|
resolveAppContainerConfig: resolveAppAclAppContainerConfig
|
|
3412
3576
|
});
|
|
@@ -3416,121 +3580,56 @@ function serializeAppRight(right) {
|
|
|
3416
3580
|
return {
|
|
3417
3581
|
entity: {
|
|
3418
3582
|
type: right.entity.type,
|
|
3419
|
-
code: right.entity.code
|
|
3420
|
-
},
|
|
3421
|
-
includeSubs: right.includeSubs,
|
|
3422
|
-
appEditable: right.appEditable,
|
|
3423
|
-
recordViewable: right.recordViewable,
|
|
3424
|
-
recordAddable: right.recordAddable,
|
|
3425
|
-
recordEditable: right.recordEditable,
|
|
3426
|
-
recordDeletable: right.recordDeletable,
|
|
3427
|
-
recordImportable: right.recordImportable,
|
|
3428
|
-
recordExportable: right.recordExportable
|
|
3429
|
-
};
|
|
3430
|
-
}
|
|
3431
|
-
const AppPermissionConfigSerializer = { serialize: (config) => {
|
|
3432
|
-
return { rights: config.rights.map(serializeAppRight) };
|
|
3433
|
-
} };
|
|
3434
|
-
//#endregion
|
|
3435
|
-
//#region src/core/application/appPermission/captureAppPermission.ts
|
|
3436
|
-
async function captureAppPermission({ container }) {
|
|
3437
|
-
return captureFromConfig({
|
|
3438
|
-
fetchRemote: () => container.appPermissionConfigurator.getAppPermissions(),
|
|
3439
|
-
serialize: ({ rights }) => stringifyConfig(container.configCodec, AppPermissionConfigSerializer.serialize({ rights })),
|
|
3440
|
-
getStorage: () => container.appPermissionStorage.get()
|
|
3441
|
-
});
|
|
3442
|
-
}
|
|
3443
|
-
//#endregion
|
|
3444
|
-
//#region src/core/application/appPermission/saveAppPermission.ts
|
|
3445
|
-
async function saveAppPermission({ container, input }) {
|
|
3446
|
-
await container.appPermissionStorage.update(input.configText);
|
|
3447
|
-
}
|
|
3448
|
-
//#endregion
|
|
3449
|
-
//#region src/cli/commands/app-acl/capture.ts
|
|
3450
|
-
var capture_default$11 = createCaptureCommand({
|
|
3451
|
-
description: "Capture current app access permissions from kintone app to file",
|
|
3452
|
-
args: appAclArgs,
|
|
3453
|
-
spinnerMessage: "Capturing app access permissions...",
|
|
3454
|
-
spinnerStopMessage: "App access permissions captured.",
|
|
3455
|
-
domainLabel: "App ACL",
|
|
3456
|
-
multiAppSuccessMessage: "All app ACL captures completed successfully.",
|
|
3457
|
-
createContainer: createAppPermissionCliContainer,
|
|
3458
|
-
captureFn: captureAppPermission,
|
|
3459
|
-
saveFn: saveAppPermission,
|
|
3460
|
-
getConfigFilePath: (config) => config.appAclFilePath,
|
|
3461
|
-
resolveContainerConfig: resolveAppAclContainerConfig,
|
|
3462
|
-
resolveAppContainerConfig: resolveAppAclAppContainerConfig
|
|
3463
|
-
});
|
|
3464
|
-
//#endregion
|
|
3465
|
-
//#region src/core/domain/appPermission/services/diffDetector.ts
|
|
3466
|
-
const BOOLEAN_FLAGS = [
|
|
3467
|
-
"includeSubs",
|
|
3468
|
-
"appEditable",
|
|
3469
|
-
"recordViewable",
|
|
3470
|
-
"recordAddable",
|
|
3471
|
-
"recordEditable",
|
|
3472
|
-
"recordDeletable",
|
|
3473
|
-
"recordImportable",
|
|
3474
|
-
"recordExportable"
|
|
3475
|
-
];
|
|
3476
|
-
function entityKey(right) {
|
|
3477
|
-
return `${right.entity.type}:${right.entity.code}`;
|
|
3478
|
-
}
|
|
3479
|
-
function describeRight$1(right) {
|
|
3480
|
-
const flags = BOOLEAN_FLAGS.filter((f) => f !== "includeSubs" && right[f]);
|
|
3481
|
-
return flags.length > 0 ? flags.join(", ") : "no permissions";
|
|
3482
|
-
}
|
|
3483
|
-
function compareRights(local, remote) {
|
|
3484
|
-
const diffs = [];
|
|
3485
|
-
for (const flag of BOOLEAN_FLAGS) if (local[flag] !== remote[flag]) diffs.push(`${flag}: ${String(remote[flag])} -> ${String(local[flag])}`);
|
|
3486
|
-
return diffs;
|
|
3487
|
-
}
|
|
3488
|
-
const AppPermissionDiffDetector = { detect: (local, remote) => {
|
|
3489
|
-
const entries = [];
|
|
3490
|
-
const localMap = new Map(local.rights.map((r) => [entityKey(r), r]));
|
|
3491
|
-
const remoteMap = new Map(remote.rights.map((r) => [entityKey(r), r]));
|
|
3492
|
-
for (const [key, localRight] of localMap) {
|
|
3493
|
-
const remoteRight = remoteMap.get(key);
|
|
3494
|
-
if (!remoteRight) entries.push({
|
|
3495
|
-
type: "added",
|
|
3496
|
-
entityKey: key,
|
|
3497
|
-
details: describeRight$1(localRight)
|
|
3498
|
-
});
|
|
3499
|
-
else {
|
|
3500
|
-
const diffs = compareRights(localRight, remoteRight);
|
|
3501
|
-
if (diffs.length > 0) entries.push({
|
|
3502
|
-
type: "modified",
|
|
3503
|
-
entityKey: key,
|
|
3504
|
-
details: diffs.join(", ")
|
|
3505
|
-
});
|
|
3506
|
-
}
|
|
3507
|
-
}
|
|
3508
|
-
for (const [key, remoteRight] of remoteMap) if (!localMap.has(key)) entries.push({
|
|
3509
|
-
type: "deleted",
|
|
3510
|
-
entityKey: key,
|
|
3511
|
-
details: describeRight$1(remoteRight)
|
|
3512
|
-
});
|
|
3513
|
-
return buildDiffResult(entries);
|
|
3583
|
+
code: right.entity.code
|
|
3584
|
+
},
|
|
3585
|
+
includeSubs: right.includeSubs,
|
|
3586
|
+
appEditable: right.appEditable,
|
|
3587
|
+
recordViewable: right.recordViewable,
|
|
3588
|
+
recordAddable: right.recordAddable,
|
|
3589
|
+
recordEditable: right.recordEditable,
|
|
3590
|
+
recordDeletable: right.recordDeletable,
|
|
3591
|
+
recordImportable: right.recordImportable,
|
|
3592
|
+
recordExportable: right.recordExportable
|
|
3593
|
+
};
|
|
3594
|
+
}
|
|
3595
|
+
const AppPermissionConfigSerializer = { serialize: (config) => {
|
|
3596
|
+
return { rights: config.rights.map(serializeAppRight) };
|
|
3514
3597
|
} };
|
|
3515
3598
|
//#endregion
|
|
3516
|
-
//#region src/core/application/appPermission/
|
|
3517
|
-
async function
|
|
3518
|
-
return
|
|
3519
|
-
getStorage: () => container.appPermissionStorage.get(),
|
|
3599
|
+
//#region src/core/application/appPermission/captureAppPermission.ts
|
|
3600
|
+
async function captureAppPermission({ container }) {
|
|
3601
|
+
return captureFromConfig({
|
|
3520
3602
|
fetchRemote: () => container.appPermissionConfigurator.getAppPermissions(),
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
notFoundMessage: "App permission config file not found"
|
|
3603
|
+
serialize: ({ rights }) => stringifyConfig(container.configCodec, AppPermissionConfigSerializer.serialize({ rights })),
|
|
3604
|
+
getStorage: () => container.appPermissionStorage.get()
|
|
3524
3605
|
});
|
|
3525
3606
|
}
|
|
3526
3607
|
//#endregion
|
|
3608
|
+
//#region src/core/application/appPermission/saveAppPermission.ts
|
|
3609
|
+
async function saveAppPermission({ container, input }) {
|
|
3610
|
+
await container.appPermissionStorage.update(input.configText);
|
|
3611
|
+
}
|
|
3612
|
+
//#endregion
|
|
3527
3613
|
//#region src/cli/commands/app-acl/index.ts
|
|
3528
3614
|
var app_acl_default = define({
|
|
3529
3615
|
name: "app-acl",
|
|
3530
3616
|
description: "Manage kintone app access permissions",
|
|
3531
3617
|
subCommands: {
|
|
3532
3618
|
apply: apply_default$10,
|
|
3533
|
-
capture:
|
|
3619
|
+
capture: createCaptureCommand({
|
|
3620
|
+
description: "Capture current app access permissions from kintone app to file",
|
|
3621
|
+
args: appAclArgs,
|
|
3622
|
+
spinnerMessage: "Capturing app access permissions...",
|
|
3623
|
+
spinnerStopMessage: "App access permissions captured.",
|
|
3624
|
+
domainLabel: "App ACL",
|
|
3625
|
+
multiAppSuccessMessage: "All app ACL captures completed successfully.",
|
|
3626
|
+
createContainer: createAppPermissionCliContainer,
|
|
3627
|
+
captureFn: captureAppPermission,
|
|
3628
|
+
saveFn: saveAppPermission,
|
|
3629
|
+
getConfigFilePath: (config) => config.appAclFilePath,
|
|
3630
|
+
resolveContainerConfig: resolveAppAclContainerConfig,
|
|
3631
|
+
resolveAppContainerConfig: resolveAppAclAppContainerConfig
|
|
3632
|
+
}),
|
|
3534
3633
|
diff: createDiffCommand({
|
|
3535
3634
|
description: "Compare local app permission config with remote kintone app",
|
|
3536
3635
|
args: appAclArgs,
|
|
@@ -3682,6 +3781,95 @@ async function applyCustomization({ container, input }) {
|
|
|
3682
3781
|
});
|
|
3683
3782
|
}
|
|
3684
3783
|
//#endregion
|
|
3784
|
+
//#region src/core/domain/customization/services/diffDetector.ts
|
|
3785
|
+
function resourceName(resource) {
|
|
3786
|
+
if (resource.type === "URL") return resource.url;
|
|
3787
|
+
const parts = resource.path.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
3788
|
+
return parts[parts.length - 1];
|
|
3789
|
+
}
|
|
3790
|
+
function remoteResourceName(resource) {
|
|
3791
|
+
if (resource.type === "URL") return resource.url;
|
|
3792
|
+
return resource.file.name;
|
|
3793
|
+
}
|
|
3794
|
+
function compareResourceLists(localResources, remoteResources, platform, resourceType, warnings) {
|
|
3795
|
+
const entries = [];
|
|
3796
|
+
const localNames = localResources.map(resourceName);
|
|
3797
|
+
const remoteNames = remoteResources.map(remoteResourceName);
|
|
3798
|
+
const localNameSet = new Set(localNames);
|
|
3799
|
+
const remoteNameSet = new Set(remoteNames);
|
|
3800
|
+
const hasDuplicates = localNames.length !== localNameSet.size || remoteNames.length !== remoteNameSet.size;
|
|
3801
|
+
if (hasDuplicates) warnings.push(`[${platform}.${resourceType}] duplicate basenames detected; diff results may be inaccurate for FILE resources`);
|
|
3802
|
+
const localTypeMap = /* @__PURE__ */ new Map();
|
|
3803
|
+
for (const r of localResources) localTypeMap.set(resourceName(r), r.type);
|
|
3804
|
+
const remoteTypeMap = /* @__PURE__ */ new Map();
|
|
3805
|
+
for (const r of remoteResources) remoteTypeMap.set(remoteResourceName(r), r.type);
|
|
3806
|
+
for (const name of localNameSet) if (!remoteNameSet.has(name)) {
|
|
3807
|
+
const resType = localTypeMap.get(name) ?? "FILE";
|
|
3808
|
+
entries.push({
|
|
3809
|
+
type: "added",
|
|
3810
|
+
platform,
|
|
3811
|
+
category: resourceType,
|
|
3812
|
+
name,
|
|
3813
|
+
details: `new ${resType} resource`
|
|
3814
|
+
});
|
|
3815
|
+
}
|
|
3816
|
+
for (const name of remoteNameSet) if (!localNameSet.has(name)) {
|
|
3817
|
+
const resType = remoteTypeMap.get(name) ?? "FILE";
|
|
3818
|
+
entries.push({
|
|
3819
|
+
type: "deleted",
|
|
3820
|
+
platform,
|
|
3821
|
+
category: resourceType,
|
|
3822
|
+
name,
|
|
3823
|
+
details: `removed ${resType} resource`
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3826
|
+
const matchedFiles = [...localNameSet].filter((n) => remoteNameSet.has(n));
|
|
3827
|
+
const hasLocalFiles = localResources.some((r) => r.type === "FILE");
|
|
3828
|
+
const hasRemoteFiles = remoteResources.some((r) => r.type === "FILE");
|
|
3829
|
+
if (matchedFiles.length > 0 && hasLocalFiles && hasRemoteFiles) warnings.push(`[${platform}.${resourceType}] FILE resources are compared by name only; content changes are not detected`);
|
|
3830
|
+
if (!hasDuplicates) {
|
|
3831
|
+
const localShared = localNames.filter((n) => remoteNameSet.has(n));
|
|
3832
|
+
const remoteShared = remoteNames.filter((n) => localNameSet.has(n));
|
|
3833
|
+
if (localShared.length > 1 && localShared.length === remoteShared.length && localShared.some((n, i) => n !== remoteShared[i])) entries.push({
|
|
3834
|
+
type: "modified",
|
|
3835
|
+
platform,
|
|
3836
|
+
category: resourceType,
|
|
3837
|
+
name: "(order)",
|
|
3838
|
+
details: "resource load order changed"
|
|
3839
|
+
});
|
|
3840
|
+
}
|
|
3841
|
+
return entries;
|
|
3842
|
+
}
|
|
3843
|
+
function comparePlatform(localJs, localCss, remote, platform, warnings) {
|
|
3844
|
+
return [...compareResourceLists(localJs, remote.js, platform, "js", warnings), ...compareResourceLists(localCss, remote.css, platform, "css", warnings)];
|
|
3845
|
+
}
|
|
3846
|
+
const CustomizationDiffDetector = { detect: (local, remote) => {
|
|
3847
|
+
const entries = [];
|
|
3848
|
+
const warnings = [];
|
|
3849
|
+
const localScope = local.scope ?? "ALL";
|
|
3850
|
+
if (localScope !== remote.scope) entries.push({
|
|
3851
|
+
type: "modified",
|
|
3852
|
+
platform: "config",
|
|
3853
|
+
category: "scope",
|
|
3854
|
+
name: "scope",
|
|
3855
|
+
details: `${remote.scope} -> ${localScope}`
|
|
3856
|
+
});
|
|
3857
|
+
entries.push(...comparePlatform(local.desktop.js, local.desktop.css, remote.desktop, "desktop", warnings));
|
|
3858
|
+
entries.push(...comparePlatform(local.mobile.js, local.mobile.css, remote.mobile, "mobile", warnings));
|
|
3859
|
+
return buildDiffResult(entries, warnings);
|
|
3860
|
+
} };
|
|
3861
|
+
//#endregion
|
|
3862
|
+
//#region src/core/application/customization/detectCustomizationDiff.ts
|
|
3863
|
+
async function detectCustomizationDiff({ container }) {
|
|
3864
|
+
return detectDiffFromConfig({
|
|
3865
|
+
getStorage: () => container.customizationStorage.get(),
|
|
3866
|
+
fetchRemote: () => container.customizationConfigurator.getCustomization(),
|
|
3867
|
+
parseConfig: (content) => parseCustomizationConfigText(container.configCodec, content),
|
|
3868
|
+
detect: (local, remote) => CustomizationDiffDetector.detect(local, remote),
|
|
3869
|
+
notFoundMessage: "Customization config file not found"
|
|
3870
|
+
});
|
|
3871
|
+
}
|
|
3872
|
+
//#endregion
|
|
3685
3873
|
//#region src/cli/customizeConfig.ts
|
|
3686
3874
|
const customizeArgs = {
|
|
3687
3875
|
...kintoneArgs,
|
|
@@ -3945,132 +4133,47 @@ var capture_default$10 = define({
|
|
|
3945
4133
|
});
|
|
3946
4134
|
//#endregion
|
|
3947
4135
|
//#region src/cli/commands/customize/apply.ts
|
|
3948
|
-
|
|
4136
|
+
function createCustomizationContainer(config) {
|
|
3949
4137
|
const container = createCustomizationCliContainer(config);
|
|
3950
4138
|
const filePrefix = deriveFilePrefix(config.customizeFilePath);
|
|
3951
|
-
|
|
3952
|
-
const s = p.spinner();
|
|
3953
|
-
s.start("Applying customization...");
|
|
3954
|
-
await applyCustomization({
|
|
4139
|
+
return {
|
|
3955
4140
|
container,
|
|
3956
|
-
|
|
3957
|
-
}
|
|
3958
|
-
s.stop("Customization applied.");
|
|
3959
|
-
return container;
|
|
3960
|
-
}
|
|
3961
|
-
var apply_default$9 = define({
|
|
3962
|
-
name: "apply",
|
|
3963
|
-
description: "Apply JS/CSS customization to kintone app",
|
|
3964
|
-
args: {
|
|
3965
|
-
...customizeArgs,
|
|
3966
|
-
...confirmArgs
|
|
3967
|
-
},
|
|
3968
|
-
run: async (ctx) => {
|
|
3969
|
-
try {
|
|
3970
|
-
const values = ctx.values;
|
|
3971
|
-
const skipConfirm = values.yes === true;
|
|
3972
|
-
await routeMultiApp(values, {
|
|
3973
|
-
singleLegacy: async () => {
|
|
3974
|
-
await confirmAndDeploy([await applyCustomizationForApp(resolveCustomizeConfig(values))], skipConfirm, "Customization applied and deployed successfully.");
|
|
3975
|
-
},
|
|
3976
|
-
singleApp: async (app, projectConfig) => {
|
|
3977
|
-
await confirmAndDeploy([await applyCustomizationForApp(resolveCustomizeAppConfig(app, projectConfig, values))], skipConfirm, "Customization applied and deployed successfully.");
|
|
3978
|
-
},
|
|
3979
|
-
multiApp: async (plan, projectConfig) => {
|
|
3980
|
-
const containers = [];
|
|
3981
|
-
await runMultiAppWithHeaders(plan, async (app) => {
|
|
3982
|
-
const container = await applyCustomizationForApp(resolveCustomizeAppConfig(app, projectConfig, values));
|
|
3983
|
-
containers.push({
|
|
3984
|
-
appDeployer: container.appDeployer,
|
|
3985
|
-
appName: app.name
|
|
3986
|
-
});
|
|
3987
|
-
});
|
|
3988
|
-
await confirmAndDeploy(containers, skipConfirm, "Customization applied and deployed successfully.");
|
|
3989
|
-
}
|
|
3990
|
-
});
|
|
3991
|
-
} catch (error) {
|
|
3992
|
-
handleCliError(error);
|
|
3993
|
-
}
|
|
3994
|
-
}
|
|
3995
|
-
});
|
|
3996
|
-
//#endregion
|
|
3997
|
-
//#region src/core/domain/customization/services/diffDetector.ts
|
|
3998
|
-
function resourceName(resource) {
|
|
3999
|
-
if (resource.type === "URL") return resource.url;
|
|
4000
|
-
const parts = resource.path.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
4001
|
-
return parts[parts.length - 1];
|
|
4002
|
-
}
|
|
4003
|
-
function remoteResourceName(resource) {
|
|
4004
|
-
if (resource.type === "URL") return resource.url;
|
|
4005
|
-
return resource.file.name;
|
|
4141
|
+
basePath: join(dirname(resolve(config.customizeFilePath)), filePrefix)
|
|
4142
|
+
};
|
|
4006
4143
|
}
|
|
4007
|
-
function
|
|
4008
|
-
const
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
if (hasDuplicates) warnings.push(`[${platform}.${resourceType}] duplicate basenames detected; diff results may be inaccurate for FILE resources`);
|
|
4015
|
-
for (const name of localNameSet) if (!remoteNameSet.has(name)) entries.push({
|
|
4016
|
-
type: "added",
|
|
4017
|
-
platform,
|
|
4018
|
-
category: resourceType,
|
|
4019
|
-
name,
|
|
4020
|
-
details: "new resource"
|
|
4021
|
-
});
|
|
4022
|
-
for (const name of remoteNameSet) if (!localNameSet.has(name)) entries.push({
|
|
4023
|
-
type: "deleted",
|
|
4024
|
-
platform,
|
|
4025
|
-
category: resourceType,
|
|
4026
|
-
name,
|
|
4027
|
-
details: "removed"
|
|
4028
|
-
});
|
|
4029
|
-
const matchedFiles = [...localNameSet].filter((n) => remoteNameSet.has(n));
|
|
4030
|
-
const hasLocalFiles = localResources.some((r) => r.type === "FILE");
|
|
4031
|
-
const hasRemoteFiles = remoteResources.some((r) => r.type === "FILE");
|
|
4032
|
-
if (matchedFiles.length > 0 && hasLocalFiles && hasRemoteFiles) warnings.push(`[${platform}.${resourceType}] FILE resources are compared by name only; content changes are not detected`);
|
|
4033
|
-
if (!hasDuplicates) {
|
|
4034
|
-
const localShared = localNames.filter((n) => remoteNameSet.has(n));
|
|
4035
|
-
const remoteShared = remoteNames.filter((n) => localNameSet.has(n));
|
|
4036
|
-
if (localShared.length > 1 && localShared.length === remoteShared.length && localShared.some((n, i) => n !== remoteShared[i])) entries.push({
|
|
4037
|
-
type: "modified",
|
|
4038
|
-
platform,
|
|
4039
|
-
category: resourceType,
|
|
4040
|
-
name: "(order)",
|
|
4041
|
-
details: "resource load order changed"
|
|
4144
|
+
async function runCustomizationApply(container, basePath) {
|
|
4145
|
+
const s = p.spinner();
|
|
4146
|
+
s.start("Applying customization...");
|
|
4147
|
+
try {
|
|
4148
|
+
await applyCustomization({
|
|
4149
|
+
container,
|
|
4150
|
+
input: { basePath }
|
|
4042
4151
|
});
|
|
4152
|
+
} catch (error) {
|
|
4153
|
+
s.stop("Apply failed.");
|
|
4154
|
+
throw error;
|
|
4043
4155
|
}
|
|
4044
|
-
|
|
4045
|
-
}
|
|
4046
|
-
function comparePlatform(localJs, localCss, remote, platform, warnings) {
|
|
4047
|
-
return [...compareResourceLists(localJs, remote.js, platform, "js", warnings), ...compareResourceLists(localCss, remote.css, platform, "css", warnings)];
|
|
4156
|
+
s.stop("Customization applied.");
|
|
4048
4157
|
}
|
|
4049
|
-
|
|
4050
|
-
const
|
|
4051
|
-
const
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
}
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
getStorage: () => container.customizationStorage.get(),
|
|
4069
|
-
fetchRemote: () => container.customizationConfigurator.getCustomization(),
|
|
4070
|
-
parseConfig: (content) => parseCustomizationConfigText(container.configCodec, content),
|
|
4071
|
-
detect: (local, remote) => CustomizationDiffDetector.detect(local, remote),
|
|
4072
|
-
notFoundMessage: "Customization config file not found"
|
|
4073
|
-
});
|
|
4158
|
+
async function runDiffPreview(config) {
|
|
4159
|
+
const { container, basePath } = createCustomizationContainer(config);
|
|
4160
|
+
const s = p.spinner();
|
|
4161
|
+
s.start("Detecting changes...");
|
|
4162
|
+
let result;
|
|
4163
|
+
try {
|
|
4164
|
+
result = await detectCustomizationDiff({ container });
|
|
4165
|
+
} catch (error) {
|
|
4166
|
+
s.stop("Comparison failed.");
|
|
4167
|
+
throw error;
|
|
4168
|
+
}
|
|
4169
|
+
s.stop("Comparison complete.");
|
|
4170
|
+
printCustomizationDiffResult(result);
|
|
4171
|
+
const hasFileContentWarning = result.warnings.some((w) => w.includes("content changes are not detected"));
|
|
4172
|
+
return {
|
|
4173
|
+
container,
|
|
4174
|
+
basePath,
|
|
4175
|
+
hasChanges: !result.isEmpty || hasFileContentWarning
|
|
4176
|
+
};
|
|
4074
4177
|
}
|
|
4075
4178
|
//#endregion
|
|
4076
4179
|
//#region src/cli/commands/customize/index.ts
|
|
@@ -4078,7 +4181,96 @@ var customize_default = define({
|
|
|
4078
4181
|
name: "customize",
|
|
4079
4182
|
description: "Manage kintone JS/CSS customizations",
|
|
4080
4183
|
subCommands: {
|
|
4081
|
-
apply:
|
|
4184
|
+
apply: define({
|
|
4185
|
+
name: "apply",
|
|
4186
|
+
description: "Apply JS/CSS customization to kintone app",
|
|
4187
|
+
args: {
|
|
4188
|
+
...customizeArgs,
|
|
4189
|
+
...confirmArgs
|
|
4190
|
+
},
|
|
4191
|
+
run: async (ctx) => {
|
|
4192
|
+
try {
|
|
4193
|
+
const values = ctx.values;
|
|
4194
|
+
const skipConfirm = values.yes === true;
|
|
4195
|
+
await routeMultiApp(values, {
|
|
4196
|
+
singleLegacy: async () => {
|
|
4197
|
+
const { container, basePath, hasChanges } = await runDiffPreview(resolveCustomizeConfig(values));
|
|
4198
|
+
if (!hasChanges) {
|
|
4199
|
+
p.log.success("No changes detected.");
|
|
4200
|
+
return;
|
|
4201
|
+
}
|
|
4202
|
+
if (!skipConfirm) {
|
|
4203
|
+
const shouldContinue = await p.confirm({ message: "Apply these changes?" });
|
|
4204
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
4205
|
+
p.cancel("Apply cancelled.");
|
|
4206
|
+
return;
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
await runCustomizationApply(container, basePath);
|
|
4210
|
+
await confirmAndDeploy([container], skipConfirm, "Customization applied and deployed successfully.");
|
|
4211
|
+
},
|
|
4212
|
+
singleApp: async (app, projectConfig) => {
|
|
4213
|
+
const { container, basePath, hasChanges } = await runDiffPreview(resolveCustomizeAppConfig(app, projectConfig, values));
|
|
4214
|
+
if (!hasChanges) {
|
|
4215
|
+
p.log.success("No changes detected.");
|
|
4216
|
+
return;
|
|
4217
|
+
}
|
|
4218
|
+
if (!skipConfirm) {
|
|
4219
|
+
const shouldContinue = await p.confirm({ message: "Apply these changes?" });
|
|
4220
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
4221
|
+
p.cancel("Apply cancelled.");
|
|
4222
|
+
return;
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
await runCustomizationApply(container, basePath);
|
|
4226
|
+
await confirmAndDeploy([container], skipConfirm, "Customization applied and deployed successfully.");
|
|
4227
|
+
},
|
|
4228
|
+
multiApp: async (plan, projectConfig) => {
|
|
4229
|
+
const appDiffResults = [];
|
|
4230
|
+
for (const app of plan.orderedApps) {
|
|
4231
|
+
const config = resolveCustomizeAppConfig(app, projectConfig, values);
|
|
4232
|
+
printAppHeader(app.name, app.appId);
|
|
4233
|
+
const { container, basePath, hasChanges } = await runDiffPreview(config);
|
|
4234
|
+
appDiffResults.push({
|
|
4235
|
+
app,
|
|
4236
|
+
container,
|
|
4237
|
+
basePath,
|
|
4238
|
+
hasChanges
|
|
4239
|
+
});
|
|
4240
|
+
}
|
|
4241
|
+
if (!appDiffResults.some((a) => a.hasChanges)) {
|
|
4242
|
+
p.log.success("No changes detected in any app.");
|
|
4243
|
+
return;
|
|
4244
|
+
}
|
|
4245
|
+
if (!skipConfirm) {
|
|
4246
|
+
const shouldContinue = await p.confirm({ message: "Apply these changes to all apps?" });
|
|
4247
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
4248
|
+
p.cancel("Apply cancelled.");
|
|
4249
|
+
return;
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
const containers = [];
|
|
4253
|
+
await runMultiAppWithHeaders(plan, async (app) => {
|
|
4254
|
+
const entry = appDiffResults.find((a) => a.app.name === app.name);
|
|
4255
|
+
if (!entry) throw new SystemError(SystemErrorCode.InternalServerError, `App container not found for "${app.name}"`);
|
|
4256
|
+
if (!entry.hasChanges) {
|
|
4257
|
+
p.log.info("No changes. Skipping.");
|
|
4258
|
+
return;
|
|
4259
|
+
}
|
|
4260
|
+
await runCustomizationApply(entry.container, entry.basePath);
|
|
4261
|
+
containers.push({
|
|
4262
|
+
appDeployer: entry.container.appDeployer,
|
|
4263
|
+
appName: app.name
|
|
4264
|
+
});
|
|
4265
|
+
});
|
|
4266
|
+
await confirmAndDeploy(containers, skipConfirm, "Customization applied and deployed successfully.");
|
|
4267
|
+
}
|
|
4268
|
+
});
|
|
4269
|
+
} catch (error) {
|
|
4270
|
+
handleCliError(error);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
}),
|
|
4082
4274
|
capture: capture_default$10,
|
|
4083
4275
|
diff: createDiffCommand({
|
|
4084
4276
|
description: "Compare local customization config with remote kintone app",
|
|
@@ -4270,6 +4462,63 @@ async function applyFieldPermission({ container }) {
|
|
|
4270
4462
|
});
|
|
4271
4463
|
}
|
|
4272
4464
|
//#endregion
|
|
4465
|
+
//#region src/core/domain/fieldPermission/services/diffDetector.ts
|
|
4466
|
+
function isEntitiesEqual$1(a, b) {
|
|
4467
|
+
return deepEqual(a.entities.map((e) => ({
|
|
4468
|
+
accessibility: e.accessibility,
|
|
4469
|
+
type: e.entity.type,
|
|
4470
|
+
code: e.entity.code,
|
|
4471
|
+
includeSubs: e.includeSubs ?? false
|
|
4472
|
+
})), b.entities.map((e) => ({
|
|
4473
|
+
accessibility: e.accessibility,
|
|
4474
|
+
type: e.entity.type,
|
|
4475
|
+
code: e.entity.code,
|
|
4476
|
+
includeSubs: e.includeSubs ?? false
|
|
4477
|
+
})));
|
|
4478
|
+
}
|
|
4479
|
+
function describeEntities(entities) {
|
|
4480
|
+
if (entities.length === 0) return "no entities";
|
|
4481
|
+
return entities.map((e) => {
|
|
4482
|
+
const access = e.accessibility.toLowerCase();
|
|
4483
|
+
return `${e.entity.type}:${e.entity.code}(${access})`;
|
|
4484
|
+
}).join(", ");
|
|
4485
|
+
}
|
|
4486
|
+
const FieldPermissionDiffDetector = { detect: (local, remote) => {
|
|
4487
|
+
const entries = [];
|
|
4488
|
+
const localMap = new Map(local.rights.map((r) => [r.code, r]));
|
|
4489
|
+
const remoteMap = new Map(remote.rights.map((r) => [r.code, r]));
|
|
4490
|
+
for (const [code, localRight] of localMap) {
|
|
4491
|
+
const remoteRight = remoteMap.get(code);
|
|
4492
|
+
if (!remoteRight) entries.push({
|
|
4493
|
+
type: "added",
|
|
4494
|
+
fieldCode: code,
|
|
4495
|
+
details: `entities: ${describeEntities(localRight.entities)}`
|
|
4496
|
+
});
|
|
4497
|
+
else if (!isEntitiesEqual$1(localRight, remoteRight)) entries.push({
|
|
4498
|
+
type: "modified",
|
|
4499
|
+
fieldCode: code,
|
|
4500
|
+
details: `entities: ${describeEntities(localRight.entities)}`
|
|
4501
|
+
});
|
|
4502
|
+
}
|
|
4503
|
+
for (const [code, remoteRight] of remoteMap) if (!localMap.has(code)) entries.push({
|
|
4504
|
+
type: "deleted",
|
|
4505
|
+
fieldCode: code,
|
|
4506
|
+
details: `entities: ${describeEntities(remoteRight.entities)}`
|
|
4507
|
+
});
|
|
4508
|
+
return buildDiffResult(entries);
|
|
4509
|
+
} };
|
|
4510
|
+
//#endregion
|
|
4511
|
+
//#region src/core/application/fieldPermission/detectFieldPermissionDiff.ts
|
|
4512
|
+
async function detectFieldPermissionDiff({ container }) {
|
|
4513
|
+
return detectDiffFromConfig({
|
|
4514
|
+
getStorage: () => container.fieldPermissionStorage.get(),
|
|
4515
|
+
fetchRemote: () => container.fieldPermissionConfigurator.getFieldPermissions(),
|
|
4516
|
+
parseConfig: (content) => parseFieldPermissionConfigText(container.configCodec, content),
|
|
4517
|
+
detect: (local, remote) => FieldPermissionDiffDetector.detect(local, { rights: remote.rights }),
|
|
4518
|
+
notFoundMessage: "Field permission config file not found"
|
|
4519
|
+
});
|
|
4520
|
+
}
|
|
4521
|
+
//#endregion
|
|
4273
4522
|
//#region src/cli/fieldAclConfig.ts
|
|
4274
4523
|
const fieldAclArgs = {
|
|
4275
4524
|
...kintoneArgs,
|
|
@@ -4300,6 +4549,10 @@ var apply_default$8 = createApplyCommand({
|
|
|
4300
4549
|
successMessage: "Field access permissions applied successfully.",
|
|
4301
4550
|
createContainer: createFieldPermissionCliContainer,
|
|
4302
4551
|
applyFn: applyFieldPermission,
|
|
4552
|
+
diffPreview: {
|
|
4553
|
+
detectDiff: detectFieldPermissionDiff,
|
|
4554
|
+
printResult: printFieldPermissionDiffResult
|
|
4555
|
+
},
|
|
4303
4556
|
resolveContainerConfig: resolveFieldAclContainerConfig,
|
|
4304
4557
|
resolveAppContainerConfig: resolveFieldAclAppContainerConfig
|
|
4305
4558
|
});
|
|
@@ -4337,79 +4590,26 @@ async function saveFieldPermission({ container, input }) {
|
|
|
4337
4590
|
await container.fieldPermissionStorage.update(input.configText);
|
|
4338
4591
|
}
|
|
4339
4592
|
//#endregion
|
|
4340
|
-
//#region src/cli/commands/field-acl/capture.ts
|
|
4341
|
-
var capture_default$9 = createCaptureCommand({
|
|
4342
|
-
description: "Capture current field access permissions from kintone app to file",
|
|
4343
|
-
args: fieldAclArgs,
|
|
4344
|
-
spinnerMessage: "Capturing field access permissions...",
|
|
4345
|
-
spinnerStopMessage: "Field access permissions captured.",
|
|
4346
|
-
domainLabel: "Field ACL",
|
|
4347
|
-
multiAppSuccessMessage: "All field ACL captures completed successfully.",
|
|
4348
|
-
createContainer: createFieldPermissionCliContainer,
|
|
4349
|
-
captureFn: captureFieldPermission,
|
|
4350
|
-
saveFn: saveFieldPermission,
|
|
4351
|
-
getConfigFilePath: (config) => config.fieldAclFilePath,
|
|
4352
|
-
resolveContainerConfig: resolveFieldAclContainerConfig,
|
|
4353
|
-
resolveAppContainerConfig: resolveFieldAclAppContainerConfig
|
|
4354
|
-
});
|
|
4355
|
-
//#endregion
|
|
4356
|
-
//#region src/core/domain/fieldPermission/services/diffDetector.ts
|
|
4357
|
-
function isEntitiesEqual$1(a, b) {
|
|
4358
|
-
return deepEqual(a.entities.map((e) => ({
|
|
4359
|
-
accessibility: e.accessibility,
|
|
4360
|
-
type: e.entity.type,
|
|
4361
|
-
code: e.entity.code,
|
|
4362
|
-
includeSubs: e.includeSubs ?? false
|
|
4363
|
-
})), b.entities.map((e) => ({
|
|
4364
|
-
accessibility: e.accessibility,
|
|
4365
|
-
type: e.entity.type,
|
|
4366
|
-
code: e.entity.code,
|
|
4367
|
-
includeSubs: e.includeSubs ?? false
|
|
4368
|
-
})));
|
|
4369
|
-
}
|
|
4370
|
-
const FieldPermissionDiffDetector = { detect: (local, remote) => {
|
|
4371
|
-
const entries = [];
|
|
4372
|
-
const localMap = new Map(local.rights.map((r) => [r.code, r]));
|
|
4373
|
-
const remoteMap = new Map(remote.rights.map((r) => [r.code, r]));
|
|
4374
|
-
for (const [code, localRight] of localMap) {
|
|
4375
|
-
const remoteRight = remoteMap.get(code);
|
|
4376
|
-
if (!remoteRight) entries.push({
|
|
4377
|
-
type: "added",
|
|
4378
|
-
fieldCode: code,
|
|
4379
|
-
details: `${localRight.entities.length} entities`
|
|
4380
|
-
});
|
|
4381
|
-
else if (!isEntitiesEqual$1(localRight, remoteRight)) entries.push({
|
|
4382
|
-
type: "modified",
|
|
4383
|
-
fieldCode: code,
|
|
4384
|
-
details: "entities changed"
|
|
4385
|
-
});
|
|
4386
|
-
}
|
|
4387
|
-
for (const code of remoteMap.keys()) if (!localMap.has(code)) entries.push({
|
|
4388
|
-
type: "deleted",
|
|
4389
|
-
fieldCode: code,
|
|
4390
|
-
details: "removed"
|
|
4391
|
-
});
|
|
4392
|
-
return buildDiffResult(entries);
|
|
4393
|
-
} };
|
|
4394
|
-
//#endregion
|
|
4395
|
-
//#region src/core/application/fieldPermission/detectFieldPermissionDiff.ts
|
|
4396
|
-
async function detectFieldPermissionDiff({ container }) {
|
|
4397
|
-
return detectDiffFromConfig({
|
|
4398
|
-
getStorage: () => container.fieldPermissionStorage.get(),
|
|
4399
|
-
fetchRemote: () => container.fieldPermissionConfigurator.getFieldPermissions(),
|
|
4400
|
-
parseConfig: (content) => parseFieldPermissionConfigText(container.configCodec, content),
|
|
4401
|
-
detect: (local, remote) => FieldPermissionDiffDetector.detect(local, { rights: remote.rights }),
|
|
4402
|
-
notFoundMessage: "Field permission config file not found"
|
|
4403
|
-
});
|
|
4404
|
-
}
|
|
4405
|
-
//#endregion
|
|
4406
4593
|
//#region src/cli/commands/field-acl/index.ts
|
|
4407
4594
|
var field_acl_default = define({
|
|
4408
4595
|
name: "field-acl",
|
|
4409
4596
|
description: "Manage kintone field access permissions",
|
|
4410
4597
|
subCommands: {
|
|
4411
4598
|
apply: apply_default$8,
|
|
4412
|
-
capture:
|
|
4599
|
+
capture: createCaptureCommand({
|
|
4600
|
+
description: "Capture current field access permissions from kintone app to file",
|
|
4601
|
+
args: fieldAclArgs,
|
|
4602
|
+
spinnerMessage: "Capturing field access permissions...",
|
|
4603
|
+
spinnerStopMessage: "Field access permissions captured.",
|
|
4604
|
+
domainLabel: "Field ACL",
|
|
4605
|
+
multiAppSuccessMessage: "All field ACL captures completed successfully.",
|
|
4606
|
+
createContainer: createFieldPermissionCliContainer,
|
|
4607
|
+
captureFn: captureFieldPermission,
|
|
4608
|
+
saveFn: saveFieldPermission,
|
|
4609
|
+
getConfigFilePath: (config) => config.fieldAclFilePath,
|
|
4610
|
+
resolveContainerConfig: resolveFieldAclContainerConfig,
|
|
4611
|
+
resolveAppContainerConfig: resolveFieldAclAppContainerConfig
|
|
4612
|
+
}),
|
|
4413
4613
|
diff: createDiffCommand({
|
|
4414
4614
|
description: "Compare local field permission config with remote kintone app",
|
|
4415
4615
|
args: fieldAclArgs,
|
|
@@ -6352,7 +6552,7 @@ async function fetchSpaceApps(args) {
|
|
|
6352
6552
|
return apps;
|
|
6353
6553
|
}
|
|
6354
6554
|
//#endregion
|
|
6355
|
-
//#region src/core/domain/
|
|
6555
|
+
//#region src/core/domain/app/entity.ts
|
|
6356
6556
|
const UNSAFE_PATH_CHARS = /[<>:"/\\|?*\u0000-\u001f]/g;
|
|
6357
6557
|
function sanitizeForFileSystem(name) {
|
|
6358
6558
|
const sanitized = name.replace(UNSAFE_PATH_CHARS, "_").replace(/\.+$/, "");
|
|
@@ -6689,56 +6889,6 @@ async function applyNotification({ container }) {
|
|
|
6689
6889
|
}
|
|
6690
6890
|
}
|
|
6691
6891
|
//#endregion
|
|
6692
|
-
//#region src/cli/notificationConfig.ts
|
|
6693
|
-
const notificationArgs = {
|
|
6694
|
-
...kintoneArgs,
|
|
6695
|
-
...multiAppArgs,
|
|
6696
|
-
"notification-file": {
|
|
6697
|
-
type: "string",
|
|
6698
|
-
description: "Notification file path (default: notification.yaml)"
|
|
6699
|
-
}
|
|
6700
|
-
};
|
|
6701
|
-
const { resolveFilePath: resolveNotificationFilePath, resolveContainerConfig: resolveNotificationContainerConfig, resolveAppContainerConfig: resolveNotificationAppContainerConfig } = createDomainConfigResolver({
|
|
6702
|
-
fileArgKey: "notification-file",
|
|
6703
|
-
envVar: () => process.env.NOTIFICATION_FILE_PATH,
|
|
6704
|
-
appFileField: (a) => a.notificationFile,
|
|
6705
|
-
defaultDir: "notification",
|
|
6706
|
-
defaultFileName: "notification.yaml",
|
|
6707
|
-
buildConfig: (base, filePath) => ({
|
|
6708
|
-
...base,
|
|
6709
|
-
notificationFilePath: filePath
|
|
6710
|
-
})
|
|
6711
|
-
});
|
|
6712
|
-
//#endregion
|
|
6713
|
-
//#region src/cli/commands/notification/apply.ts
|
|
6714
|
-
var apply_default$7 = createApplyCommand({
|
|
6715
|
-
description: "Apply notification settings from YAML to kintone app",
|
|
6716
|
-
args: notificationArgs,
|
|
6717
|
-
spinnerMessage: "Applying notification settings...",
|
|
6718
|
-
spinnerStopMessage: "Notification settings applied.",
|
|
6719
|
-
successMessage: "Notification settings applied successfully.",
|
|
6720
|
-
createContainer: createNotificationCliContainer,
|
|
6721
|
-
applyFn: applyNotification,
|
|
6722
|
-
resolveContainerConfig: resolveNotificationContainerConfig,
|
|
6723
|
-
resolveAppContainerConfig: resolveNotificationAppContainerConfig
|
|
6724
|
-
});
|
|
6725
|
-
//#endregion
|
|
6726
|
-
//#region src/cli/commands/notification/capture.ts
|
|
6727
|
-
var capture_default$8 = createCaptureCommand({
|
|
6728
|
-
description: "Capture current notification settings from kintone app to file",
|
|
6729
|
-
args: notificationArgs,
|
|
6730
|
-
spinnerMessage: "Capturing notification settings...",
|
|
6731
|
-
spinnerStopMessage: "Notification settings captured.",
|
|
6732
|
-
domainLabel: "Notification settings",
|
|
6733
|
-
multiAppSuccessMessage: "All notification captures completed successfully.",
|
|
6734
|
-
createContainer: createNotificationCliContainer,
|
|
6735
|
-
captureFn: captureNotification,
|
|
6736
|
-
saveFn: saveNotification,
|
|
6737
|
-
getConfigFilePath: (config) => config.notificationFilePath,
|
|
6738
|
-
resolveContainerConfig: resolveNotificationContainerConfig,
|
|
6739
|
-
resolveAppContainerConfig: resolveNotificationAppContainerConfig
|
|
6740
|
-
});
|
|
6741
|
-
//#endregion
|
|
6742
6892
|
//#region src/lib/groupByKey.ts
|
|
6743
6893
|
/**
|
|
6744
6894
|
* Groups items by a key function into a Map where each key maps to an array of items.
|
|
@@ -6968,13 +7118,61 @@ async function detectNotificationDiff({ container }) {
|
|
|
6968
7118
|
return NotificationDiffDetector.detect(localConfig, remoteConfig);
|
|
6969
7119
|
}
|
|
6970
7120
|
//#endregion
|
|
7121
|
+
//#region src/cli/notificationConfig.ts
|
|
7122
|
+
const notificationArgs = {
|
|
7123
|
+
...kintoneArgs,
|
|
7124
|
+
...multiAppArgs,
|
|
7125
|
+
"notification-file": {
|
|
7126
|
+
type: "string",
|
|
7127
|
+
description: "Notification file path (default: notification.yaml)"
|
|
7128
|
+
}
|
|
7129
|
+
};
|
|
7130
|
+
const { resolveFilePath: resolveNotificationFilePath, resolveContainerConfig: resolveNotificationContainerConfig, resolveAppContainerConfig: resolveNotificationAppContainerConfig } = createDomainConfigResolver({
|
|
7131
|
+
fileArgKey: "notification-file",
|
|
7132
|
+
envVar: () => process.env.NOTIFICATION_FILE_PATH,
|
|
7133
|
+
appFileField: (a) => a.notificationFile,
|
|
7134
|
+
defaultDir: "notification",
|
|
7135
|
+
defaultFileName: "notification.yaml",
|
|
7136
|
+
buildConfig: (base, filePath) => ({
|
|
7137
|
+
...base,
|
|
7138
|
+
notificationFilePath: filePath
|
|
7139
|
+
})
|
|
7140
|
+
});
|
|
7141
|
+
//#endregion
|
|
6971
7142
|
//#region src/cli/commands/notification/index.ts
|
|
6972
7143
|
var notification_default = define({
|
|
6973
7144
|
name: "notification",
|
|
6974
7145
|
description: "Manage kintone notification settings",
|
|
6975
7146
|
subCommands: {
|
|
6976
|
-
apply:
|
|
6977
|
-
|
|
7147
|
+
apply: createApplyCommand({
|
|
7148
|
+
description: "Apply notification settings from YAML to kintone app",
|
|
7149
|
+
args: notificationArgs,
|
|
7150
|
+
spinnerMessage: "Applying notification settings...",
|
|
7151
|
+
spinnerStopMessage: "Notification settings applied.",
|
|
7152
|
+
successMessage: "Notification settings applied successfully.",
|
|
7153
|
+
createContainer: createNotificationCliContainer,
|
|
7154
|
+
applyFn: applyNotification,
|
|
7155
|
+
diffPreview: {
|
|
7156
|
+
detectDiff: detectNotificationDiff,
|
|
7157
|
+
printResult: printNotificationDiffResult
|
|
7158
|
+
},
|
|
7159
|
+
resolveContainerConfig: resolveNotificationContainerConfig,
|
|
7160
|
+
resolveAppContainerConfig: resolveNotificationAppContainerConfig
|
|
7161
|
+
}),
|
|
7162
|
+
capture: createCaptureCommand({
|
|
7163
|
+
description: "Capture current notification settings from kintone app to file",
|
|
7164
|
+
args: notificationArgs,
|
|
7165
|
+
spinnerMessage: "Capturing notification settings...",
|
|
7166
|
+
spinnerStopMessage: "Notification settings captured.",
|
|
7167
|
+
domainLabel: "Notification settings",
|
|
7168
|
+
multiAppSuccessMessage: "All notification captures completed successfully.",
|
|
7169
|
+
createContainer: createNotificationCliContainer,
|
|
7170
|
+
captureFn: captureNotification,
|
|
7171
|
+
saveFn: saveNotification,
|
|
7172
|
+
getConfigFilePath: (config) => config.notificationFilePath,
|
|
7173
|
+
resolveContainerConfig: resolveNotificationContainerConfig,
|
|
7174
|
+
resolveAppContainerConfig: resolveNotificationAppContainerConfig
|
|
7175
|
+
}),
|
|
6978
7176
|
diff: createDiffCommand({
|
|
6979
7177
|
description: "Compare local notification config with remote kintone app",
|
|
6980
7178
|
args: notificationArgs,
|
|
@@ -7033,56 +7231,6 @@ async function applyPlugin({ container }) {
|
|
|
7033
7231
|
});
|
|
7034
7232
|
}
|
|
7035
7233
|
//#endregion
|
|
7036
|
-
//#region src/cli/pluginConfig.ts
|
|
7037
|
-
const pluginArgs = {
|
|
7038
|
-
...kintoneArgs,
|
|
7039
|
-
...multiAppArgs,
|
|
7040
|
-
"plugin-file": {
|
|
7041
|
-
type: "string",
|
|
7042
|
-
description: "Plugin file path (default: plugins.yaml)"
|
|
7043
|
-
}
|
|
7044
|
-
};
|
|
7045
|
-
const { resolveFilePath: resolvePluginFilePath, resolveContainerConfig: resolvePluginContainerConfig, resolveAppContainerConfig: resolvePluginAppContainerConfig } = createDomainConfigResolver({
|
|
7046
|
-
fileArgKey: "plugin-file",
|
|
7047
|
-
envVar: () => process.env.PLUGIN_FILE_PATH,
|
|
7048
|
-
appFileField: (a) => a.pluginFile,
|
|
7049
|
-
defaultDir: "plugin",
|
|
7050
|
-
defaultFileName: "plugins.yaml",
|
|
7051
|
-
buildConfig: (base, filePath) => ({
|
|
7052
|
-
...base,
|
|
7053
|
-
pluginFilePath: filePath
|
|
7054
|
-
})
|
|
7055
|
-
});
|
|
7056
|
-
//#endregion
|
|
7057
|
-
//#region src/cli/commands/plugin/apply.ts
|
|
7058
|
-
var apply_default$6 = createApplyCommand({
|
|
7059
|
-
description: "Apply plugins from YAML to kintone app",
|
|
7060
|
-
args: pluginArgs,
|
|
7061
|
-
spinnerMessage: "Applying plugins...",
|
|
7062
|
-
spinnerStopMessage: "Plugins applied.",
|
|
7063
|
-
successMessage: "Plugins applied successfully.",
|
|
7064
|
-
createContainer: createPluginCliContainer,
|
|
7065
|
-
applyFn: applyPlugin,
|
|
7066
|
-
resolveContainerConfig: resolvePluginContainerConfig,
|
|
7067
|
-
resolveAppContainerConfig: resolvePluginAppContainerConfig
|
|
7068
|
-
});
|
|
7069
|
-
//#endregion
|
|
7070
|
-
//#region src/cli/commands/plugin/capture.ts
|
|
7071
|
-
var capture_default$7 = createCaptureCommand({
|
|
7072
|
-
description: "Capture current plugins from kintone app to file",
|
|
7073
|
-
args: pluginArgs,
|
|
7074
|
-
spinnerMessage: "Capturing plugins...",
|
|
7075
|
-
spinnerStopMessage: "Plugins captured.",
|
|
7076
|
-
domainLabel: "Plugins",
|
|
7077
|
-
multiAppSuccessMessage: "All plugin captures completed successfully.",
|
|
7078
|
-
createContainer: createPluginCliContainer,
|
|
7079
|
-
captureFn: capturePlugin,
|
|
7080
|
-
saveFn: savePlugin,
|
|
7081
|
-
getConfigFilePath: (config) => config.pluginFilePath,
|
|
7082
|
-
resolveContainerConfig: resolvePluginContainerConfig,
|
|
7083
|
-
resolveAppContainerConfig: resolvePluginAppContainerConfig
|
|
7084
|
-
});
|
|
7085
|
-
//#endregion
|
|
7086
7234
|
//#region src/core/domain/plugin/services/diffDetector.ts
|
|
7087
7235
|
const PluginDiffDetector = { detect: (local, remote) => {
|
|
7088
7236
|
const entries = [];
|
|
@@ -7125,13 +7273,61 @@ async function detectPluginDiff({ container }) {
|
|
|
7125
7273
|
});
|
|
7126
7274
|
}
|
|
7127
7275
|
//#endregion
|
|
7276
|
+
//#region src/cli/pluginConfig.ts
|
|
7277
|
+
const pluginArgs = {
|
|
7278
|
+
...kintoneArgs,
|
|
7279
|
+
...multiAppArgs,
|
|
7280
|
+
"plugin-file": {
|
|
7281
|
+
type: "string",
|
|
7282
|
+
description: "Plugin file path (default: plugins.yaml)"
|
|
7283
|
+
}
|
|
7284
|
+
};
|
|
7285
|
+
const { resolveFilePath: resolvePluginFilePath, resolveContainerConfig: resolvePluginContainerConfig, resolveAppContainerConfig: resolvePluginAppContainerConfig } = createDomainConfigResolver({
|
|
7286
|
+
fileArgKey: "plugin-file",
|
|
7287
|
+
envVar: () => process.env.PLUGIN_FILE_PATH,
|
|
7288
|
+
appFileField: (a) => a.pluginFile,
|
|
7289
|
+
defaultDir: "plugin",
|
|
7290
|
+
defaultFileName: "plugins.yaml",
|
|
7291
|
+
buildConfig: (base, filePath) => ({
|
|
7292
|
+
...base,
|
|
7293
|
+
pluginFilePath: filePath
|
|
7294
|
+
})
|
|
7295
|
+
});
|
|
7296
|
+
//#endregion
|
|
7128
7297
|
//#region src/cli/commands/plugin/index.ts
|
|
7129
7298
|
var plugin_default = define({
|
|
7130
7299
|
name: "plugin",
|
|
7131
7300
|
description: "Manage kintone plugins",
|
|
7132
7301
|
subCommands: {
|
|
7133
|
-
apply:
|
|
7134
|
-
|
|
7302
|
+
apply: createApplyCommand({
|
|
7303
|
+
description: "Apply plugins from YAML to kintone app",
|
|
7304
|
+
args: pluginArgs,
|
|
7305
|
+
spinnerMessage: "Applying plugins...",
|
|
7306
|
+
spinnerStopMessage: "Plugins applied.",
|
|
7307
|
+
successMessage: "Plugins applied successfully.",
|
|
7308
|
+
createContainer: createPluginCliContainer,
|
|
7309
|
+
applyFn: applyPlugin,
|
|
7310
|
+
diffPreview: {
|
|
7311
|
+
detectDiff: detectPluginDiff,
|
|
7312
|
+
printResult: printPluginDiffResult
|
|
7313
|
+
},
|
|
7314
|
+
resolveContainerConfig: resolvePluginContainerConfig,
|
|
7315
|
+
resolveAppContainerConfig: resolvePluginAppContainerConfig
|
|
7316
|
+
}),
|
|
7317
|
+
capture: createCaptureCommand({
|
|
7318
|
+
description: "Capture current plugins from kintone app to file",
|
|
7319
|
+
args: pluginArgs,
|
|
7320
|
+
spinnerMessage: "Capturing plugins...",
|
|
7321
|
+
spinnerStopMessage: "Plugins captured.",
|
|
7322
|
+
domainLabel: "Plugins",
|
|
7323
|
+
multiAppSuccessMessage: "All plugin captures completed successfully.",
|
|
7324
|
+
createContainer: createPluginCliContainer,
|
|
7325
|
+
captureFn: capturePlugin,
|
|
7326
|
+
saveFn: savePlugin,
|
|
7327
|
+
getConfigFilePath: (config) => config.pluginFilePath,
|
|
7328
|
+
resolveContainerConfig: resolvePluginContainerConfig,
|
|
7329
|
+
resolveAppContainerConfig: resolvePluginAppContainerConfig
|
|
7330
|
+
}),
|
|
7135
7331
|
diff: createDiffCommand({
|
|
7136
7332
|
description: "Compare local plugin config with remote kintone app",
|
|
7137
7333
|
args: pluginArgs,
|
|
@@ -7266,59 +7462,6 @@ async function applyProcessManagement({ container }) {
|
|
|
7266
7462
|
};
|
|
7267
7463
|
}
|
|
7268
7464
|
//#endregion
|
|
7269
|
-
//#region src/cli/processConfig.ts
|
|
7270
|
-
const processArgs = {
|
|
7271
|
-
...kintoneArgs,
|
|
7272
|
-
...multiAppArgs,
|
|
7273
|
-
"process-file": {
|
|
7274
|
-
type: "string",
|
|
7275
|
-
description: "Process management file path (default: process.yaml)"
|
|
7276
|
-
}
|
|
7277
|
-
};
|
|
7278
|
-
const { resolveFilePath: resolveProcessFilePath, resolveContainerConfig: resolveProcessContainerConfig, resolveAppContainerConfig: resolveProcessAppContainerConfig } = createDomainConfigResolver({
|
|
7279
|
-
fileArgKey: "process-file",
|
|
7280
|
-
envVar: () => process.env.PROCESS_FILE_PATH,
|
|
7281
|
-
appFileField: (a) => a.processFile,
|
|
7282
|
-
defaultDir: "process",
|
|
7283
|
-
defaultFileName: "process.yaml",
|
|
7284
|
-
buildConfig: (base, filePath) => ({
|
|
7285
|
-
...base,
|
|
7286
|
-
processFilePath: filePath
|
|
7287
|
-
})
|
|
7288
|
-
});
|
|
7289
|
-
//#endregion
|
|
7290
|
-
//#region src/cli/commands/process/apply.ts
|
|
7291
|
-
var apply_default$5 = createApplyCommand({
|
|
7292
|
-
description: "Apply process management settings from YAML to kintone app",
|
|
7293
|
-
args: processArgs,
|
|
7294
|
-
spinnerMessage: "Applying process management settings...",
|
|
7295
|
-
spinnerStopMessage: "Process management settings applied.",
|
|
7296
|
-
successMessage: "Process management settings applied successfully.",
|
|
7297
|
-
createContainer: createProcessManagementCliContainer,
|
|
7298
|
-
applyFn: applyProcessManagement,
|
|
7299
|
-
onResult: (result) => {
|
|
7300
|
-
if (result.enableChanged) p.log.warn(result.newEnable ? "Process management will be ENABLED. This activates workflow processing for this app." : "Process management will be DISABLED. This deactivates workflow processing for this app.");
|
|
7301
|
-
},
|
|
7302
|
-
resolveContainerConfig: resolveProcessContainerConfig,
|
|
7303
|
-
resolveAppContainerConfig: resolveProcessAppContainerConfig
|
|
7304
|
-
});
|
|
7305
|
-
//#endregion
|
|
7306
|
-
//#region src/cli/commands/process/capture.ts
|
|
7307
|
-
var capture_default$6 = createCaptureCommand({
|
|
7308
|
-
description: "Capture current process management settings from kintone app to file",
|
|
7309
|
-
args: processArgs,
|
|
7310
|
-
spinnerMessage: "Capturing process management settings...",
|
|
7311
|
-
spinnerStopMessage: "Process management settings captured.",
|
|
7312
|
-
domainLabel: "Process management settings",
|
|
7313
|
-
multiAppSuccessMessage: "All process management captures completed successfully.",
|
|
7314
|
-
createContainer: createProcessManagementCliContainer,
|
|
7315
|
-
captureFn: captureProcessManagement,
|
|
7316
|
-
saveFn: saveProcessManagement,
|
|
7317
|
-
getConfigFilePath: (config) => config.processFilePath,
|
|
7318
|
-
resolveContainerConfig: resolveProcessContainerConfig,
|
|
7319
|
-
resolveAppContainerConfig: resolveProcessAppContainerConfig
|
|
7320
|
-
});
|
|
7321
|
-
//#endregion
|
|
7322
7465
|
//#region src/core/domain/processManagement/services/diffDetector.ts
|
|
7323
7466
|
function isEntityEqual(a, b) {
|
|
7324
7467
|
if (a.type !== b.type) return false;
|
|
@@ -7430,13 +7573,64 @@ async function detectProcessManagementDiff({ container }) {
|
|
|
7430
7573
|
});
|
|
7431
7574
|
}
|
|
7432
7575
|
//#endregion
|
|
7576
|
+
//#region src/cli/processConfig.ts
|
|
7577
|
+
const processArgs = {
|
|
7578
|
+
...kintoneArgs,
|
|
7579
|
+
...multiAppArgs,
|
|
7580
|
+
"process-file": {
|
|
7581
|
+
type: "string",
|
|
7582
|
+
description: "Process management file path (default: process.yaml)"
|
|
7583
|
+
}
|
|
7584
|
+
};
|
|
7585
|
+
const { resolveFilePath: resolveProcessFilePath, resolveContainerConfig: resolveProcessContainerConfig, resolveAppContainerConfig: resolveProcessAppContainerConfig } = createDomainConfigResolver({
|
|
7586
|
+
fileArgKey: "process-file",
|
|
7587
|
+
envVar: () => process.env.PROCESS_FILE_PATH,
|
|
7588
|
+
appFileField: (a) => a.processFile,
|
|
7589
|
+
defaultDir: "process",
|
|
7590
|
+
defaultFileName: "process.yaml",
|
|
7591
|
+
buildConfig: (base, filePath) => ({
|
|
7592
|
+
...base,
|
|
7593
|
+
processFilePath: filePath
|
|
7594
|
+
})
|
|
7595
|
+
});
|
|
7596
|
+
//#endregion
|
|
7433
7597
|
//#region src/cli/commands/process/index.ts
|
|
7434
7598
|
var process_default = define({
|
|
7435
7599
|
name: "process",
|
|
7436
7600
|
description: "Manage kintone process management settings",
|
|
7437
7601
|
subCommands: {
|
|
7438
|
-
apply:
|
|
7439
|
-
|
|
7602
|
+
apply: createApplyCommand({
|
|
7603
|
+
description: "Apply process management settings from YAML to kintone app",
|
|
7604
|
+
args: processArgs,
|
|
7605
|
+
spinnerMessage: "Applying process management settings...",
|
|
7606
|
+
spinnerStopMessage: "Process management settings applied.",
|
|
7607
|
+
successMessage: "Process management settings applied successfully.",
|
|
7608
|
+
createContainer: createProcessManagementCliContainer,
|
|
7609
|
+
applyFn: applyProcessManagement,
|
|
7610
|
+
onResult: (result) => {
|
|
7611
|
+
if (result.enableChanged) p.log.warn(result.newEnable ? "Process management will be ENABLED. This activates workflow processing for this app." : "Process management will be DISABLED. This deactivates workflow processing for this app.");
|
|
7612
|
+
},
|
|
7613
|
+
diffPreview: {
|
|
7614
|
+
detectDiff: detectProcessManagementDiff,
|
|
7615
|
+
printResult: printProcessDiffResult
|
|
7616
|
+
},
|
|
7617
|
+
resolveContainerConfig: resolveProcessContainerConfig,
|
|
7618
|
+
resolveAppContainerConfig: resolveProcessAppContainerConfig
|
|
7619
|
+
}),
|
|
7620
|
+
capture: createCaptureCommand({
|
|
7621
|
+
description: "Capture current process management settings from kintone app to file",
|
|
7622
|
+
args: processArgs,
|
|
7623
|
+
spinnerMessage: "Capturing process management settings...",
|
|
7624
|
+
spinnerStopMessage: "Process management settings captured.",
|
|
7625
|
+
domainLabel: "Process management settings",
|
|
7626
|
+
multiAppSuccessMessage: "All process management captures completed successfully.",
|
|
7627
|
+
createContainer: createProcessManagementCliContainer,
|
|
7628
|
+
captureFn: captureProcessManagement,
|
|
7629
|
+
saveFn: saveProcessManagement,
|
|
7630
|
+
getConfigFilePath: (config) => config.processFilePath,
|
|
7631
|
+
resolveContainerConfig: resolveProcessContainerConfig,
|
|
7632
|
+
resolveAppContainerConfig: resolveProcessAppContainerConfig
|
|
7633
|
+
}),
|
|
7440
7634
|
diff: createDiffCommand({
|
|
7441
7635
|
description: "Compare local process management settings with remote kintone app",
|
|
7442
7636
|
args: processArgs,
|
|
@@ -7524,56 +7718,6 @@ async function applyRecordPermission({ container }) {
|
|
|
7524
7718
|
});
|
|
7525
7719
|
}
|
|
7526
7720
|
//#endregion
|
|
7527
|
-
//#region src/cli/recordAclConfig.ts
|
|
7528
|
-
const recordAclArgs = {
|
|
7529
|
-
...kintoneArgs,
|
|
7530
|
-
...multiAppArgs,
|
|
7531
|
-
"record-acl-file": {
|
|
7532
|
-
type: "string",
|
|
7533
|
-
description: "Record ACL file path (default: record-acl.yaml)"
|
|
7534
|
-
}
|
|
7535
|
-
};
|
|
7536
|
-
const { resolveFilePath: resolveRecordAclFilePath, resolveContainerConfig: resolveRecordAclContainerConfig, resolveAppContainerConfig: resolveRecordAclAppContainerConfig } = createDomainConfigResolver({
|
|
7537
|
-
fileArgKey: "record-acl-file",
|
|
7538
|
-
envVar: () => process.env.RECORD_ACL_FILE_PATH,
|
|
7539
|
-
appFileField: (a) => a.recordAclFile,
|
|
7540
|
-
defaultDir: "record-acl",
|
|
7541
|
-
defaultFileName: "record-acl.yaml",
|
|
7542
|
-
buildConfig: (base, filePath) => ({
|
|
7543
|
-
...base,
|
|
7544
|
-
recordAclFilePath: filePath
|
|
7545
|
-
})
|
|
7546
|
-
});
|
|
7547
|
-
//#endregion
|
|
7548
|
-
//#region src/cli/commands/record-acl/apply.ts
|
|
7549
|
-
var apply_default$4 = createApplyCommand({
|
|
7550
|
-
description: "Apply record access permissions from YAML to kintone app",
|
|
7551
|
-
args: recordAclArgs,
|
|
7552
|
-
spinnerMessage: "Applying record access permissions...",
|
|
7553
|
-
spinnerStopMessage: "Record access permissions applied.",
|
|
7554
|
-
successMessage: "Record access permissions applied successfully.",
|
|
7555
|
-
createContainer: createRecordPermissionCliContainer,
|
|
7556
|
-
applyFn: applyRecordPermission,
|
|
7557
|
-
resolveContainerConfig: resolveRecordAclContainerConfig,
|
|
7558
|
-
resolveAppContainerConfig: resolveRecordAclAppContainerConfig
|
|
7559
|
-
});
|
|
7560
|
-
//#endregion
|
|
7561
|
-
//#region src/cli/commands/record-acl/capture.ts
|
|
7562
|
-
var capture_default$5 = createCaptureCommand({
|
|
7563
|
-
description: "Capture current record access permissions from kintone app to file",
|
|
7564
|
-
args: recordAclArgs,
|
|
7565
|
-
spinnerMessage: "Capturing record access permissions...",
|
|
7566
|
-
spinnerStopMessage: "Record access permissions captured.",
|
|
7567
|
-
domainLabel: "Record ACL",
|
|
7568
|
-
multiAppSuccessMessage: "All record ACL captures completed successfully.",
|
|
7569
|
-
createContainer: createRecordPermissionCliContainer,
|
|
7570
|
-
captureFn: captureRecordPermission,
|
|
7571
|
-
saveFn: saveRecordPermission,
|
|
7572
|
-
getConfigFilePath: (config) => config.recordAclFilePath,
|
|
7573
|
-
resolveContainerConfig: resolveRecordAclContainerConfig,
|
|
7574
|
-
resolveAppContainerConfig: resolveRecordAclAppContainerConfig
|
|
7575
|
-
});
|
|
7576
|
-
//#endregion
|
|
7577
7721
|
//#region src/core/domain/recordPermission/services/diffDetector.ts
|
|
7578
7722
|
function isRightEqual(a, b) {
|
|
7579
7723
|
return deepEqual(a.entities.map((e) => ({
|
|
@@ -7620,7 +7764,7 @@ function compareRightsForFilter(filterCond, localRights, remoteRights, entries)
|
|
|
7620
7764
|
});
|
|
7621
7765
|
else if (localRight && remoteRight) {
|
|
7622
7766
|
if (!isRightEqual(localRight, remoteRight)) {
|
|
7623
|
-
const detail = localRight.entities.length !== remoteRight.entities.length ? `entities: ${remoteRight.entities.length} -> ${localRight.entities.length}` :
|
|
7767
|
+
const detail = localRight.entities.length !== remoteRight.entities.length ? `entities: ${remoteRight.entities.length} -> ${localRight.entities.length}` : `entities: ${describeRight(localRight)}`;
|
|
7624
7768
|
entries.push({
|
|
7625
7769
|
type: "modified",
|
|
7626
7770
|
filterCond,
|
|
@@ -7654,13 +7798,61 @@ async function detectRecordPermissionDiff({ container }) {
|
|
|
7654
7798
|
});
|
|
7655
7799
|
}
|
|
7656
7800
|
//#endregion
|
|
7801
|
+
//#region src/cli/recordAclConfig.ts
|
|
7802
|
+
const recordAclArgs = {
|
|
7803
|
+
...kintoneArgs,
|
|
7804
|
+
...multiAppArgs,
|
|
7805
|
+
"record-acl-file": {
|
|
7806
|
+
type: "string",
|
|
7807
|
+
description: "Record ACL file path (default: record-acl.yaml)"
|
|
7808
|
+
}
|
|
7809
|
+
};
|
|
7810
|
+
const { resolveFilePath: resolveRecordAclFilePath, resolveContainerConfig: resolveRecordAclContainerConfig, resolveAppContainerConfig: resolveRecordAclAppContainerConfig } = createDomainConfigResolver({
|
|
7811
|
+
fileArgKey: "record-acl-file",
|
|
7812
|
+
envVar: () => process.env.RECORD_ACL_FILE_PATH,
|
|
7813
|
+
appFileField: (a) => a.recordAclFile,
|
|
7814
|
+
defaultDir: "record-acl",
|
|
7815
|
+
defaultFileName: "record-acl.yaml",
|
|
7816
|
+
buildConfig: (base, filePath) => ({
|
|
7817
|
+
...base,
|
|
7818
|
+
recordAclFilePath: filePath
|
|
7819
|
+
})
|
|
7820
|
+
});
|
|
7821
|
+
//#endregion
|
|
7657
7822
|
//#region src/cli/commands/record-acl/index.ts
|
|
7658
7823
|
var record_acl_default = define({
|
|
7659
7824
|
name: "record-acl",
|
|
7660
7825
|
description: "Manage kintone record access permissions",
|
|
7661
7826
|
subCommands: {
|
|
7662
|
-
apply:
|
|
7663
|
-
|
|
7827
|
+
apply: createApplyCommand({
|
|
7828
|
+
description: "Apply record access permissions from YAML to kintone app",
|
|
7829
|
+
args: recordAclArgs,
|
|
7830
|
+
spinnerMessage: "Applying record access permissions...",
|
|
7831
|
+
spinnerStopMessage: "Record access permissions applied.",
|
|
7832
|
+
successMessage: "Record access permissions applied successfully.",
|
|
7833
|
+
createContainer: createRecordPermissionCliContainer,
|
|
7834
|
+
applyFn: applyRecordPermission,
|
|
7835
|
+
diffPreview: {
|
|
7836
|
+
detectDiff: detectRecordPermissionDiff,
|
|
7837
|
+
printResult: printRecordPermissionDiffResult
|
|
7838
|
+
},
|
|
7839
|
+
resolveContainerConfig: resolveRecordAclContainerConfig,
|
|
7840
|
+
resolveAppContainerConfig: resolveRecordAclAppContainerConfig
|
|
7841
|
+
}),
|
|
7842
|
+
capture: createCaptureCommand({
|
|
7843
|
+
description: "Capture current record access permissions from kintone app to file",
|
|
7844
|
+
args: recordAclArgs,
|
|
7845
|
+
spinnerMessage: "Capturing record access permissions...",
|
|
7846
|
+
spinnerStopMessage: "Record access permissions captured.",
|
|
7847
|
+
domainLabel: "Record ACL",
|
|
7848
|
+
multiAppSuccessMessage: "All record ACL captures completed successfully.",
|
|
7849
|
+
createContainer: createRecordPermissionCliContainer,
|
|
7850
|
+
captureFn: captureRecordPermission,
|
|
7851
|
+
saveFn: saveRecordPermission,
|
|
7852
|
+
getConfigFilePath: (config) => config.recordAclFilePath,
|
|
7853
|
+
resolveContainerConfig: resolveRecordAclContainerConfig,
|
|
7854
|
+
resolveAppContainerConfig: resolveRecordAclAppContainerConfig
|
|
7855
|
+
}),
|
|
7664
7856
|
diff: createDiffCommand({
|
|
7665
7857
|
description: "Compare local record permission config with remote kintone app",
|
|
7666
7858
|
args: recordAclArgs,
|
|
@@ -7839,56 +8031,6 @@ async function applyReport({ container }) {
|
|
|
7839
8031
|
});
|
|
7840
8032
|
}
|
|
7841
8033
|
//#endregion
|
|
7842
|
-
//#region src/cli/reportConfig.ts
|
|
7843
|
-
const reportArgs = {
|
|
7844
|
-
...kintoneArgs,
|
|
7845
|
-
...multiAppArgs,
|
|
7846
|
-
"report-file": {
|
|
7847
|
-
type: "string",
|
|
7848
|
-
description: "Report file path (default: reports.yaml)"
|
|
7849
|
-
}
|
|
7850
|
-
};
|
|
7851
|
-
const { resolveFilePath: resolveReportFilePath, resolveContainerConfig: resolveReportContainerConfig, resolveAppContainerConfig: resolveReportAppContainerConfig } = createDomainConfigResolver({
|
|
7852
|
-
fileArgKey: "report-file",
|
|
7853
|
-
envVar: () => process.env.REPORT_FILE_PATH,
|
|
7854
|
-
appFileField: (a) => a.reportFile,
|
|
7855
|
-
defaultDir: "report",
|
|
7856
|
-
defaultFileName: "reports.yaml",
|
|
7857
|
-
buildConfig: (base, filePath) => ({
|
|
7858
|
-
...base,
|
|
7859
|
-
reportFilePath: filePath
|
|
7860
|
-
})
|
|
7861
|
-
});
|
|
7862
|
-
//#endregion
|
|
7863
|
-
//#region src/cli/commands/report/apply.ts
|
|
7864
|
-
var apply_default$3 = createApplyCommand({
|
|
7865
|
-
description: "Apply report settings from YAML to kintone app",
|
|
7866
|
-
args: reportArgs,
|
|
7867
|
-
spinnerMessage: "Applying report settings...",
|
|
7868
|
-
spinnerStopMessage: "Report settings applied.",
|
|
7869
|
-
successMessage: "Report settings applied successfully.",
|
|
7870
|
-
createContainer: createReportCliContainer,
|
|
7871
|
-
applyFn: applyReport,
|
|
7872
|
-
resolveContainerConfig: resolveReportContainerConfig,
|
|
7873
|
-
resolveAppContainerConfig: resolveReportAppContainerConfig
|
|
7874
|
-
});
|
|
7875
|
-
//#endregion
|
|
7876
|
-
//#region src/cli/commands/report/capture.ts
|
|
7877
|
-
var capture_default$4 = createCaptureCommand({
|
|
7878
|
-
description: "Capture current report settings from kintone app to file",
|
|
7879
|
-
args: reportArgs,
|
|
7880
|
-
spinnerMessage: "Capturing report settings...",
|
|
7881
|
-
spinnerStopMessage: "Report settings captured.",
|
|
7882
|
-
domainLabel: "Reports",
|
|
7883
|
-
multiAppSuccessMessage: "All report captures completed successfully.",
|
|
7884
|
-
createContainer: createReportCliContainer,
|
|
7885
|
-
captureFn: captureReport,
|
|
7886
|
-
saveFn: saveReport,
|
|
7887
|
-
getConfigFilePath: (config) => config.reportFilePath,
|
|
7888
|
-
resolveContainerConfig: resolveReportContainerConfig,
|
|
7889
|
-
resolveAppContainerConfig: resolveReportAppContainerConfig
|
|
7890
|
-
});
|
|
7891
|
-
//#endregion
|
|
7892
8034
|
//#region src/core/domain/report/services/diffDetector.ts
|
|
7893
8035
|
function compareReports(local, remote) {
|
|
7894
8036
|
const diffs = [];
|
|
@@ -7937,13 +8079,61 @@ async function detectReportDiff({ container }) {
|
|
|
7937
8079
|
});
|
|
7938
8080
|
}
|
|
7939
8081
|
//#endregion
|
|
8082
|
+
//#region src/cli/reportConfig.ts
|
|
8083
|
+
const reportArgs = {
|
|
8084
|
+
...kintoneArgs,
|
|
8085
|
+
...multiAppArgs,
|
|
8086
|
+
"report-file": {
|
|
8087
|
+
type: "string",
|
|
8088
|
+
description: "Report file path (default: reports.yaml)"
|
|
8089
|
+
}
|
|
8090
|
+
};
|
|
8091
|
+
const { resolveFilePath: resolveReportFilePath, resolveContainerConfig: resolveReportContainerConfig, resolveAppContainerConfig: resolveReportAppContainerConfig } = createDomainConfigResolver({
|
|
8092
|
+
fileArgKey: "report-file",
|
|
8093
|
+
envVar: () => process.env.REPORT_FILE_PATH,
|
|
8094
|
+
appFileField: (a) => a.reportFile,
|
|
8095
|
+
defaultDir: "report",
|
|
8096
|
+
defaultFileName: "reports.yaml",
|
|
8097
|
+
buildConfig: (base, filePath) => ({
|
|
8098
|
+
...base,
|
|
8099
|
+
reportFilePath: filePath
|
|
8100
|
+
})
|
|
8101
|
+
});
|
|
8102
|
+
//#endregion
|
|
7940
8103
|
//#region src/cli/commands/report/index.ts
|
|
7941
8104
|
var report_default = define({
|
|
7942
8105
|
name: "report",
|
|
7943
8106
|
description: "Manage kintone report settings",
|
|
7944
8107
|
subCommands: {
|
|
7945
|
-
apply:
|
|
7946
|
-
|
|
8108
|
+
apply: createApplyCommand({
|
|
8109
|
+
description: "Apply report settings from YAML to kintone app",
|
|
8110
|
+
args: reportArgs,
|
|
8111
|
+
spinnerMessage: "Applying report settings...",
|
|
8112
|
+
spinnerStopMessage: "Report settings applied.",
|
|
8113
|
+
successMessage: "Report settings applied successfully.",
|
|
8114
|
+
createContainer: createReportCliContainer,
|
|
8115
|
+
applyFn: applyReport,
|
|
8116
|
+
diffPreview: {
|
|
8117
|
+
detectDiff: detectReportDiff,
|
|
8118
|
+
printResult: printReportDiffResult
|
|
8119
|
+
},
|
|
8120
|
+
resolveContainerConfig: resolveReportContainerConfig,
|
|
8121
|
+
resolveAppContainerConfig: resolveReportAppContainerConfig
|
|
8122
|
+
}),
|
|
8123
|
+
capture: createCaptureCommand({
|
|
8124
|
+
description: "Capture current report settings from kintone app to file",
|
|
8125
|
+
args: reportArgs,
|
|
8126
|
+
spinnerMessage: "Capturing report settings...",
|
|
8127
|
+
spinnerStopMessage: "Report settings captured.",
|
|
8128
|
+
domainLabel: "Reports",
|
|
8129
|
+
multiAppSuccessMessage: "All report captures completed successfully.",
|
|
8130
|
+
createContainer: createReportCliContainer,
|
|
8131
|
+
captureFn: captureReport,
|
|
8132
|
+
saveFn: saveReport,
|
|
8133
|
+
getConfigFilePath: (config) => config.reportFilePath,
|
|
8134
|
+
resolveContainerConfig: resolveReportContainerConfig,
|
|
8135
|
+
resolveAppContainerConfig: resolveReportAppContainerConfig
|
|
8136
|
+
}),
|
|
7947
8137
|
diff: createDiffCommand({
|
|
7948
8138
|
description: "Compare local report config with remote kintone app",
|
|
7949
8139
|
args: reportArgs,
|
|
@@ -9824,56 +10014,6 @@ async function applyGeneralSettings({ container }) {
|
|
|
9824
10014
|
});
|
|
9825
10015
|
}
|
|
9826
10016
|
//#endregion
|
|
9827
|
-
//#region src/cli/settingsConfig.ts
|
|
9828
|
-
const settingsArgs = {
|
|
9829
|
-
...kintoneArgs,
|
|
9830
|
-
...multiAppArgs,
|
|
9831
|
-
"settings-file": {
|
|
9832
|
-
type: "string",
|
|
9833
|
-
description: "General settings file path (default: settings.yaml)"
|
|
9834
|
-
}
|
|
9835
|
-
};
|
|
9836
|
-
const { resolveFilePath: resolveSettingsFilePath, resolveContainerConfig: resolveSettingsContainerConfig, resolveAppContainerConfig: resolveSettingsAppContainerConfig } = createDomainConfigResolver({
|
|
9837
|
-
fileArgKey: "settings-file",
|
|
9838
|
-
envVar: () => process.env.SETTINGS_FILE_PATH,
|
|
9839
|
-
appFileField: (a) => a.settingsFile,
|
|
9840
|
-
defaultDir: "settings",
|
|
9841
|
-
defaultFileName: "settings.yaml",
|
|
9842
|
-
buildConfig: (base, filePath) => ({
|
|
9843
|
-
...base,
|
|
9844
|
-
settingsFilePath: filePath
|
|
9845
|
-
})
|
|
9846
|
-
});
|
|
9847
|
-
//#endregion
|
|
9848
|
-
//#region src/cli/commands/settings/apply.ts
|
|
9849
|
-
var apply_default$1 = createApplyCommand({
|
|
9850
|
-
description: "Apply general settings from YAML to kintone app",
|
|
9851
|
-
args: settingsArgs,
|
|
9852
|
-
spinnerMessage: "Applying general settings...",
|
|
9853
|
-
spinnerStopMessage: "General settings applied.",
|
|
9854
|
-
successMessage: "General settings applied successfully.",
|
|
9855
|
-
createContainer: createGeneralSettingsCliContainer,
|
|
9856
|
-
applyFn: applyGeneralSettings,
|
|
9857
|
-
resolveContainerConfig: resolveSettingsContainerConfig,
|
|
9858
|
-
resolveAppContainerConfig: resolveSettingsAppContainerConfig
|
|
9859
|
-
});
|
|
9860
|
-
//#endregion
|
|
9861
|
-
//#region src/cli/commands/settings/capture.ts
|
|
9862
|
-
var capture_default$1 = createCaptureCommand({
|
|
9863
|
-
description: "Capture current general settings from kintone app to file",
|
|
9864
|
-
args: settingsArgs,
|
|
9865
|
-
spinnerMessage: "Capturing general settings...",
|
|
9866
|
-
spinnerStopMessage: "General settings captured.",
|
|
9867
|
-
domainLabel: "General settings",
|
|
9868
|
-
multiAppSuccessMessage: "All general settings captures completed successfully.",
|
|
9869
|
-
createContainer: createGeneralSettingsCliContainer,
|
|
9870
|
-
captureFn: captureGeneralSettings,
|
|
9871
|
-
saveFn: saveGeneralSettings,
|
|
9872
|
-
getConfigFilePath: (config) => config.settingsFilePath,
|
|
9873
|
-
resolveContainerConfig: resolveSettingsContainerConfig,
|
|
9874
|
-
resolveAppContainerConfig: resolveSettingsAppContainerConfig
|
|
9875
|
-
});
|
|
9876
|
-
//#endregion
|
|
9877
10017
|
//#region src/core/domain/generalSettings/services/diffDetector.ts
|
|
9878
10018
|
const DEFAULT_STRING = "";
|
|
9879
10019
|
const DEFAULT_BOOLEAN = false;
|
|
@@ -9946,13 +10086,61 @@ async function detectGeneralSettingsDiff({ container }) {
|
|
|
9946
10086
|
});
|
|
9947
10087
|
}
|
|
9948
10088
|
//#endregion
|
|
10089
|
+
//#region src/cli/settingsConfig.ts
|
|
10090
|
+
const settingsArgs = {
|
|
10091
|
+
...kintoneArgs,
|
|
10092
|
+
...multiAppArgs,
|
|
10093
|
+
"settings-file": {
|
|
10094
|
+
type: "string",
|
|
10095
|
+
description: "General settings file path (default: settings.yaml)"
|
|
10096
|
+
}
|
|
10097
|
+
};
|
|
10098
|
+
const { resolveFilePath: resolveSettingsFilePath, resolveContainerConfig: resolveSettingsContainerConfig, resolveAppContainerConfig: resolveSettingsAppContainerConfig } = createDomainConfigResolver({
|
|
10099
|
+
fileArgKey: "settings-file",
|
|
10100
|
+
envVar: () => process.env.SETTINGS_FILE_PATH,
|
|
10101
|
+
appFileField: (a) => a.settingsFile,
|
|
10102
|
+
defaultDir: "settings",
|
|
10103
|
+
defaultFileName: "settings.yaml",
|
|
10104
|
+
buildConfig: (base, filePath) => ({
|
|
10105
|
+
...base,
|
|
10106
|
+
settingsFilePath: filePath
|
|
10107
|
+
})
|
|
10108
|
+
});
|
|
10109
|
+
//#endregion
|
|
9949
10110
|
//#region src/cli/commands/settings/index.ts
|
|
9950
10111
|
var settings_default = define({
|
|
9951
10112
|
name: "settings",
|
|
9952
10113
|
description: "Manage kintone general settings",
|
|
9953
10114
|
subCommands: {
|
|
9954
|
-
apply:
|
|
9955
|
-
|
|
10115
|
+
apply: createApplyCommand({
|
|
10116
|
+
description: "Apply general settings from YAML to kintone app",
|
|
10117
|
+
args: settingsArgs,
|
|
10118
|
+
spinnerMessage: "Applying general settings...",
|
|
10119
|
+
spinnerStopMessage: "General settings applied.",
|
|
10120
|
+
successMessage: "General settings applied successfully.",
|
|
10121
|
+
createContainer: createGeneralSettingsCliContainer,
|
|
10122
|
+
applyFn: applyGeneralSettings,
|
|
10123
|
+
diffPreview: {
|
|
10124
|
+
detectDiff: detectGeneralSettingsDiff,
|
|
10125
|
+
printResult: printGeneralSettingsDiffResult
|
|
10126
|
+
},
|
|
10127
|
+
resolveContainerConfig: resolveSettingsContainerConfig,
|
|
10128
|
+
resolveAppContainerConfig: resolveSettingsAppContainerConfig
|
|
10129
|
+
}),
|
|
10130
|
+
capture: createCaptureCommand({
|
|
10131
|
+
description: "Capture current general settings from kintone app to file",
|
|
10132
|
+
args: settingsArgs,
|
|
10133
|
+
spinnerMessage: "Capturing general settings...",
|
|
10134
|
+
spinnerStopMessage: "General settings captured.",
|
|
10135
|
+
domainLabel: "General settings",
|
|
10136
|
+
multiAppSuccessMessage: "All general settings captures completed successfully.",
|
|
10137
|
+
createContainer: createGeneralSettingsCliContainer,
|
|
10138
|
+
captureFn: captureGeneralSettings,
|
|
10139
|
+
saveFn: saveGeneralSettings,
|
|
10140
|
+
getConfigFilePath: (config) => config.settingsFilePath,
|
|
10141
|
+
resolveContainerConfig: resolveSettingsContainerConfig,
|
|
10142
|
+
resolveAppContainerConfig: resolveSettingsAppContainerConfig
|
|
10143
|
+
}),
|
|
9956
10144
|
diff: createDiffCommand({
|
|
9957
10145
|
description: "Compare local general settings config with remote kintone app",
|
|
9958
10146
|
args: settingsArgs,
|
|
@@ -10036,59 +10224,6 @@ async function applyView({ container }) {
|
|
|
10036
10224
|
return { skippedBuiltinViews };
|
|
10037
10225
|
}
|
|
10038
10226
|
//#endregion
|
|
10039
|
-
//#region src/cli/viewConfig.ts
|
|
10040
|
-
const viewArgs = {
|
|
10041
|
-
...kintoneArgs,
|
|
10042
|
-
...multiAppArgs,
|
|
10043
|
-
"view-file": {
|
|
10044
|
-
type: "string",
|
|
10045
|
-
description: "View file path (default: views.yaml)"
|
|
10046
|
-
}
|
|
10047
|
-
};
|
|
10048
|
-
const { resolveFilePath: resolveViewFilePath, resolveContainerConfig: resolveViewContainerConfig, resolveAppContainerConfig: resolveViewAppContainerConfig } = createDomainConfigResolver({
|
|
10049
|
-
fileArgKey: "view-file",
|
|
10050
|
-
envVar: () => process.env.VIEW_FILE_PATH,
|
|
10051
|
-
appFileField: (a) => a.viewFile,
|
|
10052
|
-
defaultDir: "view",
|
|
10053
|
-
defaultFileName: "views.yaml",
|
|
10054
|
-
buildConfig: (base, filePath) => ({
|
|
10055
|
-
...base,
|
|
10056
|
-
viewFilePath: filePath
|
|
10057
|
-
})
|
|
10058
|
-
});
|
|
10059
|
-
//#endregion
|
|
10060
|
-
//#region src/cli/commands/view/apply.ts
|
|
10061
|
-
var apply_default = createApplyCommand({
|
|
10062
|
-
description: "Apply view settings from YAML to kintone app",
|
|
10063
|
-
args: viewArgs,
|
|
10064
|
-
spinnerMessage: "Applying views...",
|
|
10065
|
-
spinnerStopMessage: "Views applied.",
|
|
10066
|
-
successMessage: "Views applied successfully.",
|
|
10067
|
-
createContainer: createViewCliContainer,
|
|
10068
|
-
applyFn: applyView,
|
|
10069
|
-
onResult: (result) => {
|
|
10070
|
-
if (result.skippedBuiltinViews.length > 0) p.log.warn(`Skipped built-in views: ${result.skippedBuiltinViews.join(", ")}`);
|
|
10071
|
-
},
|
|
10072
|
-
resolveContainerConfig: resolveViewContainerConfig,
|
|
10073
|
-
resolveAppContainerConfig: resolveViewAppContainerConfig
|
|
10074
|
-
});
|
|
10075
|
-
//#endregion
|
|
10076
|
-
//#region src/cli/commands/view/capture.ts
|
|
10077
|
-
var capture_default = createCaptureCommand({
|
|
10078
|
-
description: "Capture current view settings from kintone app to file",
|
|
10079
|
-
args: viewArgs,
|
|
10080
|
-
spinnerMessage: "Capturing views...",
|
|
10081
|
-
spinnerStopMessage: "Views captured.",
|
|
10082
|
-
domainLabel: "Views",
|
|
10083
|
-
multiAppSuccessMessage: "All view captures completed successfully.",
|
|
10084
|
-
createContainer: createViewCliContainer,
|
|
10085
|
-
captureFn: captureView,
|
|
10086
|
-
saveFn: saveView,
|
|
10087
|
-
getConfigFilePath: (config) => config.viewFilePath,
|
|
10088
|
-
resolveContainerConfig: resolveViewContainerConfig,
|
|
10089
|
-
resolveAppContainerConfig: resolveViewAppContainerConfig
|
|
10090
|
-
});
|
|
10091
|
-
//#endregion
|
|
10092
10227
|
//#region src/core/domain/view/services/diffDetector.ts
|
|
10093
10228
|
function checkOptionalStringChange(changes, field, localVal, remoteVal) {
|
|
10094
10229
|
if ((localVal ?? "") !== (remoteVal ?? "")) changes.push(`${field} changed`);
|
|
@@ -10110,10 +10245,10 @@ function describeChanges(local, remote) {
|
|
|
10110
10245
|
}
|
|
10111
10246
|
const ViewDiffDetector = { detect: (localViews, remoteViews) => {
|
|
10112
10247
|
return buildDiffResult(detectRecordDiff(localViews, remoteViews, {
|
|
10113
|
-
onAdded: (name) => ({
|
|
10248
|
+
onAdded: (name, localView) => ({
|
|
10114
10249
|
type: "added",
|
|
10115
10250
|
viewName: name,
|
|
10116
|
-
details:
|
|
10251
|
+
details: `new ${localView.type} view`
|
|
10117
10252
|
}),
|
|
10118
10253
|
onModified: (name, localView, remoteView) => {
|
|
10119
10254
|
const changes = describeChanges(localView, remoteView);
|
|
@@ -10123,10 +10258,10 @@ const ViewDiffDetector = { detect: (localViews, remoteViews) => {
|
|
|
10123
10258
|
details: changes.join(", ")
|
|
10124
10259
|
};
|
|
10125
10260
|
},
|
|
10126
|
-
onDeleted: (name) => ({
|
|
10261
|
+
onDeleted: (name, remoteView) => ({
|
|
10127
10262
|
type: "deleted",
|
|
10128
10263
|
viewName: name,
|
|
10129
|
-
details:
|
|
10264
|
+
details: `removed ${remoteView.type} view`
|
|
10130
10265
|
})
|
|
10131
10266
|
}));
|
|
10132
10267
|
} };
|
|
@@ -10142,13 +10277,64 @@ async function detectViewDiff({ container }) {
|
|
|
10142
10277
|
});
|
|
10143
10278
|
}
|
|
10144
10279
|
//#endregion
|
|
10280
|
+
//#region src/cli/viewConfig.ts
|
|
10281
|
+
const viewArgs = {
|
|
10282
|
+
...kintoneArgs,
|
|
10283
|
+
...multiAppArgs,
|
|
10284
|
+
"view-file": {
|
|
10285
|
+
type: "string",
|
|
10286
|
+
description: "View file path (default: views.yaml)"
|
|
10287
|
+
}
|
|
10288
|
+
};
|
|
10289
|
+
const { resolveFilePath: resolveViewFilePath, resolveContainerConfig: resolveViewContainerConfig, resolveAppContainerConfig: resolveViewAppContainerConfig } = createDomainConfigResolver({
|
|
10290
|
+
fileArgKey: "view-file",
|
|
10291
|
+
envVar: () => process.env.VIEW_FILE_PATH,
|
|
10292
|
+
appFileField: (a) => a.viewFile,
|
|
10293
|
+
defaultDir: "view",
|
|
10294
|
+
defaultFileName: "views.yaml",
|
|
10295
|
+
buildConfig: (base, filePath) => ({
|
|
10296
|
+
...base,
|
|
10297
|
+
viewFilePath: filePath
|
|
10298
|
+
})
|
|
10299
|
+
});
|
|
10300
|
+
//#endregion
|
|
10145
10301
|
//#region src/cli/commands/view/index.ts
|
|
10146
10302
|
var view_default = define({
|
|
10147
10303
|
name: "view",
|
|
10148
10304
|
description: "Manage kintone view settings",
|
|
10149
10305
|
subCommands: {
|
|
10150
|
-
apply:
|
|
10151
|
-
|
|
10306
|
+
apply: createApplyCommand({
|
|
10307
|
+
description: "Apply view settings from YAML to kintone app",
|
|
10308
|
+
args: viewArgs,
|
|
10309
|
+
spinnerMessage: "Applying views...",
|
|
10310
|
+
spinnerStopMessage: "Views applied.",
|
|
10311
|
+
successMessage: "Views applied successfully.",
|
|
10312
|
+
createContainer: createViewCliContainer,
|
|
10313
|
+
applyFn: applyView,
|
|
10314
|
+
onResult: (result) => {
|
|
10315
|
+
if (result.skippedBuiltinViews.length > 0) p.log.warn(`Skipped built-in views: ${result.skippedBuiltinViews.join(", ")}`);
|
|
10316
|
+
},
|
|
10317
|
+
diffPreview: {
|
|
10318
|
+
detectDiff: detectViewDiff,
|
|
10319
|
+
printResult: printViewDiffResult
|
|
10320
|
+
},
|
|
10321
|
+
resolveContainerConfig: resolveViewContainerConfig,
|
|
10322
|
+
resolveAppContainerConfig: resolveViewAppContainerConfig
|
|
10323
|
+
}),
|
|
10324
|
+
capture: createCaptureCommand({
|
|
10325
|
+
description: "Capture current view settings from kintone app to file",
|
|
10326
|
+
args: viewArgs,
|
|
10327
|
+
spinnerMessage: "Capturing views...",
|
|
10328
|
+
spinnerStopMessage: "Views captured.",
|
|
10329
|
+
domainLabel: "Views",
|
|
10330
|
+
multiAppSuccessMessage: "All view captures completed successfully.",
|
|
10331
|
+
createContainer: createViewCliContainer,
|
|
10332
|
+
captureFn: captureView,
|
|
10333
|
+
saveFn: saveView,
|
|
10334
|
+
getConfigFilePath: (config) => config.viewFilePath,
|
|
10335
|
+
resolveContainerConfig: resolveViewContainerConfig,
|
|
10336
|
+
resolveAppContainerConfig: resolveViewAppContainerConfig
|
|
10337
|
+
}),
|
|
10152
10338
|
diff: createDiffCommand({
|
|
10153
10339
|
description: "Compare local view config with remote kintone app",
|
|
10154
10340
|
args: viewArgs,
|