@appaflytech/zeyrek-ai-mcp 0.0.28 → 0.0.30
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/.env.example +15 -0
- package/README.md +5 -5
- package/dist/config.js +37 -0
- package/dist/index.js +2 -0
- package/dist/knowledge/access.js +802 -0
- package/dist/knowledge/backendConstraints.js +18 -1
- package/dist/knowledge/case.js +41 -0
- package/dist/knowledge/componentCatalog.js +494 -34
- package/dist/knowledge/componentEvents.js +132 -7
- package/dist/knowledge/connectDataBind.js +819 -0
- package/dist/knowledge/connectDataDefinition.js +341 -0
- package/dist/knowledge/connectDataExecute.js +93 -0
- package/dist/knowledge/connectDataRules.js +128 -0
- package/dist/knowledge/decision.js +121 -0
- package/dist/knowledge/expressionPrelude.js +59 -0
- package/dist/knowledge/layoutSummary.js +140 -2
- package/dist/knowledge/microserviceParameters.js +58 -0
- package/dist/knowledge/mining.js +94 -0
- package/dist/knowledge/mobileComponentCatalog.js +859 -0
- package/dist/knowledge/mobileComponentEvents.js +239 -0
- package/dist/knowledge/normalize.js +236 -67
- package/dist/knowledge/outlines.js +36 -0
- package/dist/knowledge/platform/lint.js +385 -0
- package/dist/knowledge/platform/mobile.js +142 -0
- package/dist/knowledge/platform/mobileLayoutLint.js +324 -0
- package/dist/knowledge/platform/mobileRules.js +231 -0
- package/dist/knowledge/platform/mobileSpacing.js +82 -0
- package/dist/knowledge/platform/mobileTabs.js +108 -0
- package/dist/knowledge/platform/nativeBoxModel.js +44 -0
- package/dist/knowledge/platform/profile.js +25 -0
- package/dist/knowledge/platform/resolve.js +122 -0
- package/dist/knowledge/platform/web.js +39 -0
- package/dist/knowledge/policy.js +18 -4
- package/dist/knowledge/process.js +510 -0
- package/dist/knowledge/reservedTables.js +79 -0
- package/dist/knowledge/rowFilter.js +43 -0
- package/dist/knowledge/rules.js +319 -21
- package/dist/knowledge/schemaGuard.js +11 -0
- package/dist/knowledge/styleResolve.js +50 -4
- package/dist/knowledge/styleResolveNative.js +527 -0
- package/dist/knowledge/themeResolve.js +3 -3
- package/dist/observability/trace.js +6 -3
- package/dist/platform/argumentAliases.js +128 -0
- package/dist/platform/bodyFile.js +103 -0
- package/dist/platform/capture/actions.js +333 -0
- package/dist/platform/capture/browser.js +1 -0
- package/dist/platform/{screenshot.js → capture/capture.js} +105 -519
- package/dist/platform/capture/console-log.js +122 -0
- package/dist/platform/capture/index.js +11 -0
- package/dist/platform/capture/readiness.js +103 -0
- package/dist/platform/capture/summary.js +77 -0
- package/dist/platform/capture/target.js +5 -0
- package/dist/platform/capture/targets/studio-mobile.js +15 -0
- package/dist/platform/capture/targets/studio-web.js +5 -0
- package/dist/platform/diagnostics.js +10 -4
- package/dist/platform/domSummary.js +1 -1
- package/dist/platform/errors.js +162 -10
- package/dist/platform/http.js +29 -8
- package/dist/platform/impersonation.js +45 -0
- package/dist/platform/jsonArray.js +24 -0
- package/dist/platform/responses.js +39 -5
- package/dist/platform/schemaReadMemory.js +60 -0
- package/dist/platform/secrets.js +17 -1
- package/dist/platform/strictArguments.js +68 -12
- package/dist/platform/tokenVault.js +187 -4
- package/dist/resources/examples/bpm-gorev-kontrol.json +294 -0
- package/dist/resources/examples/bpm-iso-dokuman.json +228 -0
- package/dist/resources/examples/bpm-satinalma.json +376 -0
- package/dist/resources/examples/connect-data-convert-verify.json +107 -0
- package/dist/resources/examples/connect-data-dropdown-roles.json +66 -0
- package/dist/resources/examples/connect-data-edit-m2m.json +73 -0
- package/dist/resources/examples/connect-data-query-params.json +50 -0
- package/dist/resources/examples/connect-data-table-entity.json +147 -0
- package/dist/resources/examples/connect-data-workflow-microservice.json +65 -0
- package/dist/resources/examples/mobile-app-shell-drawer.json +243 -0
- package/dist/resources/examples/mobile-app-shell-stack.json +157 -0
- package/dist/resources/examples/mobile-app-shell-tab.json +208 -0
- package/dist/resources/examples/mobile-form-screen.json +365 -0
- package/dist/resources/examples/mobile-list-detail-form.json +672 -0
- package/dist/resources/examples/page-detail-profile.json +2 -1
- package/dist/resources/examples/page-dynamic-form.json +3 -2
- package/dist/resources/examples/page-flex-sections.json +1 -1
- package/dist/resources/examples/page-html-embed.json +1 -1
- package/dist/resources/examples/workflow-basic.json +8 -2
- package/dist/resources/guides/access.md +796 -0
- package/dist/resources/guides/bpm.md +686 -0
- package/dist/resources/guides/case.md +153 -0
- package/dist/resources/guides/component.md +91 -4
- package/dist/resources/guides/decision.md +185 -0
- package/dist/resources/guides/entity.md +50 -8
- package/dist/resources/guides/expressions.md +14 -5
- package/dist/resources/guides/functions.md +1 -1
- package/dist/resources/guides/getting-started.md +38 -1
- package/dist/resources/guides/layout.md +11 -7
- package/dist/resources/guides/microservice.md +81 -2
- package/dist/resources/guides/middleware.md +44 -2
- package/dist/resources/guides/mobile-layout.md +193 -0
- package/dist/resources/guides/mobile.md +495 -0
- package/dist/resources/guides/page.md +454 -75
- package/dist/resources/guides/theme.md +8 -2
- package/dist/resources/guides/translation.md +1 -1
- package/dist/resources/guides/workflow.md +58 -1
- package/dist/resources/read.js +41 -0
- package/dist/resources/rules.js +11 -5
- package/dist/resources/schema-fingerprint.json +7 -5
- package/dist/resources/schemas/AccessExplanationDto.json +144 -0
- package/dist/resources/schemas/AccessMatrixDto.json +170 -0
- package/dist/resources/schemas/AccessPermissionDto.json +57 -0
- package/dist/resources/schemas/AccessPolicyDto.json +223 -0
- package/dist/resources/schemas/AccessResourceDto.json +86 -0
- package/dist/resources/schemas/AppSessionDto.json +53 -0
- package/dist/resources/schemas/ConnectDataDescribeDto.json +344 -0
- package/dist/resources/schemas/ConnectDataRequestModel.json +202 -0
- package/dist/resources/schemas/ConnectDataResultDto.json +421 -0
- package/dist/resources/schemas/ConnectorCredentialDto.json +70 -0
- package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +37 -0
- package/dist/resources/schemas/CreateAccessPolicyCommand.json +209 -0
- package/dist/resources/schemas/CreateDecisionCommand.json +221 -0
- package/dist/resources/schemas/CreateEntityCommand.json +118 -0
- package/dist/resources/schemas/CreateMicroserviceCommand.json +13 -1
- package/dist/resources/schemas/CreateProcessDefinitionCommand.json +1337 -0
- package/dist/resources/schemas/CreateQueryCommand.json +4 -0
- package/dist/resources/schemas/CreateWorkflowCommand.json +143 -1
- package/dist/resources/schemas/DataJobDto.json +6 -1
- package/dist/resources/schemas/DecisionDto.json +302 -0
- package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +28 -0
- package/dist/resources/schemas/ExplainAccessQuery.json +33 -0
- package/dist/resources/schemas/GenerateProcessDocumentCommand.json +116 -0
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +21 -1
- package/dist/resources/schemas/MicroserviceDto.json +15 -3
- package/dist/resources/schemas/OrganizationProjectDto.json +335 -0
- package/dist/resources/schemas/OrganizationSchemaDto.json +196 -0
- package/dist/resources/schemas/OrganizationSchemaVersionDto.json +207 -0
- package/dist/resources/schemas/PatchProcessDefinitionCommand.json +76 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +10 -1
- package/dist/resources/schemas/PreviewWorkflowCommand.json +22 -1
- package/dist/resources/schemas/ProcessDefinitionDto.json +1480 -0
- package/dist/resources/schemas/ProcessSimulationDto.json +96 -0
- package/dist/resources/schemas/SaveConnectorCredentialCommand.json +90 -0
- package/dist/resources/schemas/SaveProcessEventSourceCommand.json +61 -0
- package/dist/resources/schemas/SaveProcessMailSourceCommand.json +89 -0
- package/dist/resources/schemas/SignProcessTaskCommand.json +73 -0
- package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +92 -0
- package/dist/resources/schemas/StepDto.json +22 -1
- package/dist/resources/schemas/UpdateAccessPolicyCommand.json +209 -0
- package/dist/resources/schemas/UpdateDecisionCommand.json +216 -0
- package/dist/resources/schemas/UpdateEntityCommand.json +118 -0
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +13 -1
- package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +1357 -0
- package/dist/resources/schemas/UpdateQueryCommand.json +4 -0
- package/dist/resources/schemas/UpdateViewCommand.json +0 -2
- package/dist/resources/schemas/UpdateWorkflowCommand.json +143 -1
- package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +1339 -0
- package/dist/server.js +27 -1
- package/dist/tools/access.js +369 -2
- package/dist/tools/accessOperations.js +135 -0
- package/dist/tools/accessPolicies.js +170 -0
- package/dist/tools/accessRuntime.js +203 -0
- package/dist/tools/applications.js +60 -3
- package/dist/tools/bpm.js +343 -0
- package/dist/tools/bpmGovernance.js +266 -0
- package/dist/tools/bpmOperations.js +230 -0
- package/dist/tools/bpmReporting.js +154 -0
- package/dist/tools/bpmRouting.js +150 -0
- package/dist/tools/bpmRuntime.js +396 -0
- package/dist/tools/case.js +178 -0
- package/dist/tools/caseRuntime.js +89 -0
- package/dist/tools/common.js +7 -0
- package/dist/tools/components.js +118 -14
- package/dist/tools/connectData.js +449 -0
- package/dist/tools/connectors.js +193 -0
- package/dist/tools/datasources.js +3 -3
- package/dist/tools/decisions.js +206 -0
- package/dist/tools/dependencies.js +1 -1
- package/dist/tools/deployments.js +2 -2
- package/dist/tools/designSchemaPatch.js +34 -9
- package/dist/tools/dtos.js +36 -5
- package/dist/tools/entities.js +79 -12
- package/dist/tools/externalComponents.js +26 -5
- package/dist/tools/flows.js +122 -14
- package/dist/tools/folders.js +1 -1
- package/dist/tools/imports.js +5 -2
- package/dist/tools/layouts.js +50 -17
- package/dist/tools/merges.js +1 -1
- package/dist/tools/microservices.js +77 -25
- package/dist/tools/mobile.js +221 -0
- package/dist/tools/modules.js +48 -0
- package/dist/tools/organizationStructure.js +137 -0
- package/dist/tools/pages.js +465 -98
- package/dist/tools/platformInfo.js +27 -8
- package/dist/tools/profileWrite.js +92 -0
- package/dist/tools/projects.js +71 -9
- package/dist/tools/rows.js +69 -13
- package/dist/tools/schemaOps.js +61 -1
- package/dist/tools/screenWrite.js +37 -8
- package/dist/tools/screens.js +95 -5
- package/dist/tools/templates.js +26 -1
- package/dist/tools/translations.js +1 -1
- package/dist/tools/variables.js +11 -5
- package/dist/tools/workflows.js +10 -5
- package/package.json +2 -2
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { logStep } from '../observability/trace.js';
|
|
2
2
|
import { PlatformApiError } from '../platform/errors.js';
|
|
3
3
|
import { ensureWorkflowErrorPath } from './errorPath.js';
|
|
4
|
-
import { TYPED_STYLE_COMPONENTS } from './styleResolve.js';
|
|
4
|
+
import { DOCUMENT_STYLE_TYPES, TYPED_STYLE_COMPONENTS } from './styleResolve.js';
|
|
5
|
+
import { STATE_STORAGE_KINDS, STEP_ALIASES } from './platform/profile.js';
|
|
6
|
+
import { inlineStyleFields } from './componentCatalog.js';
|
|
5
7
|
const SORT_DEFAULT = { name: 'sortField', type: 'sortType', source: 'query-string' };
|
|
6
8
|
const LIMIT_DEFAULT = { name: 'limit', offset: 'offset', source: 'query-string' };
|
|
7
9
|
function asArray(value) {
|
|
@@ -269,12 +271,11 @@ export function normalizeWorkflowDefinition(definition) {
|
|
|
269
271
|
*/
|
|
270
272
|
/**
|
|
271
273
|
* Adım tipi sözlüğü backend'in, KOŞAN tipler barındırıcının: motor yedi tip register eder, web
|
|
272
|
-
* `Runtime.svelte` altı, mobil `
|
|
274
|
+
* `Runtime.svelte` altı, mobil `runtime-tasks.ts` yedi tip ekler ve aynı sayfa kaydı ikisinde de
|
|
273
275
|
* koşar. Register edilmemiş bir tipe gelen akış sessizce ölür (`flow-engine.ts` `process()`
|
|
274
276
|
* callback bulamazsa next/completed/stopped hiç çağrılmaz), üstelik `run()` promise'i
|
|
275
277
|
* çözülmediği için `__ngAppsFlowActivity.running` sıfıra inmez. İki hâl tamamen türetilebilir
|
|
276
|
-
* olduğu için lint değil NORMALİZASYON
|
|
277
|
-
* uygulama tarafında kapanabilir, `FLOW-023` onları uyarır.
|
|
278
|
+
* olduğu için lint değil NORMALİZASYON; `FLOW-023` kalan hâlleri uyarır.
|
|
278
279
|
*/
|
|
279
280
|
function normalizeFlowHostGaps(steps, list) {
|
|
280
281
|
const fixes = [];
|
|
@@ -288,12 +289,15 @@ function normalizeFlowHostGaps(steps, list) {
|
|
|
288
289
|
.map(step => String(step.stepId ?? ''))
|
|
289
290
|
.filter(id => id.length > 0));
|
|
290
291
|
for (const step of list) {
|
|
291
|
-
// navigate ile redirect'in argümanı AYNI ({ path, pageId, query, targetBlank })
|
|
292
|
-
// yalnız mobil register eder; redirect ise iki barındırıcıda da koşar (mobilde
|
|
293
|
-
// uygulamasına eşlenir), yani redirect kesin üstün.
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
292
|
+
// navigate ile redirect'in argümanı AYNI ({ path, pageId, query, targetBlank, presentation })
|
|
293
|
+
// ama navigate'i yalnız mobil register eder; redirect ise iki barındırıcıda da koşar (mobilde
|
|
294
|
+
// aynı navigate uygulamasına eşlenir), yani redirect kesin üstün. `presentation`
|
|
295
|
+
// (push | modal | replace) yalnız mobil barındırıcıda okunur; web yok sayar.
|
|
296
|
+
const alias = STEP_ALIASES[String(step.type ?? '')];
|
|
297
|
+
if (alias) {
|
|
298
|
+
const original = String(step.type);
|
|
299
|
+
step.type = alias;
|
|
300
|
+
fixes.push(`'${label(step)}': type ${original} → ${alias} yazıldı — argüman şekli aynı ({ path, pageId, query, targetBlank, presentation }) ama ${original}'i web barındırıcısı register etmez, ${alias} ikisinde de koşar`);
|
|
297
301
|
}
|
|
298
302
|
if (endStepIds.size === 0)
|
|
299
303
|
continue;
|
|
@@ -369,9 +373,17 @@ const REQUIRED_COLLECTIONS = ['events', 'validations', 'stateBindings', 'childre
|
|
|
369
373
|
// PropValueType (DesignComponentProperty.cs:421) — 'translation' listeden düşünce çeviriye bağlı
|
|
370
374
|
// prop'un KENDİSİ veri sanılıp static Prop'a sarılıyordu: istek 200 dönüyor, prop bozuk kuruluyordu
|
|
371
375
|
// (09-04 Y-22). Enum burada eksiksiz tutulur.
|
|
372
|
-
export const PROP_VALUE_TYPES = new Set(['static', 'file', 'flow', 'widget', 'element', 'page', 'code', 'translation']);
|
|
376
|
+
export const PROP_VALUE_TYPES = new Set(['static', 'file', 'flow', 'widget', 'element', 'page', 'code', 'translation', 'connectData']);
|
|
377
|
+
// Prop'un TAŞIYICISI da aranır: `type` tek başına yetmez, çünkü liste öğesinin kendi `type` alanı
|
|
378
|
+
// olabilir ve değeri Prop tipi adıyla çakışabilir — datatable kolonunda dosya alanı tam olarak
|
|
379
|
+
// böyledir (`{ name, label, type: 'file', isFilterable }`). Yalnız `type`'a bakan sürüm o öğeyi
|
|
380
|
+
// kurulu bir Prop sanıp sarmadan bırakıyordu ve platform 500 JsonException veriyordu (koşu
|
|
381
|
+
// bulgusu S-2'nin gateway ayağı; Studio ayağı `staticFieldListItems` ile aynı kararı verdi).
|
|
373
382
|
function isPropShaped(value) {
|
|
374
|
-
|
|
383
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
384
|
+
return false;
|
|
385
|
+
const candidate = value;
|
|
386
|
+
return PROP_VALUE_TYPES.has(String(candidate.type)) && ('data' in candidate || 'ref' in candidate);
|
|
375
387
|
}
|
|
376
388
|
function wrapPropDictionaryValues(dictionary) {
|
|
377
389
|
let wrapped = false;
|
|
@@ -614,12 +626,16 @@ export function codePropTemplateErrors(ops) {
|
|
|
614
626
|
*
|
|
615
627
|
* Seçici anahtarlara (`&__body`, `:hover`, `--token`) DOKUNULMAZ; yalnız `a-b` biçimli düz CSS
|
|
616
628
|
* özellik adları camelCase'e çevrilir ve çevrim `gatewayNormalized` ile bildirilir.
|
|
629
|
+
*
|
|
630
|
+
* TB-129 — `inlineFields` verilirse o ÜST DÜZEY alanların altına hiç girilmez: `table.style.th`
|
|
631
|
+
* gibi dallar satır içi `style` attribute'una basılır ve kebab-case zorunludur
|
|
632
|
+
* (`INLINE_STYLE_FIELDS_BY_TYPE`). Çeviri orada stili öldürüyordu.
|
|
617
633
|
*/
|
|
618
634
|
const styleKeyPattern = /^[a-z][a-z0-9]*(-[a-z0-9]+)+$/;
|
|
619
635
|
export function isStylePropName(name) {
|
|
620
636
|
return name === 'style' || /Style$/.test(name);
|
|
621
637
|
}
|
|
622
|
-
export function normalizeStyleKeys(value, label, fixed) {
|
|
638
|
+
export function normalizeStyleKeys(value, label, fixed, inlineFields) {
|
|
623
639
|
if (Array.isArray(value)) {
|
|
624
640
|
for (const entry of value)
|
|
625
641
|
normalizeStyleKeys(entry, label, fixed);
|
|
@@ -628,7 +644,10 @@ export function normalizeStyleKeys(value, label, fixed) {
|
|
|
628
644
|
if (!value || typeof value !== 'object')
|
|
629
645
|
return;
|
|
630
646
|
const record = value;
|
|
647
|
+
const skipped = new Set(inlineFields ?? []);
|
|
631
648
|
for (const key of Object.keys(record)) {
|
|
649
|
+
if (skipped.has(key))
|
|
650
|
+
continue;
|
|
632
651
|
normalizeStyleKeys(record[key], label, fixed);
|
|
633
652
|
if (!styleKeyPattern.test(key))
|
|
634
653
|
continue;
|
|
@@ -650,6 +669,44 @@ export function styleKeyNote(fixed) {
|
|
|
650
669
|
+ 'değer kaydedilir ama hiç uygulanmaz ve tek işareti tarayıcı konsoludur (F-06). '
|
|
651
670
|
+ "Seçici anahtarlara ('&__body', ':hover', '--token') dokunulmadı."];
|
|
652
671
|
}
|
|
672
|
+
/**
|
|
673
|
+
* Kabın `states.isDroppable`ı KATALOĞUN kararıdır. Gateway düğümü kurarken bu alanı
|
|
674
|
+
* yazmıyordu (`DEFAULT_STATES` hepsini `false` bırakır) ve Studio kanvası düğümü kap saymıyordu:
|
|
675
|
+
* imleç `scroll-view`un İÇİNDEYKEN bırakma planı sayfa kabına düşüyor, çizgi kabın üst kenarına
|
|
676
|
+
* çiziliyordu (ölçüldü 2026-09-21, `test/mobile app` › `Satislar`). Aynı tipi paletten ekleyen
|
|
677
|
+
* Studio katalog değerini yazdığı için tek şemada iki türlü davranan kap oluyordu.
|
|
678
|
+
*
|
|
679
|
+
* Değer uygulamanın KENDİ sözlüğünden gelir (`listComponents`; mobil uygulamada `type=mobile`
|
|
680
|
+
* satırları), yani kural platformdan bağımsızdır ve kuruluşun kendi komponentlerini de kapsar.
|
|
681
|
+
* Yalnız `true` yazılır: katalog bir tipi kap saymıyorsa düğüme dokunulmaz.
|
|
682
|
+
*/
|
|
683
|
+
export function normalizeDroppableStates(nodes, droppable) {
|
|
684
|
+
const fixed = [];
|
|
685
|
+
if (droppable.size === 0)
|
|
686
|
+
return fixed;
|
|
687
|
+
for (const node of asObjects(nodes)) {
|
|
688
|
+
const type = typeof node.type === 'string' ? node.type : '';
|
|
689
|
+
if (droppable.get(type) === true) {
|
|
690
|
+
// `states` normalde `normalizeComponentDefaults`tan geçmiş olur; gelmediyse burada da
|
|
691
|
+
// eksiksiz kurulur — yarım `states` platformda NullReference üretir.
|
|
692
|
+
if (!node.states || typeof node.states !== 'object' || Array.isArray(node.states)) {
|
|
693
|
+
node.states = { ...DEFAULT_STATES };
|
|
694
|
+
}
|
|
695
|
+
const states = node.states;
|
|
696
|
+
if (states.isDroppable !== true) {
|
|
697
|
+
states.isDroppable = true;
|
|
698
|
+
fixed.push(`'${String(node.elementId ?? node.name ?? type)}' (${type})`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
fixed.push(...normalizeDroppableStates(node.children, droppable));
|
|
702
|
+
}
|
|
703
|
+
return fixed;
|
|
704
|
+
}
|
|
705
|
+
export function droppableStatesNote(fixed) {
|
|
706
|
+
return fixed.length === 0
|
|
707
|
+
? []
|
|
708
|
+
: [`states.isDroppable katalogdan yazıldı (${fixed.join(' · ')}) — kataloğun kap saydığı düğüm Studio kanvasında da kap olmalı; alanı bilerek kapatmak için resize_component/set_states kullanın`];
|
|
709
|
+
}
|
|
653
710
|
export function normalizeComponentDefaults(nodes) {
|
|
654
711
|
const fixed = [];
|
|
655
712
|
for (const node of asObjects(nodes)) {
|
|
@@ -689,8 +746,10 @@ export function normalizeComponentDefaults(nodes) {
|
|
|
689
746
|
if (node.props && typeof node.props === 'object' && !Array.isArray(node.props)) {
|
|
690
747
|
const props = node.props;
|
|
691
748
|
const styleKeys = [];
|
|
749
|
+
// Satır içi stil dalları komponent TİPİNE göre atlanır; tip bilinmiyorsa eski davranış.
|
|
750
|
+
const inlineFields = (name) => name === 'style' ? inlineStyleFields(typeof node.type === 'string' ? node.type : undefined) : undefined;
|
|
692
751
|
for (const name of Object.keys(props).filter(isStylePropName)) {
|
|
693
|
-
normalizeStyleKeys(props[name], `${String(node.elementId ?? node.name ?? '?')}.${name}`, styleKeys);
|
|
752
|
+
normalizeStyleKeys(props[name], `${String(node.elementId ?? node.name ?? '?')}.${name}`, styleKeys, inlineFields(name));
|
|
694
753
|
}
|
|
695
754
|
if (styleKeys.length > 0)
|
|
696
755
|
missing.push(`stil anahtarları camelCase'e çevrildi: ${styleKeys.join(' · ')}`);
|
|
@@ -795,19 +854,31 @@ function normalizeReplacePropValue(op) {
|
|
|
795
854
|
}
|
|
796
855
|
return notes;
|
|
797
856
|
}
|
|
857
|
+
// connectData sarmalı burada değiştirilmez: gövde duvarı (CD-005, `connectDataOpIssues`) op'u
|
|
858
|
+
// set_connect_data'ya yönlendirerek rejectedOps'a yazar; burada atmak listeyi tek hataya indirirdi.
|
|
859
|
+
if (propType === 'connectData')
|
|
860
|
+
return notes;
|
|
798
861
|
// Applier her sarmalın tipini korur, ama page/file/flow/widget/element taşıyıcıları başka alanlara
|
|
799
862
|
// (FlowId, RedirectPageId, dosya) yazılır ve bu op'la bağları kurulmaz. Remove+add önerilmez:
|
|
800
863
|
// düğümü yeniden kurmak ona yazan setter iteratee'lerinin element'ini siler (G-04, FLOW-018).
|
|
801
864
|
throw new PlatformApiError(`${label}: '${propType}' tipli Prop replace_prop ile kurulmaz — bu op static, code ve translation sarmalını taşır. Komponenti silip yeniden EKLEMEYİN: ona yazan setter adımlarının hedefi silinir (FLOW-018). Akış bağı için set_event, diğer tipler için page_update(schema) ile tam şema yazın.`, 400);
|
|
802
865
|
}
|
|
803
|
-
|
|
866
|
+
/**
|
|
867
|
+
* `typesByElementId` — TB-129: `replace_prop` op'u yalnız elementId taşır, stil çevirisinin
|
|
868
|
+
* komponent tipine bakabilmesi için haritayı çağıran (okuduğu şemadan) verir. Verilmezse çeviri
|
|
869
|
+
* tip ayrımı yapmaz; bu, harita okunamadığında yazmayı engellememek için bilinçli düşüştür.
|
|
870
|
+
*/
|
|
871
|
+
export function normalizeSchemaOps(ops, typesByElementId) {
|
|
804
872
|
const components = [];
|
|
805
873
|
const props = [];
|
|
806
874
|
const validations = [];
|
|
807
875
|
for (const op of asObjects(ops)) {
|
|
808
876
|
if (op.op === 'replace_prop') {
|
|
809
877
|
if (isStylePropName(String(op.prop ?? ''))) {
|
|
810
|
-
|
|
878
|
+
const inline = String(op.prop) === 'style'
|
|
879
|
+
? inlineStyleFields(typesByElementId?.get(String(op.target ?? '')))
|
|
880
|
+
: undefined;
|
|
881
|
+
normalizeStyleKeys(op.value, `'${String(op.target ?? '?')}.${String(op.prop)}'`, props, inline);
|
|
811
882
|
}
|
|
812
883
|
props.push(...normalizeReplacePropValue(op));
|
|
813
884
|
continue;
|
|
@@ -884,11 +955,11 @@ export function pageContainerNode() {
|
|
|
884
955
|
* çekilirlerse sayfa içeriğinin akışına girer ve katman olarak açılmazlar.
|
|
885
956
|
*/
|
|
886
957
|
const ROOT_LAYER_TYPES = new Set(['modal', 'drawer']);
|
|
887
|
-
export function ensurePageContainer(schema) {
|
|
958
|
+
export function ensurePageContainer(schema, rootContainer = pageContainerNode) {
|
|
888
959
|
const nodes = asObjects(schema);
|
|
889
960
|
if (nodes.some(node => node.elementId === PAGE_CONTAINER_ELEMENT_ID))
|
|
890
961
|
return { schema: nodes, fixes: [] };
|
|
891
|
-
const container =
|
|
962
|
+
const container = rootContainer();
|
|
892
963
|
const layers = nodes.filter(node => ROOT_LAYER_TYPES.has(String(node.type ?? '')));
|
|
893
964
|
container.children = nodes.filter(node => !ROOT_LAYER_TYPES.has(String(node.type ?? '')));
|
|
894
965
|
const moved = container.children.length;
|
|
@@ -931,7 +1002,7 @@ export function clampBlockSizes(nodes, maxSizes) {
|
|
|
931
1002
|
* başlatır (`ComponentHeightType.Fixed = 0`), yani "alan yok" = "sabit yükseklik". Studio'nun
|
|
932
1003
|
* kendi bırakma yolu bunu ASLA yapmaz: katalogdaki `isDefaultAutoHeight`e bakıp
|
|
933
1004
|
* `heightType: isDefaultAutoHeight ? 'auto' : 'fixed'` yazar
|
|
934
|
-
* (`ScreenBuilderDroppable.svelte:701`, `store-converter.ts
|
|
1005
|
+
* (`ScreenBuilderDroppable.svelte:701`, `store-converter.ts` `createDefaultSchemaNode`). Katalogda varsayılan
|
|
935
1006
|
* `true`'dur (`ZeyrekComponent.ts:62`); `false` diyen yalnız sekiz tip var — auth-layout, html,
|
|
936
1007
|
* image, layout, qrcode, table, text-editor, video.
|
|
937
1008
|
*
|
|
@@ -1717,19 +1788,18 @@ export function viewAliasNote(fixes) {
|
|
|
1717
1788
|
return [`view alanlarının entity bağı id'den alias'a çevrildi (${fixes.join(', ')}): yazma tarafı viewEntityAlias ister, okuma tarafı viewEntityId döndürür — alias boş kalsa platform tüm alanları ilk tabloya düşürürdü`];
|
|
1718
1789
|
}
|
|
1719
1790
|
/**
|
|
1720
|
-
*
|
|
1721
|
-
*
|
|
1722
|
-
*
|
|
1723
|
-
* `data`'nın **JSON string** olmasıdır: "[{\"key\":\"MyTest\",\"value\":{\"isActive\":true}}]".
|
|
1724
|
-
* `Data` tipi `object` olduğu için platform her gövdeyi kabul eder; alan adı tutmayan bir gövde
|
|
1725
|
-
* (name/type/defaultValue gibi) `Data`'yı null bırakır ve istek 200 döner ama HİÇBİR ŞEY yazılmaz
|
|
1726
|
-
* (17/Ç1). Okuma tarafı da aynı string'i geri verir (`AppVariablesDto.Map` → GetRawText).
|
|
1791
|
+
* `storage` kayıtta isteğe bağlıdır (`docs/adr/0004-state-saklama-turu.md`). Tanınmayan tür ya da
|
|
1792
|
+
* metin olmayan değer çalışma zamanında da yok sayılır (`@ng-apps/ui-native` `variableStorageKinds`);
|
|
1793
|
+
* gateway onu taşımaz ki bir sonraki yazım bozuk değeri kalıcılaştırmasın.
|
|
1727
1794
|
*/
|
|
1728
1795
|
export function parseVariableEntries(data) {
|
|
1729
1796
|
const source = typeof data === 'string' ? safeParse(data) : data;
|
|
1730
1797
|
return asObjects(source)
|
|
1731
1798
|
.filter(entry => typeof entry.key === 'string' && entry.key !== '')
|
|
1732
|
-
.map(entry =>
|
|
1799
|
+
.map(entry => {
|
|
1800
|
+
const storage = STATE_STORAGE_KINDS.find(kind => kind === entry.storage);
|
|
1801
|
+
return { key: String(entry.key), value: entry.value, ...(storage ? { storage } : {}) };
|
|
1802
|
+
});
|
|
1733
1803
|
}
|
|
1734
1804
|
function safeParse(value) {
|
|
1735
1805
|
try {
|
|
@@ -1744,17 +1814,29 @@ function safeParse(value) {
|
|
|
1744
1814
|
* mevcut seti okuyup anahtar bazında birleştirir; `replace: true` verilirse bilinçli olarak ezer.
|
|
1745
1815
|
*/
|
|
1746
1816
|
export function mergeVariableEntries(existing, incoming, replace) {
|
|
1817
|
+
const stored = (entry, current) => {
|
|
1818
|
+
const storage = entry.storage === undefined ? current?.storage : STATE_STORAGE_KINDS.find(kind => kind === entry.storage);
|
|
1819
|
+
const value = entry.value === undefined ? (current ? current.value : null) : entry.value;
|
|
1820
|
+
return { key: entry.key, value, ...(storage ? { storage } : {}) };
|
|
1821
|
+
};
|
|
1747
1822
|
if (replace)
|
|
1748
|
-
return { entries: incoming, fixes: [] };
|
|
1823
|
+
return { entries: incoming.map(entry => stored(entry)), fixes: [] };
|
|
1749
1824
|
const merged = [...existing];
|
|
1750
1825
|
const kept = [];
|
|
1826
|
+
const keptStorage = [];
|
|
1827
|
+
const keptValue = [];
|
|
1751
1828
|
for (const entry of incoming) {
|
|
1752
1829
|
const index = merged.findIndex(current => current.key === entry.key);
|
|
1753
1830
|
if (index === -1) {
|
|
1754
|
-
merged.push(entry);
|
|
1831
|
+
merged.push(stored(entry));
|
|
1755
1832
|
continue;
|
|
1756
1833
|
}
|
|
1757
|
-
merged[index]
|
|
1834
|
+
const current = merged[index];
|
|
1835
|
+
if (entry.storage === undefined && current?.storage)
|
|
1836
|
+
keptStorage.push(`'${entry.key}' → ${current.storage}`);
|
|
1837
|
+
if (entry.value === undefined)
|
|
1838
|
+
keptValue.push(`'${entry.key}'`);
|
|
1839
|
+
merged[index] = stored(entry, current);
|
|
1758
1840
|
}
|
|
1759
1841
|
for (const entry of existing) {
|
|
1760
1842
|
if (!incoming.some(current => current.key === entry.key))
|
|
@@ -1762,9 +1844,17 @@ export function mergeVariableEntries(existing, incoming, replace) {
|
|
|
1762
1844
|
}
|
|
1763
1845
|
return {
|
|
1764
1846
|
entries: merged,
|
|
1765
|
-
fixes:
|
|
1766
|
-
|
|
1767
|
-
|
|
1847
|
+
fixes: [
|
|
1848
|
+
...(kept.length > 0
|
|
1849
|
+
? [`mevcut değişkenler korundu (${kept.join(', ')}): uç seti komple değiştirir, gateway anahtar bazında birleştirdi — kasten silmek için replace: true verin`]
|
|
1850
|
+
: []),
|
|
1851
|
+
...(keptStorage.length > 0
|
|
1852
|
+
? [`saklama türü korundu (${keptStorage.join(', ')}): gelen değişken storage taşımıyordu, kayıttaki tür silinmedi — belleğe çevirmek için storage: 'memory' verin`]
|
|
1853
|
+
: []),
|
|
1854
|
+
...(keptValue.length > 0
|
|
1855
|
+
? [`değer korundu (${keptValue.join(', ')}): gelen değişken value taşımıyordu, kayıttaki değer silinmedi — boşaltmak için value: null verin`]
|
|
1856
|
+
: [])
|
|
1857
|
+
]
|
|
1768
1858
|
};
|
|
1769
1859
|
}
|
|
1770
1860
|
export function blockSizeNote(clamped) {
|
|
@@ -1845,12 +1935,22 @@ export function nestedRepeaterNodes(nodes) {
|
|
|
1845
1935
|
walk(asObjects(nodes), false);
|
|
1846
1936
|
return found;
|
|
1847
1937
|
}
|
|
1848
|
-
|
|
1849
|
-
|
|
1938
|
+
/**
|
|
1939
|
+
* Mobil profilde gruplu listenin (gün/kategori başlığı altında satırlar) hazır bileşeni vardır:
|
|
1940
|
+
* `grouped-list` (ui-native, ADR 0007). Web'de karşılığı yok — web mesajı textarea tarifinde kalır.
|
|
1941
|
+
*/
|
|
1942
|
+
export function nestedRepeaterMessage(ids, platform = 'web') {
|
|
1943
|
+
const measured = `PAGE-013 — repeater içinde repeater (istek gönderilmedi): ${ids.join(' · ')}. `
|
|
1850
1944
|
+ 'Ölçüldü (2026-08-19): iç repeater OKUMADA çalışır ama girilen değer dış satıra GERİ YAZILMAZ '
|
|
1851
1945
|
+ '(_repeaterValues null kalır) ve tek düzenlemeden sonra DOM bozulur. Sebep yapısal: şemada iç '
|
|
1852
|
-
+ 'repeater tek düğümdür, dış satır başına ayrı düğüm yoktur.
|
|
1853
|
-
|
|
1946
|
+
+ 'repeater tek düğümdür, dış satır başına ayrı düğüm yoktur. ';
|
|
1947
|
+
const textarea = "Satır içi listeyi tek bir textarea ile topla (satır başına bir öğe) ve kaydederken split('\n') ile böl — platform_guide('page') Kural 1g.";
|
|
1948
|
+
if (platform !== 'mobile')
|
|
1949
|
+
return measured + textarea;
|
|
1950
|
+
return measured
|
|
1951
|
+
+ 'Başlıklar altında gruplanmış liste (güne/kategoriye göre) için mobilde tek `grouped-list` kur: düz `rows` + '
|
|
1952
|
+
+ '`groupBy` alan yolu; çocuk 0 bölüm başlığı (`{{ Section.title }}`), çocuk 1 öğe şablonu (`Row`, `{{ item.<alan> }}`) — '
|
|
1953
|
+
+ "platform_guide('mobile') §Güne göre görev listesi. Satır içinde düzenlenen alt liste gerekiyorsa: " + textarea;
|
|
1854
1954
|
}
|
|
1855
1955
|
/**
|
|
1856
1956
|
* `style` prop'u düz CSS STRING verilmiş düğümler. Çalışır (emotion string'i CSS metni sayar) ama
|
|
@@ -1864,7 +1964,7 @@ export function stringStyleNodes(nodes) {
|
|
|
1864
1964
|
for (const node of list) {
|
|
1865
1965
|
const props = (node.props ?? {});
|
|
1866
1966
|
const style = props.style;
|
|
1867
|
-
if (style && typeof style.data === 'string' && style.data.includes(':')) {
|
|
1967
|
+
if (style && typeof style.data === 'string' && style.data.includes(':') && !DOCUMENT_STYLE_TYPES.has(String(node.type))) {
|
|
1868
1968
|
found.push(String(node.elementId ?? node.name ?? '?'));
|
|
1869
1969
|
}
|
|
1870
1970
|
walk(asObjects(node.children));
|
|
@@ -1995,6 +2095,95 @@ export function flowBindings(schema, hostEvents) {
|
|
|
1995
2095
|
visitNode(node);
|
|
1996
2096
|
return bindings;
|
|
1997
2097
|
}
|
|
2098
|
+
/**
|
|
2099
|
+
* TB-125 — op listesi UYGULANDIKTAN sonra şemada (ve düzey olaylarında) hâlâ referanslı olan
|
|
2100
|
+
* akışlar. Simülasyon yalnız akış referansını umursar: eklenen düğüm ağacın köküne konur (konum
|
|
2101
|
+
* sayıma girmez), silinen düğüm ağaçtan çıkarılır, olay op'ları olay dizisini günceller.
|
|
2102
|
+
* `batch` op'u iç listesiyle düzleştirilir.
|
|
2103
|
+
*/
|
|
2104
|
+
function survivingFlowRefs(nodes, hostEvents, ops) {
|
|
2105
|
+
const simulated = structuredClone(nodes);
|
|
2106
|
+
const simulatedHostEvents = structuredClone(hostEvents);
|
|
2107
|
+
const removeNode = (list, target) => {
|
|
2108
|
+
const index = list.findIndex(node => node.elementId === target);
|
|
2109
|
+
if (index >= 0) {
|
|
2110
|
+
list.splice(index, 1);
|
|
2111
|
+
return true;
|
|
2112
|
+
}
|
|
2113
|
+
for (const node of list) {
|
|
2114
|
+
if (Array.isArray(node.children) && removeNode(node.children, target))
|
|
2115
|
+
return true;
|
|
2116
|
+
}
|
|
2117
|
+
return false;
|
|
2118
|
+
};
|
|
2119
|
+
const eventsOf = (target) => {
|
|
2120
|
+
if (target === 'page')
|
|
2121
|
+
return simulatedHostEvents;
|
|
2122
|
+
const node = findNodeByElementId(simulated, target);
|
|
2123
|
+
if (!node)
|
|
2124
|
+
return undefined;
|
|
2125
|
+
if (!Array.isArray(node.events))
|
|
2126
|
+
node.events = [];
|
|
2127
|
+
return node.events;
|
|
2128
|
+
};
|
|
2129
|
+
const apply = (op) => {
|
|
2130
|
+
if (op.op === 'batch') {
|
|
2131
|
+
for (const inner of asObjects(op.ops))
|
|
2132
|
+
apply(inner);
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
2135
|
+
if (op.op === 'add_component' && op.component && typeof op.component === 'object') {
|
|
2136
|
+
simulated.push(structuredClone(op.component));
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
const target = String(op.target ?? '');
|
|
2140
|
+
if (target === '')
|
|
2141
|
+
return;
|
|
2142
|
+
if (op.op === 'remove_component') {
|
|
2143
|
+
removeNode(simulated, target);
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
if (op.op !== 'set_event' && op.op !== 'add_event' && op.op !== 'remove_event')
|
|
2147
|
+
return;
|
|
2148
|
+
const events = eventsOf(target);
|
|
2149
|
+
if (events === undefined)
|
|
2150
|
+
return;
|
|
2151
|
+
const eventName = String(op.event ?? '');
|
|
2152
|
+
const eventValue = typeof op.eventValue === 'string' ? op.eventValue : undefined;
|
|
2153
|
+
const named = events.filter(event => String(event.name ?? '') === eventName && typeof event.value === 'string' && event.value !== '');
|
|
2154
|
+
if (op.op === 'add_event') {
|
|
2155
|
+
if (eventValue !== undefined)
|
|
2156
|
+
events.push({ name: eventName, value: eventValue });
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
if (op.op === 'set_event') {
|
|
2160
|
+
// set_event adın BÜTÜN bağlarını tek kayda indirir.
|
|
2161
|
+
for (const event of named)
|
|
2162
|
+
events.splice(events.indexOf(event), 1);
|
|
2163
|
+
if (eventValue !== undefined)
|
|
2164
|
+
events.push({ name: eventName, value: eventValue });
|
|
2165
|
+
return;
|
|
2166
|
+
}
|
|
2167
|
+
// Değersiz remove_event çoklu bağda platformda ambiguous-event ile düşer: hiçbir bağ kalkmaz.
|
|
2168
|
+
const removed = eventValue === undefined
|
|
2169
|
+
? (named.length === 1 ? named : [])
|
|
2170
|
+
: named.filter(event => event.value === eventValue);
|
|
2171
|
+
for (const event of removed)
|
|
2172
|
+
events.splice(events.indexOf(event), 1);
|
|
2173
|
+
};
|
|
2174
|
+
for (const op of ops)
|
|
2175
|
+
apply(op);
|
|
2176
|
+
const surviving = new Set();
|
|
2177
|
+
for (const event of simulatedHostEvents) {
|
|
2178
|
+
if (typeof event.value === 'string')
|
|
2179
|
+
surviving.add(event.value);
|
|
2180
|
+
}
|
|
2181
|
+
for (const node of simulated) {
|
|
2182
|
+
for (const flowId of collectFlowRefs(node))
|
|
2183
|
+
surviving.add(flowId);
|
|
2184
|
+
}
|
|
2185
|
+
return surviving;
|
|
2186
|
+
}
|
|
1998
2187
|
/**
|
|
1999
2188
|
* Bir yamanın SİLECEĞİ akışlar. Platform referanssız kalan akışı KALICI siler; uyarı yamadan sonra
|
|
2000
2189
|
* geldiğinde "önce yedekle" tavsiyesi uygulanamaz hâle geliyordu (09-05 koşusu: sekiz adımlı giriş
|
|
@@ -2003,26 +2192,15 @@ export function flowBindings(schema, hostEvents) {
|
|
|
2003
2192
|
*/
|
|
2004
2193
|
export function orphanedFlowPlan(schema, pageEvents, ops) {
|
|
2005
2194
|
const nodes = asObjects(schema);
|
|
2006
|
-
|
|
2195
|
+
// `batch` açılır: içindeki silme de plana girer (kapı yalnız üst düzeye bakınca batch'teki
|
|
2196
|
+
// `remove_component` akışı uyarısız siliyordu).
|
|
2197
|
+
const opList = asObjects(ops).flatMap(op => op.op === 'batch' ? asObjects(op.ops) : [op]);
|
|
2007
2198
|
const plan = [];
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
}
|
|
2014
|
-
collectFlowRefsExcept(nodes, skipElementId, surviving);
|
|
2015
|
-
if (skipEvent !== undefined) {
|
|
2016
|
-
const node = findNodeByElementId(nodes, skipElementId);
|
|
2017
|
-
for (const event of asObjects(node?.events)) {
|
|
2018
|
-
if (String(event.name ?? '') !== skipEvent && typeof event.value === 'string')
|
|
2019
|
-
surviving.add(event.value);
|
|
2020
|
-
}
|
|
2021
|
-
for (const flowId of collectFlowRefs({ ...(node ?? {}), events: [] }))
|
|
2022
|
-
surviving.add(flowId);
|
|
2023
|
-
}
|
|
2024
|
-
return surviving;
|
|
2025
|
-
};
|
|
2199
|
+
// TB-125 — hayatta kalan referanslar yamanın SONUCUNDAN okunur, op op özgün ağaçtan değil. Eski
|
|
2200
|
+
// hesap her op'a tek başına baktığı için aynı yamada başka bir düğüme bağlanan akışı da
|
|
2201
|
+
// "referanssız" sayıyor ve düğüm taşıyan her yamayı ikiye böldürüyordu (S2-35). İstek atomik
|
|
2202
|
+
// olduğuna göre doğru soru tektir: yama bittiğinde bu akışa referans kalıyor mu?
|
|
2203
|
+
const surviving = survivingFlowRefs(nodes, asObjects(pageEvents), opList);
|
|
2026
2204
|
for (const op of opList) {
|
|
2027
2205
|
const target = String(op.target ?? '');
|
|
2028
2206
|
if (target === '')
|
|
@@ -2032,7 +2210,6 @@ export function orphanedFlowPlan(schema, pageEvents, ops) {
|
|
|
2032
2210
|
if (!doomed)
|
|
2033
2211
|
continue;
|
|
2034
2212
|
const losing = collectFlowRefs(doomed);
|
|
2035
|
-
const surviving = survivingRefs(target);
|
|
2036
2213
|
const orphaned = [...losing].filter(flowId => !surviving.has(flowId));
|
|
2037
2214
|
if (orphaned.length > 0)
|
|
2038
2215
|
plan.push({ target, op: 'remove_component', flowIds: orphaned });
|
|
@@ -2054,10 +2231,7 @@ export function orphanedFlowPlan(schema, pageEvents, ops) {
|
|
|
2054
2231
|
// oraya bağlı akış kapıdan geçip kalıcı silinirdi. Düzey olayı olmayan widget'ta applier da
|
|
2055
2232
|
// düğüm aramasına düşer.
|
|
2056
2233
|
if (op.op === 'remove_event' && target === 'page' && Array.isArray(pageEvents)) {
|
|
2057
|
-
const
|
|
2058
|
-
const removed = removedBy(boundTo(hostEvents));
|
|
2059
|
-
const surviving = new Set(hostEvents.filter(event => !removed.includes(event) && typeof event.value === 'string').map(event => String(event.value)));
|
|
2060
|
-
collectFlowRefsExcept(nodes, '', surviving);
|
|
2234
|
+
const removed = removedBy(boundTo(asObjects(pageEvents)));
|
|
2061
2235
|
const flowIds = [...new Set(removed.map(event => String(event.value)))].filter(flowId => !surviving.has(flowId));
|
|
2062
2236
|
if (flowIds.length > 0)
|
|
2063
2237
|
plan.push({ target, op: 'remove_event', flowIds });
|
|
@@ -2069,11 +2243,6 @@ export function orphanedFlowPlan(schema, pageEvents, ops) {
|
|
|
2069
2243
|
const losing = op.op === 'set_event' ? named.filter(event => event.value !== eventValue) : removedBy(named);
|
|
2070
2244
|
if (losing.length === 0)
|
|
2071
2245
|
continue;
|
|
2072
|
-
const surviving = survivingRefs(target, eventName);
|
|
2073
|
-
for (const event of named) {
|
|
2074
|
-
if (!losing.includes(event))
|
|
2075
|
-
surviving.add(String(event.value));
|
|
2076
|
-
}
|
|
2077
2246
|
const flowIds = [...new Set(losing.map(event => String(event.value)))].filter(flowId => !surviving.has(flowId));
|
|
2078
2247
|
if (flowIds.length > 0)
|
|
2079
2248
|
plan.push({ target, op: String(op.op), flowIds });
|
|
@@ -357,3 +357,39 @@ export function functionOutline(definition) {
|
|
|
357
357
|
view: 'outline'
|
|
358
358
|
};
|
|
359
359
|
}
|
|
360
|
+
export function processOutline(payload) {
|
|
361
|
+
const model = (payload.definition && typeof payload.definition === 'object' ? payload.definition : payload);
|
|
362
|
+
const describeAssignee = (value) => {
|
|
363
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
364
|
+
return value ?? null;
|
|
365
|
+
const assignee = value;
|
|
366
|
+
const rule = [assignee.rule, assignee.arg].filter(part => part !== undefined && part !== null).join(':');
|
|
367
|
+
return assignee.of ? `${rule} of ${String(assignee.of)}` : rule;
|
|
368
|
+
};
|
|
369
|
+
const describeNodes = (nodes, depth) => asArray(nodes).flatMap(node => [{
|
|
370
|
+
id: node.id,
|
|
371
|
+
type: node.type,
|
|
372
|
+
depth,
|
|
373
|
+
editable: node.editable ?? 'locked',
|
|
374
|
+
description: node.description ?? null,
|
|
375
|
+
assignee: describeAssignee(node.assignee ?? node.to),
|
|
376
|
+
policy: node.policy ?? null,
|
|
377
|
+
sla: Array.isArray(node.sla) ? asArray(node.sla).map(sla => sla.duration) : node.sla ?? null,
|
|
378
|
+
on: asArray(node.on).map(handler => `${String(handler.event)} → ${String(handler.handler?.type ?? '?')}${handler.afterHandlers ? ` (${String(handler.afterHandlers)})` : ''}`)
|
|
379
|
+
}, ...describeNodes(node.nodes, depth + 1)]);
|
|
380
|
+
const nodes = describeNodes(model.nodes, 0);
|
|
381
|
+
return {
|
|
382
|
+
id: payload.id ?? null,
|
|
383
|
+
slug: model.slug ?? payload.slug,
|
|
384
|
+
name: model.name ?? payload.name,
|
|
385
|
+
version: payload.version ?? null,
|
|
386
|
+
activeVersionId: payload.activeVersionId ?? null,
|
|
387
|
+
versions: asArray(payload.versions).map(version => ({ number: version.number, state: version.state })),
|
|
388
|
+
nodeCount: nodes.length,
|
|
389
|
+
nodes,
|
|
390
|
+
edgeCount: asArray(model.edges).length,
|
|
391
|
+
on: asArray(model.on).map(handler => String(handler.event)),
|
|
392
|
+
view: 'outline',
|
|
393
|
+
hint: "Tek düğüm için process_definition_get view:'part', part:'definition.nodes[id=<düğüm>]'; değişiklik için process_definition_patch (yol /nodes[id=<düğüm>]/…)."
|
|
394
|
+
};
|
|
395
|
+
}
|