@appaflytech/zeyrek-ai-mcp 0.0.8 → 0.0.10
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/README.md +27 -21
- package/dist/config.js +2 -0
- package/dist/knowledge/componentCatalog.js +122 -27
- package/dist/knowledge/componentEvents.js +35 -4
- package/dist/knowledge/errorPath.js +1 -1
- package/dist/knowledge/normalize.js +15 -0
- package/dist/knowledge/outlines.js +24 -7
- package/dist/knowledge/rules.js +3 -1
- package/dist/knowledge/styleResolve.js +46 -4
- package/dist/knowledge/themeResolve.js +936 -0
- package/dist/knowledge/themeRules.js +221 -0
- package/dist/knowledge/themeSchema.js +335 -0
- package/dist/platform/domSummary.js +144 -0
- package/dist/platform/screenshot.js +414 -23
- package/dist/platform/screenshotMemory.js +55 -0
- package/dist/resources/examples/layout-app-shell.json +1 -1
- package/dist/resources/examples/theme-brand.json +162 -0
- package/dist/resources/guides/component.md +7 -1
- package/dist/resources/guides/getting-started.md +4 -0
- package/dist/resources/guides/layout.md +30 -26
- package/dist/resources/guides/microservice.md +55 -1
- package/dist/resources/guides/page.md +87 -44
- package/dist/resources/guides/theme.md +210 -0
- package/dist/resources/guides/translation.md +6 -4
- package/dist/resources/guides/workflow.md +91 -6
- package/dist/resources/schema-fingerprint.json +2 -2
- package/dist/server.js +52 -43
- package/dist/tools/components.js +8 -0
- package/dist/tools/designSchemaPatch.js +152 -0
- package/dist/tools/flows.js +15 -18
- package/dist/tools/layouts.js +4 -4
- package/dist/tools/microservices.js +5 -5
- package/dist/tools/pages.js +196 -323
- package/dist/tools/projects.js +66 -9
- package/dist/tools/schemaOps.js +280 -0
- package/dist/tools/screenWrite.js +2 -1
- package/dist/tools/screens.js +0 -7
- package/dist/tools/themes.js +163 -0
- package/dist/tools/workflows.js +1 -1
- package/package.json +2 -2
- package/dist/tools/globalFunctions.js +0 -63
package/README.md
CHANGED
|
@@ -4,10 +4,10 @@ Zeyrek (NgApps) platformunu **MCP tool'ları** olarak sunan bağımsız gateway.
|
|
|
4
4
|
oturumu Studio arayüzüne hiç girmeden proje kurabilir, veri modeli çıkarabilir, mikroservis ve
|
|
5
5
|
workflow yazıp çalıştırabilir, sayfa tasarlayabilir.
|
|
6
6
|
|
|
7
|
-
- **
|
|
7
|
+
- **208 tool · 34 modül** — veri/mantık tarafı (project, application, datasource, entity, row,
|
|
8
8
|
import, microservice, query, workflow, automation, function, dto, view, dependency), Studio
|
|
9
|
-
tasarım tarafı (page, component, external component, flow, layout, variable, function,
|
|
10
|
-
file, access, translation), yönetim (template, organization, deployment) ve proje dallanması
|
|
9
|
+
tasarım tarafı (page, **theme**, component, external component, flow, layout, variable, function,
|
|
10
|
+
folder, file, access, translation), yönetim (template, organization, deployment) ve proje dallanması
|
|
11
11
|
(environment, merge).
|
|
12
12
|
- Platform koduna referans vermez: Organization.API ile Tenant.API'yi **HTTP üzerinden** sarar —
|
|
13
13
|
istekler MVC binding'den geçtiği için FluentValidation aynen çalışır.
|
|
@@ -29,7 +29,7 @@ ekleyin:
|
|
|
29
29
|
"zeyrek-ai": {
|
|
30
30
|
"type": "stdio",
|
|
31
31
|
"command": "npx",
|
|
32
|
-
"args": ["-y", "@appaflytech/zeyrek-ai-mcp@
|
|
32
|
+
"args": ["-y", "@appaflytech/zeyrek-ai-mcp@latest", "--stdio"],
|
|
33
33
|
"env": {
|
|
34
34
|
"ORG_API_BASE_URL": "https://new-zeyrek.glomil.com/api/org",
|
|
35
35
|
"TENANT_API_BASE_URL": "https://new-zeyrek.glomil.com/api",
|
|
@@ -56,7 +56,7 @@ claude mcp add zeyrek-ai \
|
|
|
56
56
|
-e DEFAULT_ENVIRONMENT=development \
|
|
57
57
|
-e USERNAME=admin@zeyrek.com \
|
|
58
58
|
-e PASSWORD='parolanız' \
|
|
59
|
-
-- npx -y @appaflytech/zeyrek-ai-mcp@
|
|
59
|
+
-- npx -y @appaflytech/zeyrek-ai-mcp@latest --stdio
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
**İlk doğrulama:** oturumda `platform_whoami` tool'unu çağırtın — kimlik, org çözümü ve ağ
|
|
@@ -64,9 +64,10 @@ erişimi tek seferde test edilir. Tool listesi boş geliyorsa Sorun giderme böl
|
|
|
64
64
|
|
|
65
65
|
### Sürüm seçimi
|
|
66
66
|
|
|
67
|
-
`@
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
`@latest` önerilir: `main`'e giren her gateway değişikliği CI'da otomatik yayınlanır (bkz.
|
|
68
|
+
Yayınlama), yeni sürüm MCP sunucusu yeniden başlatılınca gelir. npx kopyayı önbelleğe aldığı
|
|
69
|
+
için eski sürümde kalan makinede `~/.npm/_npx` silinip sunucu yeniden başlatılır. Herkesin aynı
|
|
70
|
+
gateway'i çalıştırması gereken işlerde (koşu, kabul testi) `@0.0.8` gibi sabit sürüm yazın.
|
|
70
71
|
|
|
71
72
|
---
|
|
72
73
|
|
|
@@ -138,10 +139,10 @@ ya da ikisi karışık (`core,page`). `platform` modülü (3 tool) her kümede v
|
|
|
138
139
|
|
|
139
140
|
| Küme | Tool | Modüller |
|
|
140
141
|
|---|---|---|
|
|
141
|
-
| `core` |
|
|
142
|
-
| `studio` |
|
|
143
|
-
| `admin` |
|
|
144
|
-
| (boş) | **
|
|
142
|
+
| `core` | 136 | platform, project, application, datasource, entity, row, import, microservice, microfunction, query, workflow, automation, function, dto, view, dependency, environment, merge, activity, revision |
|
|
143
|
+
| `studio` | 78 | platform, page, theme, component, externalComponent, flow, layout, variable, function, folder, file, import, access, translation, revision |
|
|
144
|
+
| `admin` | 27 | platform, template, organization, deployment, environment, merge, activity |
|
|
145
|
+
| (boş) | **208** | 34 modülün tamamı |
|
|
145
146
|
|
|
146
147
|
Bilinmeyen bir modül/küme adı verilirse sunucu açılmaz, geçerli adları listeleyen bir hata yazar.
|
|
147
148
|
|
|
@@ -165,7 +166,8 @@ Bilinmeyen bir modül/küme adı verilirse sunucu açılmaz, geçerli adları li
|
|
|
165
166
|
`platform_guide('page')`.
|
|
166
167
|
- **Yazma tool'ları replace gövdeleri merge eder:** `page_update`, `layout_update`,
|
|
167
168
|
`component_update` kaydı önce okur, yalnız verdiğiniz alanları değiştirir; şema/olay kaybı
|
|
168
|
-
olmaz. `flow_*`
|
|
169
|
+
olmaz. `flow_*` yazmaları yalnız akışı gönderir; olay bağı `page_schema_patch` /
|
|
170
|
+
`layout_schema_patch` / `component_schema_patch` ile ayrı yazılır.
|
|
169
171
|
- **Gerçek ekran:** UI değişikliği `page_screenshot` ile doğrulanır (`STUDIO_BASE_URL` gerekir;
|
|
170
172
|
ilk kullanımda `npx playwright-core install chromium`).
|
|
171
173
|
|
|
@@ -213,7 +215,7 @@ etiketleri, diğer `LOG_*` ayarları ve maskeleme:
|
|
|
213
215
|
| `POST /connect/token` 404 / "kayıt bulunamadı" | Kimlik makine kullanıcı adıyla gidiyor — `USERNAME` üstteki üçüncü davranış maddesi. |
|
|
214
216
|
| `Host` çözülemedi / 404 | `ORGANIZATION` + `HOST_SUFFIX` birlikte `{org}.{suffix}` üretir; ikisi de doğru olmalı. |
|
|
215
217
|
| `page_screenshot` hata veriyor | `STUDIO_BASE_URL` boş ya da tarayıcı yok: `npx playwright-core install chromium` veya `SCREENSHOT_BROWSER_PATH`. |
|
|
216
|
-
| Eski sürüm çalışıyor | npx önbelleği: `.mcp.json`'da sabit sürüm yazın
|
|
218
|
+
| Eski sürüm çalışıyor | npx önbelleği: `~/.npm/_npx`'i silip sunucuyu yeniden başlatın ya da `.mcp.json`'da sabit sürüm yazın. |
|
|
217
219
|
|
|
218
220
|
Her durumda ilk bakılacak yer günlük dosyasıdır (`LOG_DIR`).
|
|
219
221
|
|
|
@@ -225,7 +227,7 @@ Gateway'i ortak bir sunucu olarak çalıştırmak için (stateless streamable HT
|
|
|
225
227
|
POST):
|
|
226
228
|
|
|
227
229
|
```bash
|
|
228
|
-
npx -y @appaflytech/zeyrek-ai-mcp@
|
|
230
|
+
npx -y @appaflytech/zeyrek-ai-mcp@latest # --stdio olmadan
|
|
229
231
|
```
|
|
230
232
|
|
|
231
233
|
Sağlık ucu: `http://localhost:5100/healthz` (port `MCP_PORT`). İstemci kaydı:
|
|
@@ -276,19 +278,23 @@ kural envanteri [`docs/08-kural-envanteri.md`](docs/08-kural-envanteri.md).
|
|
|
276
278
|
|
|
277
279
|
### Yayınlama (paket bakımcısı)
|
|
278
280
|
|
|
281
|
+
Yayın otomatiktir: `main`'e `zeyrek-mcp/` değişikliği girince CI işi `publish:mcp:npm`
|
|
282
|
+
([`scripts/ci-publish-npm.sh`](scripts/ci-publish-npm.sh)) paketi üretip npm'deki son sürümle
|
|
283
|
+
içerik olarak karşılaştırır; pakete giren dosyalar değiştiyse yeni patch sürümünü yayınlar.
|
|
284
|
+
Sürümün kaynağı npm'dir, CI `package.json`'ı geri commit'lemez. Minor/major için
|
|
285
|
+
`package.json`'daki sürümü elle yükseltip merge edin. Yayını o commit için atlamak: commit
|
|
286
|
+
mesajına `DoNotDeploy` (iş elle tetiklenir hâle gelir).
|
|
287
|
+
|
|
288
|
+
Yerelde deneme (yayın yapmaz; `npm ci` çalıştırdığı için bir kopyada ya da Linux container'da):
|
|
289
|
+
|
|
279
290
|
```bash
|
|
280
|
-
|
|
281
|
-
npm run typecheck && npm test
|
|
282
|
-
npm version patch # package.json sürümü
|
|
283
|
-
npm publish # prepack: tsc -p tsconfig.build.json + varlık kopyalama
|
|
291
|
+
DRY_RUN=1 sh scripts/ci-publish-npm.sh
|
|
284
292
|
```
|
|
285
293
|
|
|
286
294
|
`dist/` içine `src/resources/{schemas,guides,examples}` altındaki JSON/MD varlıklarını
|
|
287
295
|
`scripts/copy-assets.ts` kopyalar — `tsc` tek başına bunları taşımaz. Yayınlanan paket
|
|
288
296
|
`dist/`, `README.md` ve iki `.env` şablonundan oluşur.
|
|
289
297
|
|
|
290
|
-
Sürüm yükseldikten sonra ekipteki `.mcp.json` örneklerindeki sabit sürümü de güncelleyin.
|
|
291
|
-
|
|
292
298
|
---
|
|
293
299
|
|
|
294
300
|
## Bilinen sınırlar
|
package/dist/config.js
CHANGED
|
@@ -16,6 +16,7 @@ export const moduleNames = [
|
|
|
16
16
|
"dto",
|
|
17
17
|
"view",
|
|
18
18
|
"page",
|
|
19
|
+
"theme",
|
|
19
20
|
"component",
|
|
20
21
|
"externalComponent",
|
|
21
22
|
"flow",
|
|
@@ -61,6 +62,7 @@ export const modulePresets = {
|
|
|
61
62
|
studio: [
|
|
62
63
|
"platform",
|
|
63
64
|
"page",
|
|
65
|
+
"theme",
|
|
64
66
|
"component",
|
|
65
67
|
"externalComponent",
|
|
66
68
|
"flow",
|
|
@@ -249,7 +249,7 @@ export const componentKnowledge = {
|
|
|
249
249
|
behavior: [
|
|
250
250
|
"Yerleşim prop'ları (layout/direction/gap/gridColumns...) box ile BİREBİR aynıdır ve bileşende okunmaz — çocuk sarmalayıcısını RenderComponent/Draggable giydirir. layout değerleri de box ile aynı: 'flex' | 'grid' (2026-09-02'de 'cssgrid' seçenek olmaktan çıktı; o değerle kayıtlı düğümler gerçek display:grid akışıyla çizilmeye devam eder).",
|
|
251
251
|
"KATMAN SIRASI (K4): tema componentStyles → $preset TABANDIR (varsayılan verir); tipli grup alanları temayı alan alan EZER (tasarımcının/AI'ın açık seçimi kazanır); düğümün serbest style'ı her şeyin üstünde SON SÖZDÜR.",
|
|
252
|
-
"TEMA PRESET'İ: bir tema preset'ini düğüme bağlamak için style.$preset: '<ad>' yaz (adlar
|
|
252
|
+
"TEMA PRESET'İ: bir tema preset'ini düğüme bağlamak için style.$preset: '<ad>' yaz (adlar theme_get → presets, sayfa bağlamında page_runtime_get → theme.presets; preset'i yazmak/silmek theme_update; componentStyles[type] referanssız, tipin her örneğine uygulanır). Bir alanı 'temaya bırakmak' = o alanı HİÇ yazmamak (null/boş) — studio'daki 'Temaya dön' tam olarak bunu yapar; tema değerini gruba kopyalamak bağı koparır.",
|
|
253
253
|
"STİL YAZMA SIRASI: önce tipli gruplar (alan varsa oraya), grubun karşılamadığı karar style kanalına (custom properties). Tipli alan dururken aynı özelliği style'a yazmak paneli yanıltır — style kazanır ama panel alanı 'etkisiz' görünür.",
|
|
254
254
|
"Yüzey neden prop: düğümün appearance kanalı sarmalayıcıyı (.ng-app__node-item) boyar, kutunun İÇİNİ değil — box'ta .ng-box'ın kendi background/border-radius'una hiçbir panelden ulaşılamıyor. surfaceStyle bu boşluğu kapatır.",
|
|
255
255
|
"Bölge (header/footer) düğümleri box ile ORTAKTIR: hasHeader/hasFooter aynı box-section düğümlerini açar. sectionStyle kuralları bu yüzden '&__header' gibi bir parçaya değil, gerçek '& .ng-box-section--header' seçicisine yazılır.",
|
|
@@ -307,7 +307,7 @@ export const componentKnowledge = {
|
|
|
307
307
|
summary: 'Ortalanmış katman; şemanın KÖKÜNDE page_container’ın kardeşi olarak durur, içeriği (kendi formu ve submit akışı dahil) children’ına eklenir.',
|
|
308
308
|
behavior: [
|
|
309
309
|
"open/close olayları akışa bağlanabilir; açma/kapama isHidden ile değil kendi open state'iyle yürür (setter ile isOpen yaz).",
|
|
310
|
-
"Kaplama çerçevesidir (isFrame): kanvasta blok tutmaz, runtime kutu stili yazmadan ayrı dalda çizer. Katalog boyutu bilerek BOŞ aralıktır (minSize 1, maxSize 0) ve 2026-09-15'ten beri doğrulayıcı
|
|
310
|
+
"Kaplama çerçevesidir (isFrame): kanvasta blok tutmaz, runtime kutu stili yazmadan ayrı dalda çizer. Katalog boyutu bilerek BOŞ aralıktır (minSize 1, maxSize 0) ve 2026-09-15'ten beri doğrulayıcı blocks[].size'ı hiçbir eksende DENETLEMEZ (boyut sınırı kanvasın kuralıdır) — add_component ile kökte (parent null) herhangi bir { w, h } ile eklenir. Daha eski backend build'i her boyutu 'Height of modal must be between 1 and 0' (invalid-size) ile reddeder; o durumda imaj yenilenmemiştir. drawer ve toast aynı kuraldadır."
|
|
311
311
|
],
|
|
312
312
|
propNotes: { surfaceStyle: NODE_SURFACE_NOTE }
|
|
313
313
|
},
|
|
@@ -525,42 +525,104 @@ export const componentKnowledge = {
|
|
|
525
525
|
}
|
|
526
526
|
},
|
|
527
527
|
datepicker: {
|
|
528
|
-
summary: '
|
|
528
|
+
summary: 'Tek GÜN seçici (saat yok): takvimden ya da kutuya yazarak; change yükü tek anahtar { value }.',
|
|
529
|
+
behavior: [
|
|
530
|
+
"Değer YEREL duvar saati 'yyyy-MM-ddTHH:mm:ss' metnidir (dilim eki yok, saat kısmı seçimde 00:00) ya da null. change düğümün prop'una yazar: akış değeri self.value ile okur, event.data BOŞTUR (CQ-149). 2026-09-15 öncesinde bu kayıt yükte HH ve mm anahtarları da olduğunu söylüyordu — runtime hiç göndermiyordu, self.HH okuyan ifade boş dönerdi.",
|
|
531
|
+
"minDate/maxDate GÜN sınırıdır ('yyyy-MM-dd'): ikisi de KENDİ günü dahil seçilebilir kalır. 2026-09-15'te düzeltildi — çıplak gün metni UTC gece yarısı olarak okunuyordu, Greenwich'in doğusunda (TR: +03) minDate'in kendi günü takvimde PASİF görünüyordu, yazarak seçilirse değer 03:00'a kaydırılıyordu; batısında (örn. New York −04) aynı kusur maxDate'te çıkıyordu — maxDate'in KENDİ günü pasifti. Sınır dışı günler takvimde pasiftir; kutuya YAZILAN sınır dışı bir tarih hata vermez, o sınır gününün gece yarısına çekilir. Akıştan yazılan değer bu kapıdan GEÇMEZ, olduğu gibi gösterilir.",
|
|
532
|
+
'Takvim tek gün seçtirir; komşu ayların günleri de seçilebilir, yıl açılır listesi 1900-2100 arasında gezer, popup her ay altı hafta çizer. Seçim anında popup kapanır ve change yayılır — onay adımı yoktur.',
|
|
533
|
+
"Kutuya elle yazmak için çift tıklanır (tek tık takvimi açar). Okunan desenler tr'de 'd MMM yyyy' · 'd MMMM yyyy' · 'd.MM.yyyy' · 'dd.MM.yyyy' · 'dd.MM.yy', diğer dillerde 'MMM d, yyyy' · 'MMMM d, yyyy' · 'MM/dd/yyyy' · 'M/d/yyyy' · 'MM/dd/yy'; 1900 öncesi ve 2100 sonrası yıl reddedilir. Okunamayan yazı tutulan değere döner, değer yoksa kutu BOŞALIR (2026-09-15; öncesinde reddedilen metin değermiş gibi ekranda kalıyordu). Kutu salt okunur olsa da programdan gelen change'i DİNLER: page_screenshot 'set' ile ISO tarih ('2026-08-01', '2026-08-01T09:30') ya da gösterim biçimi yazılabilir ve değer takvimden seçilmiş gibi yayılır; okunamayan metinde actionsReport propWritten:false döner. 2026-09-15 öncesi olay dinlenmiyordu: kutu dolu görünüyor, prop boş kalıyordu (G-14).",
|
|
534
|
+
'Doğrulama kuralları: required · min · max (2026-09-15; pattern bildirimi kaldırıldı — panel tarih alanına regex kuralı hiç çizmiyordu, yazılan satırı düğüm seçilince siliyordu, CQ-226). min/max değeri gün metnidir ve alanın minDate/maxDate prop\'larından AYRIDIR: minDate/maxDate takvimi kısar, min/max gönderimde hata gösterir. DİKKAT (CQ-252): Form kuralın gün metnini UTC, alanın değerini YEREL okuyor (form/helper.ts dateMs), yani UTC olmayan her dilimde SINIR GÜNÜNÜN KENDİSİ yanlış tarafta kalıyor — Türkiye saatinde tam min gününe eşit bir değer yine de en-az hatası veriyor. Bugünkü güvenli yol: sınırı bir gün geniş tutmak ya da kural yerine minDate/maxDate kullanmak.',
|
|
535
|
+
'focus/blur ALAN düzeyindedir (2026-09-15): girdi ile takvim arasında dolaşmak olay yaymaz; yalnız alana girmek ve alandan çıkmak yayar. Kilitli alan (isDisabled/isReadonly/isViewmode) hiçbir olay yaymaz.',
|
|
536
|
+
'isLoading KİLİT DEĞİLDİR (2026-09-15): alan kullanılabilir kalır, sağ uçta dönen spinner çizilir (o sırada X gizlenir) ve kök aria-busy taşır. Kilit için isDisabled kullan.',
|
|
537
|
+
"Değer doluyken sağ uçta X çıkar ve change'i null ile yayar; kilitli kipte X yoktur. Gösterim dili locale'den (boşsa uygulama dili): tr'de 'd MMM yyyy', diğer dillerde 'MMM d, yyyy'. Biçim ve haftanın ilk günü prop'u YOK (ARC-071).",
|
|
538
|
+
'Saat gerekiyorsa datetimepicker, aralık gerekiyorsa daterangepicker kullanılır; bu bileşen saat taşımaz.'
|
|
539
|
+
],
|
|
540
|
+
propNotes: {
|
|
541
|
+
value: "Seçili gün: 'yyyy-MM-ddTHH:mm:ss' ya da 'yyyy-MM-dd' metni, ya da null. Çıplak gün YEREL okunur (UTC kaydırması yok). Okunamayan metin alanı BOŞ gösterir, hata vermez. " + DATE_VALUE_FORMAT_NOTE,
|
|
542
|
+
minDate: "En erken gün ('yyyy-MM-dd'); o günün kendisi seçilebilir, öncesi takvimde pasif kalır.",
|
|
543
|
+
maxDate: 'En geç gün; o günün kendisi seçilebilir, sonrası pasif kalır.',
|
|
544
|
+
placeholder: "Boş alanda görünen metin; varsayılanı '01.01.2000' ama kutu değeri her zaman dilin desenine göre yazar (tr '10 Eyl 2026', diğer diller 'Sep 10, 2026') — yer tutucu bir biçim SÖZÜ DEĞİLDİR.",
|
|
545
|
+
displayOffset: 'GÖSTERİMİ kaydıran saat sayısı (+3: saklanan değeri üç saat ileri göster); saklanan değer değişmez. Gün sınırına yakın bir değeri komşu güne kaydırabilir.',
|
|
546
|
+
valueOffset: 'YAZILAN değeri kaydıran saat sayısı; gösterim değişmez. Bir dilim farkını sabit tutmak için displayOffset ile ters işaretli kullanılır (+3 / -3).',
|
|
547
|
+
locale: LOCALE_FOLLOWS_APP_NOTE,
|
|
548
|
+
isLoading: 'Akıştan açılır; alan kilitlenmez, yalnız spinner çizilir ve kök aria-busy taşır.'
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
datetimepicker: {
|
|
552
|
+
summary: 'Tek alanda tarih + saat seçici: takvim + dakika adımlı saat listesi; değer tek value, change yükü { value }.',
|
|
529
553
|
behavior: [
|
|
530
|
-
"
|
|
554
|
+
"Değer YEREL duvar saati 'yyyy-MM-ddTHH:mm:ss' metnidir (dilim eki yok) ya da null. change düğümün prop'una yazar: akış değeri self.value ile okur, event.data BOŞTUR (CQ-149). 2026-09-16 öncesinde olay kaydında yük anahtarı yoktu; runtime her zaman { value } gönderiyordu.",
|
|
555
|
+
"Değer ancak TARİH + SAAT ikisi de seçilince yazılır: boş alanda takvimden yalnız gün seçmek change YAYMAZ — gün ekranda taslak kalır (kutu günü ve 00:00'ı gösterir ama self.value null'dır, required düşer — CQ-237), saat listesi kendiliğinden açılır ve saat seçilince yayılır. Günü yeniden seçmek de taslağı YAZMAZ (2026-09-16'da düzeltildi: ikinci gün seçimi …T00:00:00 yayıyordu). Alan zaten bir değer tutuyorsa (kullanıcı seçmiş ya da akış yazmış) tarihi değiştirmek TUTULAN saati koruyup hemen yayar. Gün seçmeden saat seçmek bugünün gününü kullanır ve hemen yayar. Akıştan gelen değer taslağı düşürür.",
|
|
556
|
+
"Saat listesi minutesStep adımıyla gösterilen günün (yoksa bugünün) üstünde üretilir; minDate öncesi ve maxDate sonrası saatler listede KALIR ama pasiftir. Liste minutesStep ve dil değişince yeniden üretilir (2026-09-16 öncesinde yalnız değer ya da sınır değişince yenileniyordu).",
|
|
557
|
+
"minDate/maxDate tarih-saat ANIDIR ('yyyy-MM-ddTHH:mm'): takvimde sınırın KENDİ günü seçilebilir kalır, o günün sınır dışı saatleri listede pasiftir. 2026-09-16'da düzeltildi — takvim sınırı an olarak karşılaştırıyordu, saati olan bir minDate (örn. …T14:00) kendi gününü takvimde PASİF gösteriyordu, o gün hiç seçilemiyordu. Yayma öncesi sarmalayıcı seçimi [minDate, maxDate] içine çeker (sınır dışı seçim hata VERMEZ, sınıra yapışır); akıştan yazılan değer bu kapıdan GEÇMEZ, olduğu gibi gösterilir.",
|
|
558
|
+
"Kutulara elle yazmak için çift tıklanır (tek tık takvimi / saat listesini açar). Tarih kutusu datepicker desenlerini okur (tr 'd MMM yyyy' · 'd.MM.yyyy' …, diğer dillerde 'MMM d, yyyy' · 'MM/dd/yyyy' …, her dilde ISO 'yyyy-MM-dd') ve takvimden gün seçmekle AYNI kurala girer. Saat kutusu '14:30', '14', en'de '02:30 PM' okur; okunamayan saat kutuyu tutulan saate geri çevirir, değeri bozmaz. 2026-09-16 öncesinde saat kutusu çift tıklamadan da yazılabiliyordu ve yazılan metin yok sayılıp ekranda kalıyordu.",
|
|
559
|
+
"page_screenshot 'set' kökte TARİH kutusuna yazar ve takvimden gün seçmekle aynı kuraldır: alan değer tutuyorsa tutulan saat korunup yazılır; boşsa yalnız taslak olur ve actionsReport propWritten:false döner. ISO metnindeki saat kısmı ('2026-08-01T09:30') KULLANILMAZ ve saat kutusunun iç kimliği yoktur, 'set' ile hedeflenemez (TOOL-020). Tam değeri doğrulamak için önce akıştan self.value yazın.",
|
|
560
|
+
"Doğrulama kuralları: required · min · max (2026-09-16; pattern bildirimi kaldırıldı — panel tarih-saat alanına regex kuralı hiç çizmiyordu, yazılan satırı düğüm seçilince siliyordu, CQ-226). min/max değeri 'yyyy-MM-ddTHH:mm' metnidir ve alanın minDate/maxDate prop'larından AYRIDIR: minDate/maxDate takvimi ve listeyi kısar, min/max gönderimde hata gösterir. Kurala çıplak gün ('2026-09-10') yazma — Form onu UTC okur ve UTC olmayan dilimde sınır birkaç saat kayar (CQ-252); saatiyle yaz.",
|
|
561
|
+
'focus/blur ALAN düzeyindedir (2026-09-16): tarih kutusu, saat kutusu, takvim ve saat listesi arasında dolaşmak olay yaymaz; yalnız alana girmek ve alandan çıkmak yayar. Kilitli alan (isDisabled/isReadonly/isViewmode) hiçbir olay yaymaz.',
|
|
562
|
+
'isLoading KİLİT DEĞİLDİR (2026-09-16): alan kullanılabilir kalır, sağ uçta dönen spinner çizilir (o sırada X gizlenir) ve kök aria-busy taşır. Kilit için isDisabled kullan.',
|
|
563
|
+
"Değer (ya da taslak gün) doluyken sağ uçta X çıkar; değeri boşaltıp change'i null ile yayar, yalnız taslak gün varsa taslağı düşürür ve change YAYMAZ (değer zaten boştu); kilitli kipte X yoktur. Gösterim dili locale'den (boşsa uygulama dili): tarih tr'de 'd MMM yyyy', diğer dillerde 'MMM d, yyyy'; saat en'de 12 saat (01:00 PM), diğer dillerde 24 saat. Değer her dilde aynı 24 saatlik metindir. Biçim ve haftanın ilk günü prop'u YOK (ARC-071, CQ-098). Yalnız gün için datepicker, aralık için datetimerangepicker kullanılır."
|
|
531
564
|
],
|
|
532
|
-
propNotes: {
|
|
565
|
+
propNotes: {
|
|
566
|
+
value: "Seçili an: 'yyyy-MM-ddTHH:mm:ss' ya da null. Çıplak 'yyyy-MM-dd' YEREL gece yarısı okunur (UTC kaydırması yok). Okunamayan metin alanı BOŞ gösterir, hata vermez. " + DATE_VALUE_FORMAT_NOTE,
|
|
567
|
+
minutesStep: "Saat listesinin adımı, METİN enum: '1' | '2' | '3' | '4' | '5' | '6' | '10' | '12' | '15' | '30' | '60' (varsayılan '15'). 0, negatif ya da okunamayan değer 15'e düşer; 1 dakika 1440 satır demektir.",
|
|
568
|
+
minDate: "En erken an ('yyyy-MM-ddTHH:mm'); o günün kendisi takvimde seçilebilir, günün sınırdan önceki saatleri listede pasif kalır. Sınır dışına düşen seçim sınıra çekilir.",
|
|
569
|
+
maxDate: "En geç an; o gün seçilebilir, sınırdan sonraki saatler pasif, sınır dışı seçim sınıra çekilir. Saatiyle yaz ('…T23:59'): çıplak gün ('2026-09-20') o günün 00:00'ıdır, günün geri kalanı pasif kalır.",
|
|
570
|
+
placeholder: "Boş tarih kutusunda görünen metin (varsayılan 'Select date'); kutu değeri her zaman dilin desenine göre yazar — yer tutucu bir biçim SÖZÜ DEĞİLDİR.",
|
|
571
|
+
timePlaceholder: "Boş saat kutusunda görünen metin (varsayılan 'Select time'). Taslak gün seçilince kutu 00:00 gösterir, yer tutucu görünmez (CQ-237).",
|
|
572
|
+
displayOffset: 'GÖSTERİMİ kaydıran saat sayısı (+3: saklanan değeri üç saat ileri göster); saklanan değer değişmez.',
|
|
573
|
+
valueOffset: 'YAZILAN değeri kaydıran saat sayısı; gösterim değişmez. displayOffset ile HER ZAMAN ters işaretli ver (+3 / -3): kullanıcı gösterilen saati seçer ve korur, yalnız biri verilirse her tarih değişikliğinde tutulan saat o kadar kayar.',
|
|
574
|
+
locale: LOCALE_FOLLOWS_APP_NOTE,
|
|
575
|
+
isLoading: 'Akıştan açılır; alan kilitlenmez, yalnız spinner çizilir ve kök aria-busy taşır.'
|
|
576
|
+
}
|
|
533
577
|
},
|
|
534
|
-
datetimepicker: { summary: 'Tarih+saat seçici; değer event.data’da değil self.value’dadır.', propNotes: { value: DATE_VALUE_FORMAT_NOTE, locale: LOCALE_FOLLOWS_APP_NOTE } },
|
|
535
578
|
daterangepicker: {
|
|
536
|
-
summary: '
|
|
537
|
-
behavior: [
|
|
538
|
-
"İki
|
|
579
|
+
summary: 'GÜN aralığı (saat yok): değer valueFrom/valueTo İKİLİSİDİR (tek value yok); her yarı bir takvim + yazılabilir kutu; change yükü { valueFrom, valueTo }.',
|
|
580
|
+
behavior: [
|
|
581
|
+
"İki uç da YEREL duvar saati 'yyyy-MM-ddTHH:mm:ss' metnidir (dilim eki yok; seçimde saat 00:00, gece yarısı yaşanmayan yaz saati günlerinde 01:00) ya da null. change her iki anahtarı birden taşır ve düğümün prop'una yazar: akış self.valueFrom / self.valueTo ile okur, event.data BOŞTUR (CQ-149). Form aralığı { valueFrom, valueTo } nesnesi olarak görür; required ancak İKİSİ de doluyken geçer. 2026-09-16 öncesinde bu kayıt yükte HH ve mm anahtarları da olduğunu söylüyordu — runtime hiç göndermiyordu.",
|
|
582
|
+
"minDate/maxDate GÜN sınırıdır ('yyyy-MM-dd'): ikisi de KENDİ günü dahil seçilebilir kalır. Takvimler de gün olarak karşılıklı sınırlanır: bitiş takvimi başlangıç GÜNÜNDEN, başlangıç takvimi bitiş GÜNÜNE kadar açıktır — aynı gün başlayıp biten tek günlük aralık seçilebilir. 2026-09-16'da düzeltildi: çıplak gün metni UTC gece yarısı okunuyordu, Greenwich'in doğusunda (TR: +03) minDate'in kendi günü takvimde PASİF görünüyor ve sınıra çekilen değer 03:00 yazılıyordu, batısında maxDate'in kendi günü pasifti; saatli bir başlangıç (displayOffset, akıştan saatli değer) bitiş takviminde kendi gününü kapatıyordu.",
|
|
583
|
+
"Yayma öncesi sarmalayıcı çifti üç adımda kurar: (1) her uç [minDate, maxDate] günlerinin içine çekilir (sınır dışı yazılan tarih o sınır gününün gece yarısına yapışır, hata VERMEZ); (2) DEĞİŞEN uç seçilen günden valueOffset kaydırılarak yazılır, DOKUNULMAYAN uç tuttuğu değerle yazılır (kırpma onu taşımadıysa) — aynı günü yeniden seçmek de değişikliktir; (3) sıra YAZILAN değerler üzerinde uygulanır: bitiş başlangıçtan önceyse başlangıca eşitlenir, yani kullanıcı değişikliğinden sonra valueFrom <= valueTo her zaman tutar. Bu yüzden başlangıç saat taşıyorsa (akış '…T10:00:00' yazmışsa) aynı günde biten aralığın bitişi de o saati alır. 2026-09-16 öncesinde iki uç da GÖSTERİLEN hâlinden yeniden türetiliyordu: yalnız displayOffset ya da yalnız valueOffset verilmiş alanda dokunulmayan uç her seçimde o kadar saat kayıyordu. Akıştan yazılan değerler bu kapıdan GEÇMEZ, olduğu gibi gösterilir (ta ki kullanıcı bir yarıyı değiştirene dek); çıplak 'yyyy-MM-dd' YEREL gece yarısı okunur, okunamayan metin yarıyı BOŞ gösterir.",
|
|
584
|
+
"Başlangıç seçilince ve bitiş boşsa bitiş takvimi kendiliğinden açılır. Her seçim popup'ı kapatır ve change'i hemen yayar — onay adımı yoktur. Her yarının kendi X'i vardır ve yalnız o yarıyı boşaltır (change o yarı null, diğeri olduğu gibi); kilitli kipte X yoktur.",
|
|
585
|
+
"Kutuya elle yazmak için çift tıklanır (tek tık takvimi açar); okunan desenler datepicker ile aynıdır (tr 'd MMM yyyy' · 'd.MM.yyyy' · 'dd.MM.yyyy' …, diğer dillerde 'MMM d, yyyy' · 'MM/dd/yyyy' …, her dilde ISO 'yyyy-MM-dd'). İki kutu ayrı adreslenir: '<elementId>__start' (valueFrom) ve '<elementId>__end' (valueTo). page_screenshot 'set' kökü REDDEDER (tek değer yok); kutuya ISO tarih ('2026-08-01') ya da gösterim biçimi ('1 Ağu 2026') yazılır, kutu değeri kendi change yoluna sokar ve prop'a yazar. Okunamayan metin kutuyu tutulan değere geri çevirir; actionsReport propWritten:false döner (G-14, 2026-09-15).",
|
|
586
|
+
"Doğrulama kuralları: required · min · max (2026-09-16; pattern bildirimi kaldırıldı — panel tarih alanına regex kuralı hiç çizmiyordu, yazılan satırı düğüm seçilince siliyordu, CQ-226). min/max değeri gün metnidir, Form aralığın İKİ ucunu da sınırla karşılaştırır ve alanın minDate/maxDate prop'larından AYRIDIR: minDate/maxDate takvimi kısar, min/max gönderimde hata gösterir. DİKKAT (CQ-252): Form kuralın gün metnini UTC, alanın değerini YEREL okuyor, yani UTC olmayan her dilimde SINIR GÜNÜNÜN KENDİSİ yanlış tarafta kalıyor. Bugünkü güvenli yol: kural yerine minDate/maxDate kullanmak ya da sınırı bir gün geniş tutmak.",
|
|
587
|
+
"focus/blur ALAN düzeyindedir (2026-09-16): iki kutu ve iki takvim arasında dolaşmak olay yaymaz; yalnız alana girmek ve alandan çıkmak yayar. Kilitli alan (isDisabled/isReadonly/isViewmode) hiçbir olay yaymaz.",
|
|
588
|
+
"isLoading KİLİT DEĞİLDİR (2026-09-16): alan kullanılabilir kalır, iki yarının X'i yerinde durur, satırın sağ ucunda dönen spinner çizilir ve kutu aria-busy taşır (450px altındaki dikey yığılmada spinner çizilmez, aria-busy kalır). Kilit için isDisabled kullan.",
|
|
589
|
+
"Gösterim dili locale'den (boşsa uygulama dili): tr'de 'd MMM yyyy', diğer dillerde 'MMM d, yyyy'. Değer her dilde aynı metindir. Biçim ve haftanın ilk günü prop'u YOK (ARC-071). Saat gerekiyorsa datetimerangepicker, tek gün gerekiyorsa datepicker kullanılır."
|
|
539
590
|
],
|
|
540
|
-
propNotes: {
|
|
591
|
+
propNotes: {
|
|
592
|
+
valueFrom: "Başlangıç günü: 'yyyy-MM-ddTHH:mm:ss' ya da 'yyyy-MM-dd' metni, ya da null. Çıplak gün YEREL okunur (UTC kaydırması yok). " + DATE_VALUE_FORMAT_NOTE,
|
|
593
|
+
valueTo: "Bitiş günü; valueFrom ile aynı biçim. Akıştan başlangıçtan önce bir bitiş yazılırsa olduğu gibi gösterilir — sıra kuralı yalnız kullanıcı seçiminde uygulanır.",
|
|
594
|
+
minDate: "En erken gün ('yyyy-MM-dd'); o günün kendisi iki takvimde de seçilebilir, öncesi pasif kalır.",
|
|
595
|
+
maxDate: 'En geç gün; o günün kendisi seçilebilir, sonrası pasif kalır.',
|
|
596
|
+
startPlaceholder: "Başlangıç kutusu boşken görünen metin; varsayılanı '01.01.2000' ama kutu değeri her zaman dilin desenine göre yazar (tr '10 Eyl 2026', diğer diller 'Sep 10, 2026') — yer tutucu bir biçim SÖZÜ DEĞİLDİR.",
|
|
597
|
+
endPlaceholder: "Bitiş kutusunun yer tutucusu; startPlaceholder ile aynı kural (varsayılan '05.01.2000').",
|
|
598
|
+
displayOffset: 'GÖSTERİMİ kaydıran saat sayısı (+3: saklanan değeri üç saat ileri göster); saklanan değer değişmez. Gün sınırına yakın bir değeri komşu güne kaydırabilir.',
|
|
599
|
+
valueOffset: 'DEĞİŞEN ucu yazarken kaydıran saat sayısı; dokunulmayan uç tuttuğu değerle kalır. Gösterim yazılan değerden okunduğu için tek başına verilirse ekranda da görünür (-3: 15 seçilir, \'…14T21:00:00\' yazılır, kutu 14 gösterir) ve min/max kurallarının karşılaştırdığı değeri de kaydırır. Bir dilim farkını sabit tutmak için displayOffset ile ters işaretli kullanılır (+3 / -3).',
|
|
600
|
+
locale: LOCALE_FOLLOWS_APP_NOTE,
|
|
601
|
+
isLoading: 'Akıştan açılır; alan kilitlenmez, yalnız spinner çizilir ve kutu aria-busy taşır.'
|
|
602
|
+
}
|
|
541
603
|
},
|
|
542
604
|
datetimerangepicker: {
|
|
543
605
|
summary: 'Tarih+saat aralığı: değer valueFrom/valueTo İKİLİSİDİR (tek value yok); her yarı bir takvim + dakika adımlı saat listesi; change yükü { valueFrom, valueTo }.',
|
|
544
606
|
behavior: [
|
|
545
607
|
"İki uç da YEREL duvar saati 'yyyy-MM-ddTHH:mm:ss' metnidir (dilim eki yok) ya da null. change her iki anahtarı birden taşır ve düğümün prop'una yazar: akış self.valueFrom / self.valueTo ile okur. Form aralığı { valueFrom, valueTo } nesnesi olarak görür; required ancak İKİSİ de doluyken geçer.",
|
|
546
608
|
"Bir yarının değeri ancak TARİH + SAAT ikisi de seçilince yazılır: takvimden yalnız gün seçmek change YAYMAZ — gün ekranda taslak olarak kalır (kutu günü ve 00:00'ı gösterir, CQ-237), günü yeniden seçmek de, diğer yarıyı tamamlamak da o taslağı YAZMAZ; saat listesi kendiliğinden açılır ve saat seçilince yayılır (tek datetimepicker ile aynı kural). Yarı zaten bir değer tutuyorsa (kullanıcı seçmiş ya da akış yazmış) tarihi değiştirmek TUTULAN saati koruyup hemen yayar — 2026-09-12'de düzeltildi, öncesinde listeden saat seçildikten sonra tarih değişikliği ekranda görünüp değere hiç yazılmıyordu. Akıştan gelen değer taslağı düşürür.",
|
|
547
|
-
"Saat listeleri minutesStep adımıyla o yarının GÜNÜ üstünde üretilir; minDate/maxDate DIŞI ve karşı ucun ÖTESİNDEKİ saatler (başlangıç için bitişten sonrası, bitiş için başlangıçtan öncesi) listede KALIR ama pasiftir. Takvimler
|
|
548
|
-
"Yayma öncesi sarmalayıcı sınırlar: her uç [minDate, maxDate]
|
|
609
|
+
"Saat listeleri minutesStep adımıyla o yarının GÜNÜ üstünde üretilir; minDate/maxDate DIŞI ve karşı ucun ÖTESİNDEKİ saatler (başlangıç için bitişten sonrası, bitiş için başlangıçtan öncesi) listede KALIR ama pasiftir. Takvimler GÜN olarak sınırlanır: bitiş takvimi başlangıç GÜNÜNDEN önceye, başlangıç takvimi bitiş GÜNÜNDEN sonraya, ikisi de minDate/maxDate GÜNLERİNİN dışına izin vermez — sınırın KENDİ günü her zaman seçilebilir, saat düzeyindeki sınır yalnız listede ve kırpmada uygulanır (2026-09-16; öncesinde saat taşıyan sınırın kendi günü takvimde pasifti: başlangıç 10:30 iken aynı gün biten aralık, minDate 09:00 iken o gün seçilemiyordu).",
|
|
610
|
+
"Yayma öncesi sarmalayıcı sınırlar: her uç [minDate, maxDate] ANINA çekilir; bir yarı değişince DOKUNULMAYAN uç kırpma onu taşımadıkça tuttuğu değerle yazılır; sıra YAZILAN çift üzerinde uygulanır, bitiş başlangıçtan önce kalırsa başlangıca eşitlenir. Sınır dışı bir seçim hata VERMEZ, sınıra yapışır. Akıştan yazılan değerler yazıldıkları anda bu kapıdan GEÇMEZ, olduğu gibi gösterilir; ama HANGİ yarıda olursa olsun bir sonraki kullanıcı seçimi onları da kırpar/sıraya sokar (sınır dışı uç sınıra, başlangıçtan önceki bitiş başlangıca) ve dokunulmayan ucu yayılan biçimde ('yyyy-MM-ddTHH:mm:ss', çıplak gün '…T00:00:00') yeniden yazar. Etkinleşen sınır günlerinin yan etkisi: tutulan saat o günde sınırın dışına düşerse (başlangıç 10:30, bitiş ertesi gün 09:00 → bitişte başlangıç günü seçilir) uç sessizce sınıra çekilir; sınırı günün son adımından geç olan gün (minDate 23:50, adım 15) seçilebilir ama listede seçilebilir saat yoktur, saat elle yazılır. 2026-09-16'ya kadar iki uç da gösterilen hâlinden yeniden türetiliyordu: yalnız displayOffset ya da yalnız valueOffset verilmiş alanda dokunulmayan uç her seçimde o kadar saat kayıyordu.",
|
|
549
611
|
"Doğrulama kuralları: required · min · max (2026-09-12; pattern bildirimi kaldırıldı — panel tarih-saat alanına regex kuralı hiç çizmiyordu, yazılan satırı düğüm seçilince siliyordu). min/max değeri 'yyyy-MM-ddTHH:mm' tarih-saat metnidir ve Form aralığın İKİ ucunu da sınırla karşılaştırır.",
|
|
550
612
|
"focus/blur ALAN düzeyindedir (2026-09-12): iki tarih girdisi, iki saat girdisi, takvim ve saat listesi arasında dolaşmak olay yaymaz; yalnız alana girmek ve alandan çıkmak yayar. Kilitli alan (isDisabled/isReadonly/isViewmode) hiçbir olay yaymaz.",
|
|
551
613
|
"isLoading KİLİT DEĞİLDİR (2026-09-12): alan odaklanabilir kalır, sağ uçta dönen spinner çizilir, kök aria-busy taşır (478px altındaki dikey yığılmada spinner çizilmez, aria-busy kalır). Kilit için isDisabled kullan.",
|
|
552
|
-
"Her yarının kendi X'i vardır ve yalnız o yarıyı boşaltır (change o yarı null, diğeri
|
|
614
|
+
"Her yarının kendi X'i vardır ve yalnız o yarıyı boşaltır (change o yarı null, diğeri tuttuğu değerle yazılır). Yalnız taslak gün tutan yarının X'i taslağı siler ama change YAYMAZ — değer zaten boştu (2026-09-16; öncesinde değişmeyen değerle change yayıyordu). İkisini birden boşaltmanın yolu iki X ya da akıştan iki prop'u null yazmaktır.",
|
|
553
615
|
"Gösterim dili locale'den (boşsa uygulama dili): tarih tr'de 'd MMM yyyy', diğer dillerde 'MMM d, yyyy'; saat en'de 12 saat (01:00 PM), diğer dillerde 24 saat. Değer her dilde aynı 24 saatlik metindir. Biçim prop'u YOK (ARC-071).",
|
|
554
616
|
"Tarih kutuları '<elementId>__start' / '<elementId>__end' ile adreslenir (G-14, 2026-09-15). page_screenshot 'set' kökü reddeder; kutuya ISO tarih yazmak takvimden gün seçmekle AYNI kuraldır: yarı değer tutmuyorsa yalnız taslak olur ve propWritten:false döner — saat kutusu ayrıca hedeflenemez, önce akıştan değer yazın ya da saati tıklamayla seçin."
|
|
555
617
|
],
|
|
556
618
|
propNotes: {
|
|
557
|
-
valueFrom: "Başlangıç: 'yyyy-MM-ddTHH:mm:ss' ya da null. Akıştan yazarken bu biçimi (ya da Date'in okuduğu bir ISO metnini) kullan; okunamayan metin yarıyı BOŞ gösterir, hata vermez.",
|
|
558
|
-
valueTo: "Bitiş; valueFrom ile aynı biçim. Akıştan başlangıçtan önce bir bitiş yazılırsa olduğu gibi gösterilir — sıra kuralı
|
|
619
|
+
valueFrom: "Başlangıç: 'yyyy-MM-ddTHH:mm:ss' ya da null. Akıştan yazarken bu biçimi (ya da Date'in okuduğu bir ISO metnini) kullan; çıplak 'yyyy-MM-dd' o günün YEREL gece yarısıdır (2026-09-16'ya kadar UTC okunuyordu, TR'de 03:00 görünüyordu); okunamayan metin yarıyı BOŞ gösterir, hata vermez.",
|
|
620
|
+
valueTo: "Bitiş; valueFrom ile aynı biçim. Akıştan başlangıçtan önce bir bitiş yazılırsa olduğu gibi gösterilir — sıra kuralı kullanıcı seçiminde uygulanır: hangi yarıda olursa olsun bir sonraki seçim bitişi başlangıca çeker.",
|
|
559
621
|
minutesStep: "Saat listelerinin adımı, METİN enum: '1' | '2' | '3' | '4' | '5' | '6' | '10' | '12' | '15' | '30' | '60' (varsayılan '15'). 0, negatif ya da okunamayan değer 15'e düşer; 1 dakika 1440 satır demektir.",
|
|
560
|
-
minDate: "En erken tarih-saat ('yyyy-MM-ddTHH:mm:ss');
|
|
561
|
-
maxDate: 'En geç tarih-saat; sonrası pasif
|
|
562
|
-
displayOffset: 'GÖSTERİMİ kaydıran saat sayısı (+3: saklanan değeri üç saat ileri göster); saklanan
|
|
563
|
-
valueOffset:
|
|
622
|
+
minDate: "En erken tarih-saat ('yyyy-MM-ddTHH:mm:ss'); takvimde o GÜNÜN öncesi, saat listesinde o ANIN öncesi pasif kalır (kendi günü seçilebilir); sınır dışına düşen seçim sınır anına çekilir.",
|
|
623
|
+
maxDate: 'En geç tarih-saat; takvimde o GÜNÜN sonrası, saat listesinde o ANIN sonrası pasif (kendi günü seçilebilir); sınır dışı seçim sınır anına çekilir.',
|
|
624
|
+
displayOffset: 'GÖSTERİMİ kaydıran saat sayısı (+3: saklanan değeri üç saat ileri göster); yalnız gösterilir, yazmada geri alınmaz — seçilen/korunan saat GÖSTERİLEN saattir. valueOffset ile ters işaretli verilmezse bir yarının tarihini değiştirmek o yarının saklanan saatini her seferinde +3 kaydırır (…06T18:00 → …07T21:00 → …08T00:00).',
|
|
625
|
+
valueOffset: "DEĞİŞEN ucu yazarken kaydıran saat sayısı; dokunulmayan uç tuttuğu değerle kalır (2026-09-16'ya kadar o uç da her seçimde kayıyordu). Gösterim yazılan değerden okunduğu için tek başına verilirse ekranda da görünür (-3: 15:00 seçilir, '…T12:00:00' yazılır, kutu 12:00 gösterir) ve değişen yarının tarihini her değiştirmede saati o kadar kaydırır. displayOffset ile HER ZAMAN ters işaretli ver (+3 / -3): kullanıcı gösterilen saati seçer ve korur, saklanan değer sabit kalır.",
|
|
564
626
|
locale: LOCALE_FOLLOWS_APP_NOTE,
|
|
565
627
|
isLoading: 'Akıştan açılır; alan kilitlenmez, yalnız spinner çizilir ve kök aria-busy taşır.'
|
|
566
628
|
}
|
|
@@ -570,10 +632,20 @@ export const componentKnowledge = {
|
|
|
570
632
|
filebutton: { summary: 'Buton görünümlü dosya seçici; fileInput ile aynı yük.' },
|
|
571
633
|
'file-viewer': { summary: 'Dosya önizleyici (pdf/görsel); file prop’una drive dosyası bağlanır.', propNotes: { surfaceStyle: NODE_SURFACE_NOTE } },
|
|
572
634
|
button: {
|
|
573
|
-
summary:
|
|
635
|
+
summary: "Tıklama kaynağı; type üç işten birini seçer — 'button' click akışını çalıştırır, 'submit' bir Form'u gönderir, 'link' bir adrese gider. click olayı veri taşımaz, bağlam gerekiyorsa ifadede komponent adlarıyla okunur.",
|
|
636
|
+
behavior: [
|
|
637
|
+
"click YALNIZ type:'button' iken yayılır. type:'submit' click YAYMAZ, formu gönderir: akışı butona değil formun submit olayına bağla (form doğrulaması geçerse yayılır). type:'link' de click yaymaz, tarayıcı href'e gider.",
|
|
638
|
+
"type:'submit' buton bir Form'un İÇİNDEYSE formId gerekmez, tarayıcı en yakın forma bağlar; formun DIŞINDAYSA formId = formun elementId'si ya da adı. isDisabled/isLoading açıkken gönderim de kilitlidir.",
|
|
639
|
+
"href ve isNewTabLink YALNIZ type:'link' iken okunur — href doldurmak butonu link yapmaz. İç sayfaya link için href'e URL değil { type:'page', ref:<pageId> } Prop'u yaz. Link kilitliyken (isDisabled/isLoading) ya da href boşken hiçbir yere gitmez ve odak almaz; kilit kalkınca ya da href akışla değişince adres anında güncellenir (2026-09-11 öncesi ilk çizimdeki adreste donuyordu: kilitli açılan link hep ölü kalıyordu).",
|
|
640
|
+
"Kayıtlı sayfalardaki eski kind:'custom' + customColor ikilisi VERİ GÖÇÜ OLMADAN aynen çizilir (render-anı takma adı, text emsali): surfaceStyle.background boşsa eski renk `--ng-btn-custom-color` değişkeniyle solid/outline/text varyantına eskisi gibi iner; Background doldurulunca takma ad susar. page_runtime_get(resolveStyles:true) bu değişkeni resolvedStyle'da gösterir. DİKKAT: platformun doğrulama duvarı sayfanın TAMAMINI okur — böyle bir düğüm taşıyan sayfaya yapılan her page_schema_patch, dokunulmayan düğüm yüzünden invalid-enum-value/unknown-prop ile reddedilir (ARC-036). Sayfayı yeniden yazmadan önce o butonu kind: semantik değer + surfaceStyle.background'a çevir (aynı çağrıda replace_prop ile).",
|
|
641
|
+
"İpucu (tooltip) prop'u YOKTUR: düğümün ortak appearance.tooltip alanı (+ tooltipPosition: top · bottom · left · right) her komponentte ipucu çizer. Tıklamadan önce onay istemek de butonun değil akışın işidir: click akışının başına confirm adımı koy (yalnız web — mobil barındırıcıda confirm adımı yok)."
|
|
642
|
+
],
|
|
574
643
|
propNotes: {
|
|
575
|
-
kind: "primary | info | success | warning | error
|
|
576
|
-
|
|
644
|
+
kind: "primary | info | success | warning | error — beş semantik renk, temayı izler; temizlenirse (null) primary çizilir. ÖZEL ZEMİN için kind değil surfaceStyle.background yazılır (Dalga 4, 2026-09-14): eski custom seçeneği ve customColor şemadan kalktı, yazılırsa invalid-enum-value / unknown-prop. `datatable.actions[].kind` FARKLI bir sözlük kullanır (error · information · solid · transparent · dark · danger · warning) — buradan bir değer (örn. 'transparent') butona yazılırsa invalid-enum-value verir.",
|
|
645
|
+
icon: "{ name: 'save', color? } nesnesi; düz 'save' metni de okunur (AI sözlüğü icon'u string gösteriyor — CQ-164). Adı boş ya da temizlenmiş ikon hiç çizilmez. Yükleniyorken ikonun yerinde spinner döner (link tipinde spinner yok).",
|
|
646
|
+
iconPosition: "'left' (varsayılan) | 'right' — ikonun (ve yükleniyorken spinner'ın) metnin hangi yanında durduğu; ikon yokken etkisiz.",
|
|
647
|
+
align: "'none' (varsayılan) butonu hücrenin TÜM genişliğine yayar; 'left' · 'center' · 'right' butonu içerik kadar daraltıp yaslar. Temizlenirse (null) 'none' sayılır.",
|
|
648
|
+
surfaceStyle: STYLE_GROUP_NOTES.surfaceStyle + ' ' + STYLE_GROUP_NOTES.colorTokens + " Buton yüzeyi (contentOverflow YOK — kaydırılan içerik yok). Her alan kind/variant CSS'inin ÜSTÜNE biner (tasarımcı kazanır): background Outline/Text varyantında da zemini doldurur ve o varyantların kind renkli hover dolgusu görünmez olur; shadow hover/active'de sabit kalır; opacity devre dışı görünümünü (0.5) de ezer. Metin rengi kind'dan gelir, burada alan yok — açık bir zeminde okunur kalması için style: { color: '…' }.",
|
|
577
649
|
badgeValue: "Butonun köşe rozetinin metni ('3', '99+'); boşsa rozet çizilmez. Rengi badgeColor'dan gelir (primary|info|success|warning|error, varsayılan 'error')."
|
|
578
650
|
}
|
|
579
651
|
},
|
|
@@ -584,11 +656,11 @@ export const componentKnowledge = {
|
|
|
584
656
|
summary: 'Görsel + başlık + açıklama + buton metni taşıyan hazır KART; click yayar.',
|
|
585
657
|
behavior: [
|
|
586
658
|
"KAPSAYICI DEĞİLDİR: çocuk kabul etmez (not-droppable). Kutu içinde serbest içerik göstermek için container kullanın (istenirse states.isWrapper:true).",
|
|
587
|
-
'Yükseklik 10-50 aralığındadır (min 10, max 20 varsayılan, max 50)
|
|
659
|
+
'Yükseklik 10-50 aralığındadır (min 10, max 20 varsayılan, max 50). Bu sınır grid kanvasının kuralıdır, API aralık dışı blocks[].size.h değerini reddetmez; yine de aralıkta tutun.'
|
|
588
660
|
]
|
|
589
661
|
},
|
|
590
662
|
'qm-card': { summary: 'QM gösterge kartı; click yayar.' },
|
|
591
|
-
tabs: { summary:
|
|
663
|
+
tabs: { summary: "Sekmeler; tab olayı seçilen sekme anahtarını taşır, her view children sırasıyla eşleşir. Etkin OLMAYAN sekmenin içeriği DOM'da YOKTUR (keepAlways dışında): o sekmedeki bir düğümü hedefleyen doğrulama önce page_screenshot actions { action: 'tab', value: '<sekme anahtarı>' } ister — sekme grubunun köküne click ilk sekmeye gider ve reddedilir.", propNotes: { surfaceStyle: NODE_SURFACE_NOTE } },
|
|
592
664
|
'collapsible-container': { summary: 'Aç/kapa kapsayıcı; collapsed/expanded olayları yayar.', propNotes: { surfaceStyle: NODE_SURFACE_NOTE } },
|
|
593
665
|
'tree-view': {
|
|
594
666
|
summary: 'Hiyerarşik liste: data ağacını çizer, satır tıklamasını click olayıyla akışa verir, satır başına aksiyon menüsü ve isteğe bağlı istemci-tarafı arama taşır.',
|
|
@@ -615,7 +687,7 @@ export const componentKnowledge = {
|
|
|
615
687
|
text: {
|
|
616
688
|
summary: 'Tek satırlık metin gösterimi; değer type:code prop’uyla ifadeye bağlanabilir. Görünümü TİPLİ stil gruplarındadır (typographyStyle · surfaceStyle), ham CSS değil.',
|
|
617
689
|
behavior: [
|
|
618
|
-
"Yükseklik SABİTTİR: maxSize.h = 1 (katalog varsayılanı 8'dir ve olduğu gibi kopyalanırsa
|
|
690
|
+
"Yükseklik SABİTTİR: maxSize.h = 1 (katalog varsayılanı 8'dir ve olduğu gibi kopyalanırsa kanvasta boyutlandırılamaz; gateway 1'e çeker ve gatewayNormalized ile bildirir). Çok satırlı metin için textarea ya da html kullanın.",
|
|
619
691
|
"type HTML etiketi + ölçek seviyesidir (h1|h2|h3|label|p|small; a11y için doğru seviyeyi seç). Punto/kalınlık/renk/hiza kararı typographyStyle'dadır: fontSize seviyenin puntosunu ezer, boş bırakılırsa seviye ölçeği (tema --ng-font-size-*) geçerlidir.",
|
|
620
692
|
"EMEKLİ prop'lar: isBold, align, color, customColor şemada YOK — yazılırsa unknown-prop ile reddedilir. Karşılıkları: typographyStyle.fontWeight ('600'), textAlign, textColor (semantik renk için tema token'ı: var(--ng-status-success) gibi). Kayıtlı eski sayfalarda bu prop'lar render anında takma adla çözülür (resolvedStyle bunu gösterir), yeni yazımda kullanılmaz.",
|
|
621
693
|
"Hover grubu yok (metnin hover semantiği yok); surfaceStyle etiket/vurgulu paragraf içindir (zemin, köşe, çerçeve, gölge) ve contentOverflow alanı yoktur (taşma hedefi yok).",
|
|
@@ -644,7 +716,25 @@ export const componentKnowledge = {
|
|
|
644
716
|
isHidden: 'Şemada tanımlıdır; statik true ile gizli başlatılır, akıştaki setter ile açılıp kapanır. Komponent kendi kapanışında da bu prop\'a yazar.'
|
|
645
717
|
}
|
|
646
718
|
},
|
|
647
|
-
'form-validation-errors': {
|
|
719
|
+
'form-validation-errors': {
|
|
720
|
+
summary: 'Formun doğrulama hatalarını tek kutuda listeler; form.errorElementId buraya işaret eder. Liste boşken hiçbir şey çizmez.',
|
|
721
|
+
behavior: [
|
|
722
|
+
"BAĞLAMA: form'un errorElementId prop'una bu düğümün elementId'sini HER ZAMAN yaz. Yazılmazsa Form yalnız KENDİ İÇİNDEKİ ve elementId'si 'formvalidation-errors' ile başlayan düğümü bulur — o önek yalnız studio kenar çubuğundan sürüklenen düğümde oluşur; MCP ile kurulan, kopyalanan ya da formun dışına konan liste bulunmaz ve hiç dolmaz (docs/issues.md CQ-259).",
|
|
723
|
+
'Listeyi Form doldurur: ilk submit’ten sonra hatalı alanları yazar, sonra her alan değişikliğinde listeyi yeniden yazar (düzelen alan düşer); başarısız submit’te kutuya kaydırır. resetForm listeyi de siler. Liste boşken bileşen DOM’a hiçbir şey basmaz.',
|
|
724
|
+
"errors öğesi { id, label, message }: id hatalı alanın elementId'si, label alan adı, message metin. Aynı id'li hatalar alan adının altında tek grupta toplanır. id'si olan satır düğmedir — tıklanınca alan kapalı bir sekmedeyse o sekme açılır, alana odaklanılır, kaydırılır ve 2 sn vurgulanır; id'siz satır düz metindir ve gruplanmaz. Dizi yerine düz metin öğesi ('Kayıt reddedildi') { message } sayılır; message'ı boş öğe ve dizi olmayan değer (null) çizilmez.",
|
|
725
|
+
'Sunucu hatalarını (ör. 422 yanıtı) göstermek için akıştan setter ile errors yaz — Form’un yazdığıyla aynı biçim. Form bir sonraki submit/alan değişikliğinde listeyi kendi sonucuyla EZER.',
|
|
726
|
+
"message DÜZ METİN olarak basılır (2026-09-16'ya kadar HTML yorumlanıyordu; akıştan gelen metinde betik çalışabilirdi) — alanın kendi hata metniyle aynı. label'daki HTML etiketleri sökülür.",
|
|
727
|
+
"Paneldeki errors listesi yalnız KANVAS ÖNİZLEMESİDİR: sayfa açılınca düğümde statik değer silinir (2026-09-16'ya kadar yalnız bileşenin yerel kopyası siliniyordu ve düğümün başka bir prop'u — title, isHidden — akıştan değişince 'Username / Zip / Expiration date' örnekleri canlı sayfada beliriyordu). {{ }} ile bağlı errors silinmez. Silme düğüm başına bir kez yapılır: sekme değişimi ya da isHidden ile yeniden takılan liste Form'un yazdığı hataları korur.",
|
|
728
|
+
"Kutu role='alert' taşır: belirdiğinde ekran okuyucu içeriği duyurur; ikonlar okunmaz. Satır düğmelerinin klavye odak halkası vardır.",
|
|
729
|
+
'Olay: yalnız mount (render katmanı atar); tıklama olayı yoktur, satır tıkı alana gider.'
|
|
730
|
+
],
|
|
731
|
+
propNotes: {
|
|
732
|
+
title: "Kutunun başlığı (kırmızı, listenin üstünde); boşsa başlık satırı çizilmez. Varsayılan 'Please review the form and correct the following errors.' — 2026-09-16'ya kadar 'formula' yazım hatasıyla bırakılıyordu, eski düğümler kendi değerini taşır.",
|
|
733
|
+
errors: "Çalışma anında Form'a (ya da setter yazan akışa) aittir: [{ id, label, message }]. Statik değer yalnız kanvas önizlemesidir ve sayfa açılınca silinir — kalıcı bir mesaj için notification kullan.",
|
|
734
|
+
hideFormValidationMessage: "true → Form alanların altındaki hata metnini yazmaz, yalnız kırmızı çerçeve kalır; mesajlar yalnız bu listede görünür. Form bunu BU düğümden okur, yani errorElementId bağlı değilse etkisizdir. Kanvasta görünür etkisi yoktur.",
|
|
735
|
+
style: STYLE_GROUP_NOTES.styleEscape + " Parçalar: KÖK (anahtarlar doğrudan style'da) kırmızı kutudur — zemin (--ng-red-50), çerçeve (--ng-red-200), köşe; '&__title' başlık metni. Satır sınıfları belgelenmemiştir."
|
|
736
|
+
}
|
|
737
|
+
},
|
|
648
738
|
breadcrumb: { summary: 'Sayfa yolu; currentTitle setter ile kip etiketine (Yeni/Düzenle) çevrilir.' },
|
|
649
739
|
'page-header': {
|
|
650
740
|
summary: 'Sayfa başlığı bandı; yalnız mount yayar.',
|
|
@@ -756,7 +846,7 @@ export const componentKnowledge = {
|
|
|
756
846
|
behavior: [
|
|
757
847
|
"Layout'ta TEK slot olmalı. Enjeksiyon HER slot'a ayrı ayrı kopyalar (layout.functions.ts injectPageSchemaIntoSlots ağacı dolaşır ve type==='slot' gören her düğümün children'ına sayfa şemasının klonunu yazar; önizleme tarafında page.mappers.mapPageLayoutToPreview aynısını yapar): iki slot = sayfa iki kez çizilir, elementId'ler çakışır. Doğrulama: page_state.layoutSlots.",
|
|
758
848
|
"Slot'un yerleşimi ızgara bloğundan gelir ve satır yüksekliği AÇIK UÇLUDUR — runtime slot için grid-row'u `y / auto` yazar (render.functions.ts), yani sayfa içeriği ne kadar uzarsa slot o kadar uzar. Slot'a sabit yükseklik vermeye çalışmak anlamsızdır.",
|
|
759
|
-
"Blok boyu yine de katalog sınırının içinde kalmalı: maxSize.h 200 (2026-09-12'den önce 80'di ve katalog varsayılanı 110 bile sınırın dışındaydı).
|
|
849
|
+
"Blok boyu yine de katalog sınırının içinde kalmalı: maxSize.h 200 (2026-09-12'den önce 80'di ve katalog varsayılanı 110 bile sınırın dışındaydı). Bu sınır grid kanvasının kuralıdır; API blok boyunu denetlemez, ama sınırı aşan blok kanvasta boyutlandırılamaz."
|
|
760
850
|
]
|
|
761
851
|
},
|
|
762
852
|
view: { summary: 'Tabs/switcher altındaki görünüm kapsayıcısı; children gruplamaya yarar.' },
|
|
@@ -1363,6 +1453,11 @@ export const INTERNAL_ROLES_BY_TYPE = {
|
|
|
1363
1453
|
'allday-<yyyy-MM-dd> (tüm gün hücresi, bırakma hedefi)',
|
|
1364
1454
|
'slot-<yyyy-MM-dd>T<HH> (saat dilimi, bırakma hedefi)'
|
|
1365
1455
|
],
|
|
1456
|
+
// Sekme butonu kimliğini sekmenin KEY'inden alır (başlık çeviriye bağlıdır, dil değişince
|
|
1457
|
+
// kayardı). Kök düğüme click DOM sırasındaki ilk sekmeye gider; seçim `tab` eyleminin işidir.
|
|
1458
|
+
tabs: [
|
|
1459
|
+
"tab-<sekme anahtarı>"
|
|
1460
|
+
],
|
|
1366
1461
|
daterangepicker: [
|
|
1367
1462
|
'start (başlangıç tarihi kutusu, valueFrom)',
|
|
1368
1463
|
'end (bitiş tarihi kutusu, valueTo)'
|
|
@@ -21,7 +21,7 @@ export const componentEventContracts = {
|
|
|
21
21
|
datatable: {
|
|
22
22
|
mount: { payload: {}, reads: 'self.filters · self.sortField · self.sortType · self.offset · self.limit' }
|
|
23
23
|
},
|
|
24
|
-
button: { click: NO_DATA },
|
|
24
|
+
button: { mount: NO_DATA, click: NO_DATA },
|
|
25
25
|
card: { click: NO_DATA },
|
|
26
26
|
compound: { click: NO_DATA },
|
|
27
27
|
image: { click: NO_DATA },
|
|
@@ -144,9 +144,40 @@ export const componentEventContracts = {
|
|
|
144
144
|
dropdown: { mount: NO_DATA, change: { payload: { value: 'seçilen option değeri', selectedLabel: "seçilen option'ın label metni (temizlemede '')" } }, search: { payload: { searchText: 'string' } }, focus: NO_DATA, blur: NO_DATA },
|
|
145
145
|
'multi-select': { mount: NO_DATA, change: { payload: { value: "seçilen değerlerin dizisi: [{ value, label, id, text }] — id/text, value/label'ın eski adlı ikizleridir" } }, search: { payload: { searchText: 'string' } }, focus: NO_DATA, blur: NO_DATA },
|
|
146
146
|
'tag-input': { mount: NO_DATA, change: { payload: { value: 'etiket dizisi: [{ value, color? }] — renk verilmemiş etikette color anahtarı HİÇ bulunmaz' } }, search: { payload: { searchText: 'string' } }, focus: NO_DATA, blur: NO_DATA },
|
|
147
|
-
datepicker: {
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
datepicker: {
|
|
148
|
+
mount: NO_DATA,
|
|
149
|
+
change: {
|
|
150
|
+
payload: {
|
|
151
|
+
value: "string 'yyyy-MM-ddTHH:mm:ss' | null (yerel duvar saati, dilim eki yok; seçimde saat 00:00, X ile boşaltılınca null)"
|
|
152
|
+
},
|
|
153
|
+
reads: "düğümün prop'una yazılır: self.value. HH/mm anahtarları YOKTUR (2026-09-15'te kayıttan çıkarıldı — runtime hiç göndermiyordu); event.data boştur (CQ-149)."
|
|
154
|
+
},
|
|
155
|
+
focus: NO_DATA,
|
|
156
|
+
blur: NO_DATA
|
|
157
|
+
},
|
|
158
|
+
datetimepicker: {
|
|
159
|
+
mount: NO_DATA,
|
|
160
|
+
change: {
|
|
161
|
+
payload: {
|
|
162
|
+
value: "string 'yyyy-MM-ddTHH:mm:ss' | null (yerel duvar saati, dilim eki yok; X ile boşaltılınca null)"
|
|
163
|
+
},
|
|
164
|
+
reads: "düğümün prop'una yazılır: self.value. Yalnız tarih + saat ikisi de seçilince yayılır — boş alanda yalnız gün seçmek yaymaz (CQ-237). 2026-09-16 öncesinde bu kayıtta yük anahtarı yoktu; runtime hep { value } gönderiyordu. event.data boştur (CQ-149)."
|
|
165
|
+
},
|
|
166
|
+
focus: NO_DATA,
|
|
167
|
+
blur: NO_DATA
|
|
168
|
+
},
|
|
169
|
+
daterangepicker: {
|
|
170
|
+
mount: NO_DATA,
|
|
171
|
+
change: {
|
|
172
|
+
payload: {
|
|
173
|
+
valueFrom: "string 'yyyy-MM-ddTHH:mm:ss' | null (yerel duvar saati, dilim eki yok; seçimde saat 00:00 — gece yarısı yaşanmayan yaz saati gününde 01:00; yarı X ile boşaltılınca null)",
|
|
174
|
+
valueTo: "string 'yyyy-MM-ddTHH:mm:ss' | null (kullanıcı değişikliğinden sonra hiçbir zaman valueFrom'dan önce değil)"
|
|
175
|
+
},
|
|
176
|
+
reads: "ikisi de düğümün prop'una yazılır: self.valueFrom / self.valueTo. Her change iki anahtarı birden taşır (değişmeyen uç tuttuğu değerle). HH/mm anahtarları YOKTUR (2026-09-16'da kayıttan çıkarıldı — runtime hiç göndermiyordu); event.data boştur (CQ-149)."
|
|
177
|
+
},
|
|
178
|
+
focus: NO_DATA,
|
|
179
|
+
blur: NO_DATA
|
|
180
|
+
},
|
|
150
181
|
datetimerangepicker: {
|
|
151
182
|
mount: NO_DATA,
|
|
152
183
|
change: {
|
|
@@ -60,5 +60,5 @@ export function ensureWorkflowErrorPath(definition, kind) {
|
|
|
60
60
|
branches.push({ id: randomUUID(), name: 'global-error', type: 'global-error', nextStepId: errorStepId });
|
|
61
61
|
}
|
|
62
62
|
startStep.branches = branches;
|
|
63
|
-
return [`hata yolu eklendi: start adımına 'global-error' dalı + '${name}' response adımı (500, { code, message }). Hata yolu olmayan akış patladığında platform
|
|
63
|
+
return [`hata yolu eklendi: start adımına 'global-error' dalı + '${name}' response adımı (500, { code, message }). Hata yolu olmayan akış patladığında platform WorkflowStepFailedException fırlatır (HTTP 500 { code, message, detail, type }; zamanlanmış işte failed + "Step 'x' failed: …"); bu adım çıktıyı { code, message } ile denetim altına alır, zamanlanmış işte sonuç yine failed düşer. Kendi hata gövdenizi istiyorsanız bu adımın bodyExpression'ını değiştirin.`];
|
|
64
64
|
}
|
|
@@ -1951,6 +1951,21 @@ export function orphanedFlowPlan(schema, pageEvents, ops) {
|
|
|
1951
1951
|
if (op.op !== 'set_event' && op.op !== 'remove_event')
|
|
1952
1952
|
continue;
|
|
1953
1953
|
const eventName = String(op.event ?? '');
|
|
1954
|
+
// `remove_event target:'page'` düğümü değil barındırıcının düzey olaylarını hedefler
|
|
1955
|
+
// (`PageSchemaMicroOpApplier.PageTarget`); düğüm aramasına düşseydi plan boş kalır ve yalnız
|
|
1956
|
+
// oraya bağlı akış kapıdan geçip kalıcı silinirdi. Düzey olayı olmayan widget'ta applier da
|
|
1957
|
+
// düğüm aramasına düşer.
|
|
1958
|
+
if (op.op === 'remove_event' && target === 'page' && Array.isArray(pageEvents)) {
|
|
1959
|
+
const hostEvents = asObjects(pageEvents);
|
|
1960
|
+
const removed = hostEvents.find(event => String(event.name ?? '') === eventName);
|
|
1961
|
+
if (typeof removed?.value !== 'string' || removed.value === '')
|
|
1962
|
+
continue;
|
|
1963
|
+
const surviving = new Set(hostEvents.filter(event => event !== removed && typeof event.value === 'string').map(event => String(event.value)));
|
|
1964
|
+
collectFlowRefsExcept(nodes, '', surviving);
|
|
1965
|
+
if (!surviving.has(removed.value))
|
|
1966
|
+
plan.push({ target, op: 'remove_event', flowIds: [removed.value] });
|
|
1967
|
+
continue;
|
|
1968
|
+
}
|
|
1954
1969
|
const node = findNodeByElementId(nodes, target);
|
|
1955
1970
|
const current = asObjects(node?.events).find(event => String(event.name ?? '') === eventName);
|
|
1956
1971
|
const currentValue = typeof current?.value === 'string' ? current.value : '';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fastJsonPatch from 'fast-json-patch';
|
|
1
2
|
import { functionSignature } from './functionGuards.js';
|
|
2
3
|
function asArray(value) {
|
|
3
4
|
return Array.isArray(value) ? value.filter((entry) => Boolean(entry) && typeof entry === 'object') : [];
|
|
@@ -280,22 +281,38 @@ export function describePatchTarget(document, path) {
|
|
|
280
281
|
const kind = entry.type ?? entry.dbType;
|
|
281
282
|
return `${path} → '${label}'${kind ? ` (${String(kind)}` + `, id ${String(entry.id ?? '?')})` : `, id ${String(entry.id ?? '?')}`}`;
|
|
282
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Her op, KENDİSİNDEN ÖNCEKİ op'ların uygulanmış hâlindeki belgeye karşı çözülür ve hemen
|
|
286
|
+
* ardından o tek op çalışan kopyaya uygulanır (S-3): aynı diziye giden birden çok `remove`
|
|
287
|
+
* seçicisi tek seferde ORİJİNAL belgeye göre indekse çevrilseydi, ilk silme diziyi kısaltıp
|
|
288
|
+
* sonraki op'ların indeksini kaydırırdı — yanıt yine de "applied: true" derdi çünkü hedef adı da
|
|
289
|
+
* aynı bayat belgeden okunuyordu. Dönen `operations` dizisi, orijinal belgeye karşı SIRAYLA
|
|
290
|
+
* uygulandığında (tek `fastJsonPatch.applyPatch` çağrısıyla dahi) bu adım adım simülasyonla aynı
|
|
291
|
+
* sonucu üretir; çağıranların uygulama biçimini değiştirmesi gerekmez.
|
|
292
|
+
*/
|
|
283
293
|
export function resolvePatchOperations(document, operations, readTool = 'workflow_get') {
|
|
284
294
|
const notes = [];
|
|
285
295
|
const targets = [];
|
|
286
|
-
const
|
|
296
|
+
const resolvedOperations = [];
|
|
297
|
+
let working = structuredClone(document);
|
|
298
|
+
for (const operation of operations) {
|
|
287
299
|
const path = typeof operation.path === 'string' ? operation.path : '';
|
|
288
300
|
const op = typeof operation.op === 'string' ? operation.op : '';
|
|
289
|
-
const outcome = resolvePatchPointer(
|
|
290
|
-
const from = typeof operation.from === 'string' ? resolvePatchPointer(
|
|
301
|
+
const outcome = resolvePatchPointer(working, path, readTool, op);
|
|
302
|
+
const from = typeof operation.from === 'string' ? resolvePatchPointer(working, operation.from, readTool, op) : undefined;
|
|
291
303
|
if (outcome.note)
|
|
292
304
|
notes.push(outcome.note);
|
|
293
305
|
if (from?.note)
|
|
294
306
|
notes.push(from.note);
|
|
295
|
-
targets.push(describePatchTarget(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
307
|
+
targets.push(describePatchTarget(working, outcome.path));
|
|
308
|
+
const resolvedOperation = from ? { ...operation, path: outcome.path, from: from.path } : { ...operation, path: outcome.path };
|
|
309
|
+
resolvedOperations.push(resolvedOperation);
|
|
310
|
+
// validate:false — bu yalnız SONRAKİ op'ların indeksini doğru izlemek için ara bir simülasyon;
|
|
311
|
+
// gerçek RFC6902 doğrulaması (ör. 'replace' hedefinin önceden var olması) çağıranın az sonra
|
|
312
|
+
// yapacağı asıl uygulamada (validate:true) hâlâ çalışır, burada erken ve gereksiz patlamaz.
|
|
313
|
+
working = fastJsonPatch.applyPatch(working, [resolvedOperation], false, true).newDocument;
|
|
314
|
+
}
|
|
315
|
+
return { operations: resolvedOperations, notes, targets };
|
|
299
316
|
}
|
|
300
317
|
/**
|
|
301
318
|
* Fonksiyon özeti (G-07): kaynak, ad, kapsam, imza, parametre listesi, gövde satır sayısı —
|
package/dist/knowledge/rules.js
CHANGED
|
@@ -4,6 +4,7 @@ import { reservedTenantTables } from './reservedTables.js';
|
|
|
4
4
|
import { headersAccessNames, isHeadersAccessGuarded } from './flowGuards.js';
|
|
5
5
|
import { callsItself, functionCallRefs, isValidParameterName, mentionsAwait, nameProblem, sourceOf, callPrefix } from './functionGuards.js';
|
|
6
6
|
import { backendPolicyRules } from './backendConstraints.js';
|
|
7
|
+
import { themePolicyRules } from './themeRules.js';
|
|
7
8
|
const terminalStepTypes = new Set(['response', 'convert', 'revert']);
|
|
8
9
|
const DESCRIPTION_EXEMPT_STEPS = new Set(['start']);
|
|
9
10
|
const stepKindMatrix = {
|
|
@@ -2716,7 +2717,7 @@ export const policyRules = [
|
|
|
2716
2717
|
id: 'WF-021',
|
|
2717
2718
|
module: 'workflow',
|
|
2718
2719
|
appliesTo: ['create', 'update'],
|
|
2719
|
-
sourceRef: "IStep.cs:
|
|
2720
|
+
sourceRef: "IStep.cs:88-104 bağlanmamış/eksik fail dalını global-error dalına yönlendirir; ikisi de yoksa canlıda WorkflowStepFailedException fırlatılır (2026-09-16), önizlemede ActivityContext.SetUnhandledError 500 gövdesi kurar. automation'da 'response' adımı yasak (stepKindMatrix) olduğu için gateway bu tipte enjeksiyon yapmaz — errorPath.ts",
|
|
2720
2721
|
check: (definition, context) => {
|
|
2721
2722
|
if (context.workflowKind !== 'automation')
|
|
2722
2723
|
return [];
|
|
@@ -2788,6 +2789,7 @@ export const policyRules = [
|
|
|
2788
2789
|
},
|
|
2789
2790
|
// Backend doğrulayıcılarının aynası (ENT-015…018, MS-017, WF-026, QRY/VIEW/DTO/ROW/DS/PRJ/TR/FLD/FILE/EXT):
|
|
2790
2791
|
// tek liste `backendConstraints.ts`'te durur, buradan yalnız politika motoruna katılır.
|
|
2792
|
+
...themePolicyRules,
|
|
2791
2793
|
...backendPolicyRules()
|
|
2792
2794
|
];
|
|
2793
2795
|
/**
|