@appaflytech/zeyrek-ai-mcp 0.0.20 → 0.0.21
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 +14 -13
- package/dist/config.js +0 -2
- package/dist/knowledge/componentCatalog.js +940 -215
- package/dist/knowledge/componentEvents.js +368 -75
- package/dist/knowledge/normalize.js +66 -63
- package/dist/knowledge/rules.js +29 -6
- package/dist/knowledge/styleResolve.js +1 -1
- package/dist/knowledge/themeResolve.js +3 -3
- package/dist/platform/diagnostics.js +85 -0
- package/dist/platform/domSummary.js +1 -1
- package/dist/platform/ifExists.js +129 -0
- package/dist/platform/responses.js +2 -1
- package/dist/platform/{capture/capture.js → screenshot.js} +509 -23
- package/dist/platform/strictArguments.js +22 -2
- package/dist/platform/writeDiff.js +58 -31
- package/dist/platform/writeView.js +17 -0
- package/dist/resources/guides/component.md +9 -6
- package/dist/resources/guides/functions.md +32 -3
- package/dist/resources/guides/getting-started.md +35 -0
- package/dist/resources/guides/layout.md +7 -11
- package/dist/resources/guides/page.md +49 -71
- package/dist/resources/guides/translation.md +5 -6
- package/dist/resources/schema-fingerprint.json +2 -2
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +18 -0
- package/dist/server.js +0 -2
- package/dist/tools/applications.js +3 -60
- package/dist/tools/components.js +10 -50
- package/dist/tools/designSchemaPatch.js +13 -18
- package/dist/tools/externalComponents.js +4 -25
- package/dist/tools/flows.js +38 -51
- package/dist/tools/functions.js +20 -10
- package/dist/tools/layouts.js +9 -41
- package/dist/tools/microservices.js +39 -11
- package/dist/tools/pages.js +95 -127
- package/dist/tools/platformInfo.js +1 -2
- package/dist/tools/schemaOps.js +2 -2
- package/dist/tools/screenWrite.js +2 -2
- package/dist/tools/screens.js +3 -9
- package/dist/tools/workflows.js +39 -12
- package/package.json +7 -2
- package/dist/knowledge/mobileComponentCatalog.js +0 -331
- package/dist/knowledge/mobileComponentEvents.js +0 -50
- package/dist/knowledge/platform/lint.js +0 -205
- package/dist/knowledge/platform/mobile.js +0 -78
- package/dist/knowledge/platform/mobileRules.js +0 -121
- package/dist/knowledge/platform/mobileTabs.js +0 -108
- package/dist/knowledge/platform/profile.js +0 -20
- package/dist/knowledge/platform/resolve.js +0 -122
- package/dist/knowledge/platform/web.js +0 -38
- package/dist/knowledge/styleResolveNative.js +0 -410
- package/dist/platform/capture/actions.js +0 -333
- package/dist/platform/capture/browser.js +0 -1
- package/dist/platform/capture/index.js +0 -10
- package/dist/platform/capture/readiness.js +0 -103
- package/dist/platform/capture/summary.js +0 -77
- package/dist/platform/capture/target.js +0 -5
- package/dist/platform/capture/targets/studio-mobile.js +0 -15
- package/dist/platform/capture/targets/studio-web.js +0 -5
- package/dist/resources/examples/mobile-app-shell-drawer.json +0 -209
- package/dist/resources/examples/mobile-app-shell-stack.json +0 -123
- package/dist/resources/examples/mobile-app-shell-tab.json +0 -174
- package/dist/resources/examples/mobile-list-detail-form.json +0 -656
- package/dist/resources/guides/mobile.md +0 -215
- package/dist/tools/mobile.js +0 -203
- package/dist/tools/profileWrite.js +0 -45
|
@@ -4,10 +4,6 @@ Studio'nun tuval tarafı. Buradaki kurallar controller + komut kodundan doğrula
|
|
|
4
4
|
(`zeyrek-mcp/docs/13-faz2-envanter.md` §4); veri/mantık tarafı için
|
|
5
5
|
`platform_guide('entity')`, `('microservice')`, `('workflow')`.
|
|
6
6
|
|
|
7
|
-
> **Mobil uygulamada** (`type: 'mobile'`) şema ve micro-op'lar aynıdır ama yerleşim yalnız flex'tir
|
|
8
|
-
> (blocks çizilmez), görünüm tipli gruplarla yazılır ve `page_create` kökü flex sütun kurar —
|
|
9
|
-
> `platform_guide('mobile')`. Bu rehberdeki "dar ekran" notları WEB uygulamasının telefon kırılımıdır.
|
|
10
|
-
|
|
11
7
|
## Kuruluş sırası
|
|
12
8
|
|
|
13
9
|
```
|
|
@@ -97,8 +93,9 @@ mümkündür ama doğrulama duvarı ve canlı canvas yalnız `page_schema_patch`
|
|
|
97
93
|
komponentin iç kimliğidir (aşağıda Kural 2, `FLOW-018`).
|
|
98
94
|
|
|
99
95
|
- **`blocks[].size`'ı komponentin `component_get`'teki `minSize`..`maxSize` aralığında tut.** Dikkat:
|
|
100
|
-
katalog varsayılanı aşabiliyor (`
|
|
101
|
-
|
|
96
|
+
katalog varsayılanı aşabiliyor (`datepicker` default `h:8`, `maxSize` `h:5`; 18 şemada aynı
|
|
97
|
+
durum, liste zeyrek-frontend `docs/issues.md` ARC-013 — `page-header` 2026-09-18'de sınırı
|
|
98
|
+
12'ye açarak çıktı) — varsayılanı körü körüne kopyalama. Sınır grid kanvasının kuralıdır; API 2026-09-15'ten beri reddetmez, ama aşan
|
|
102
99
|
blok kanvasta boyutlandırılamaz (aşağıda Kural 7 "Boyut tuzağı").
|
|
103
100
|
- **Kurulmuş bir düğümün boyutunu `resize_component` micro-op'u değiştirir.**
|
|
104
101
|
`{ op: 'resize_component', target: '<elementId>', size: { w, h } }` ızgara boyutunu,
|
|
@@ -163,19 +160,32 @@ Sayfa açılışında veri çekmek için `mount` kullanılır ama tek seçenek o
|
|
|
163
160
|
|
|
164
161
|
Yani "satırı seçince detay getir" (`select`), "kolondan süzünce sunucudan yeniden çek"
|
|
165
162
|
(`filter`), "sayfa değişince yeni sayfayı çek" (`pagination`), "satıra çift tıklayınca formu aç"
|
|
166
|
-
(`doubleClick`) akışları da aynı `set_event` mekanizmasıyla kurulur. Buna karşılık `
|
|
167
|
-
|
|
163
|
+
(`doubleClick`) akışları da aynı `set_event` mekanizmasıyla kurulur. Buna karşılık `datatable`
|
|
164
|
+
yalnız `mount` yayar (bilinçli — Kural 1e); `page-header` 2026-09-18'den beri izdeki öğe
|
|
165
|
+
tıklamasını `clickItem` olarak yayar (`component_get` yükü verir).
|
|
168
166
|
|
|
169
167
|
**Olay adları `on` ÖNEKİ ALMAZ** (`button` → `click`, `form` → `submit`), tek istisna katalogda
|
|
170
168
|
`texteditor`'dur (`onMount`/`onChange`). **Komponentin desteklemediği bir olay adı verirsen bağ
|
|
171
169
|
sessizce ölü kalır** — önce `component_get`. Gateway `set_event`'i katalogla karşılaştırır ve
|
|
172
170
|
uymayan adı **PAGE-008** ile istek gitmeden reddeder.
|
|
173
171
|
|
|
172
|
+
**Bir olaya birden fazla akış bağlanabilir — ikinciyi `add_event` ile ekle.** `set_event` olayın
|
|
173
|
+
BÜTÜN bağlarını tek akışa indirir: başlık alanının `change` olayına makale önerisi bağlıyken akıllı
|
|
174
|
+
öneriyi `set_event` ile bağlamak makale önerisini devre dışı bırakır. Gateway bunu **PAGE-034** ile
|
|
175
|
+
istek gitmeden reddeder. Doğru op `{ "op": "add_event", "target": "<elementId>", "event": "change",
|
|
176
|
+
"eventValue": "<ikinci flow id>" }`'dir. Olay tetiklenince bağlı akışların hepsi **paralel ve
|
|
177
|
+
birbirinden bağımsız** koşar: biri hata verirse diğeri etkilenmez, **sıra garantisi yoktur**. Biri
|
|
178
|
+
diğerinin sonucunu bekliyorsa ya da ikisi aynı değişkene/prop'a yazıyorsa ayrı bağ değil,
|
|
179
|
+
`flow-trigger` adımıyla zincir kur (Kural 1c). Mevcut bağı bilerek değiştirmek için `set_event`
|
|
180
|
+
op'una `replaceBoundFlows: true` ekle. **Mobil runtime yalnız ilk akışı koşar** — mobil
|
|
181
|
+
uygulamada olay başına tek akış bağla.
|
|
182
|
+
|
|
174
183
|
**Olay KALDIRMAK için `remove_event` kullan.** Platformun `set_event` micro-op'u olay silemez:
|
|
175
184
|
`eventValue: null` verildiğinde kayıt `{ name: 'click' }` olarak (değersiz) kalır, diziden
|
|
176
185
|
çıkmaz — şemada ölü bağ artığı bırakır. `{ "op": "remove_event", "target": "<elementId>",
|
|
177
186
|
"event": "click" }` platformun op'udur: olayı diziden çıkarır (yanıtta `removedEvents`); olmayan
|
|
178
|
-
bir olayı kaldırmaya çalışmak `missing-event` ile 422 döner.
|
|
187
|
+
bir olayı kaldırmaya çalışmak `missing-event` ile 422 döner. Olaya birden fazla akış bağlıysa
|
|
188
|
+
kaldırılacak akışı `eventValue` ile ver; vermezsen `ambiguous-event` ile 422 döner. Sayfa düzeyi olaylar için
|
|
179
189
|
`target: "page"`. Referanssız kalan akış silineceği için `allowFlowDeletion` kuralı (G-21) bu op'ta
|
|
180
190
|
da geçerlidir.
|
|
181
191
|
|
|
@@ -189,12 +199,14 @@ olaylarında **boştur** (ölçüm 2026-08-25, kaynak okuması: `flow-machine.ts
|
|
|
189
199
|
Pratik kural: **`payload` anahtarları aynı zamanda prop adlarıdır; akışta `self.<anahtar>` ile
|
|
190
200
|
oku** (ya da `value { type:'property', ref:{ source:'component', element, property } }` ile).
|
|
191
201
|
`event.data` yalnız `params` ile gelen olaylarda dolar — `html` komponentinin `fireEvent`
|
|
192
|
-
aksiyonları (`platform_guide('html')`) ve
|
|
193
|
-
`importwizard` · `kanban` · `signature` · `stepper`
|
|
194
|
-
|
|
195
|
-
yazmaz (`component_get` çıktısındaki sözleşme notları ayrımı
|
|
196
|
-
|
|
197
|
-
|
|
202
|
+
aksiyonları (`platform_guide('html')`) ve **`params`'ı da gönderen komponentler**
|
|
203
|
+
(`eventcalendar` · `importwizard` · `kanban` · `signature` · `stepper` · `tabs` ·
|
|
204
|
+
`tree-view` · `pagination`): bunların yükü `event.data.<anahtar>` ile de okunur; `kanban` ve
|
|
205
|
+
`eventcalendar` yükü `self`'e HİÇ yazmaz (`component_get` çıktısındaki sözleşme notları ayrımı
|
|
206
|
+
söyler). Sessiz hata örneği: **tablonun kendi** sayfalama akışını (`table.pagination`)
|
|
207
|
+
`event.data.limit`'e bağlarsan sorgu `LIMIT null OFFSET null` ile koşar ve **tüm satırları**
|
|
208
|
+
döndürür; hata yok, sayfalama yok. (Bağımsız `pagination` komponenti bu tuzağa girmez, yükünü
|
|
209
|
+
`params` ile de gönderir.)
|
|
198
210
|
|
|
199
211
|
| Komponent · olay | Yük (aynı zamanda prop adları) | Akışta nereden okunur |
|
|
200
212
|
|---|---|---|
|
|
@@ -204,16 +216,18 @@ sayfalama akışını `event.data.limit`'e bağlarsan sorgu `LIMIT null OFFSET n
|
|
|
204
216
|
| `table.select` · `doubleClick` | — | `self.selectedRow` |
|
|
205
217
|
| `table.selectionChange` | — | `self.selectedRows` |
|
|
206
218
|
| `datatable.mount` | — | `self.filters` · `self.sortField` · `self.sortType` · `self.offset` |
|
|
207
|
-
| `pagination.change` | `{ offset, limit }` | `self.offset` · `self.limit` |
|
|
219
|
+
| `pagination.change` | `{ offset, limit }` | `self.offset` · `self.limit` ya da `event.data.offset` · `event.data.limit` |
|
|
208
220
|
| `textinput/textarea/password.change` | `{ value }` | `self.value` |
|
|
209
221
|
| `dropdown.change` · `multi-select.change` | `{ value }` | `self.value` |
|
|
210
222
|
| `dropdown.search` · `multi-select.search` | `{ searchText }` | `self.searchText` |
|
|
211
|
-
| `tabs.tab` | `{ selected }` | `self.selected` |
|
|
223
|
+
| `tabs.tab` | `{ selected }` | `self.selected` ya da `event.data.selected` |
|
|
212
224
|
| `chart.dataPointClick` | `{ name, seriesName, value, dataIndex, row }` | `self.row` (kaynak satırın tamamı) |
|
|
213
|
-
| `repeater.change` | `{ selectedIndex }` | `
|
|
225
|
+
| `repeater.change` · `repeater.select` | `{ selectedIndex }` | `self.selectedIndex` · `self.selectedItem` (akış satır bağlamında koşmaz, `item`/`Row` boş) |
|
|
214
226
|
| `html` aksiyonu (`fireEvent`) | ikinci argüman | **`event.data`** |
|
|
215
227
|
| `kanban.cardMove` | `{ id, row, from, to }` | **`event.data`** (self'e yazılmaz) |
|
|
228
|
+
| `kanban.cardAdd` · `kanban.cardRemove` | `{ column }` · `{ id, row, column }` | **`event.data`** (self'e yazılmaz; kart eklenmez/gizlenmez, akış yazıp `rows`'u tazeler) |
|
|
216
229
|
| `eventcalendar.eventMove` | `{ id, row, start, end, previousStart, previousEnd }` | **`event.data`** (self'e yazılmaz) |
|
|
230
|
+
| `eventcalendar.monthChange` · `eventcalendar.viewChange` · `eventcalendar.eventCreate` | `{ month, year, view, start, end }` · `{ view, start, end }` · `{ start, end, allDay }` | **`event.data`** (self'e yazılmaz; veri sorgusunu kesişimle bağla: başlangıç < `end`+1 gün ve bitiş >= `start`) |
|
|
217
231
|
| `importwizard.complete` | `{ rows, errors, fileName, total }` | `self.rows`… ya da `event.data` |
|
|
218
232
|
| `stepper.stepChange` | `{ currentStep, previous }` | `self.currentStep` ya da `event.data` |
|
|
219
233
|
| `signature.change` | `{ value }` | `self.value` ya da `event.data.value` |
|
|
@@ -372,8 +386,11 @@ göstermek error flow'un işidir.
|
|
|
372
386
|
> `errorTasks.some(t => t.type !== 'start')` arar. Start'ın ardına en az bir adım bağla —
|
|
373
387
|
> gateway `FLOW-021` ile uyarır.
|
|
374
388
|
>
|
|
375
|
-
> **
|
|
376
|
-
> `
|
|
389
|
+
> **Mobilde `errorSteps` diye bir şey YOK.** `ScreenRuntime.tsx` `mapFlowsToMachine` yalnız
|
|
390
|
+
> `tasks` üretir (web `Runtime.svelte` ayrıca `errorTasks` verir), yani mobil uygulamada
|
|
391
|
+
> `hasErrorFlow` her zaman false: hata yolu hiç koşmaz ve akış yukarıdaki 2. yoldan —
|
|
392
|
+
> `always` + hata gövdeli storage — devam eder. Mobil sayfada hata yolunu `condition
|
|
393
|
+
> Steps.<adımAdı>.error` ile kur.
|
|
377
394
|
|
|
378
395
|
> **Hata metni ÜÇ ayrı yerde durur ve ikisi kullanıcıya gösterilecek metin DEĞİLDİR.**
|
|
379
396
|
> `onError` hata akışını koşturmadan önce `machine.setStorage('error', errorInfo)` yapar
|
|
@@ -503,14 +520,14 @@ değer tipleri: `static · page · property · storage · variable · code · it
|
|
|
503
520
|
> tip register eder, gerisini uygulama ekler. Bir sayfa TEK bir uygulamaya aittir
|
|
504
521
|
> (`Page.ApplicationId`) ve uygulamanın tipi `web` ya da `mobile`'dır (`ApplicationType.cs`), yani
|
|
505
522
|
> sayfanın barındırıcısı bellidir — matris "hangi tip sende çalışır"ı söyler, iki barındırıcıda
|
|
506
|
-
> birden koşmayı değil (web `Runtime.svelte`, mobil
|
|
523
|
+
> birden koşmayı değil (web `Runtime.svelte`, mobil `ScreenRuntime.tsx`):
|
|
507
524
|
>
|
|
508
|
-
> | Adım tipi | Web | Mobil
|
|
525
|
+
> | Adım tipi | Web | Mobil | Nerede register ediliyor |
|
|
509
526
|
> |---|---|---|---|
|
|
510
|
-
> | `start` · `setter` · `code` · `condition` · `microservice` · `validation` · `flow-trigger` · `function` | ✅ | ✅ | `flow-engine.ts` — motorun kendisi |
|
|
511
|
-
> | `alert` · `redirect` · `setcookie` · `storage` | ✅ | ✅ |
|
|
512
|
-
> | `confirm` · `download` | ✅ |
|
|
513
|
-
> | `navigate` | ❌ | ✅
|
|
527
|
+
> | `start` · `setter` · `code` · `condition` · `microservice` · `validation` · `flow-trigger` · `function` | ✅ | ✅ | `flow-engine.ts` — motorun kendisi (`function` mobilde kayıtlıdır ama mobil runtime `Functions`'ı boş kurar — K11, çağrı çalışmaz) |
|
|
528
|
+
> | `alert` · `redirect` · `setcookie` · `storage` | ✅ | ✅ | uygulama; mobilde `redirect` navigate, `setcookie` storage uygulamasına eşlenir |
|
|
529
|
+
> | `confirm` · `download` | ✅ | ❌ | yalnız `Runtime.svelte` |
|
|
530
|
+
> | `navigate` | ❌ | ✅ | yalnız `ScreenRuntime.tsx` — web'deki karşılığı `redirect` |
|
|
514
531
|
> | `end` · `query` | ❌ | ❌ | hiçbir yerde — üstelik `query` backend sözlüğünde de yok (`StepType.cs` onu saymaz), yalnız frontend enum'unda duruyor |
|
|
515
532
|
>
|
|
516
533
|
> **Register edilmemiş bir tipe gelen akış SESSİZCE durur.** `flow-engine.ts` `process()`
|
|
@@ -844,7 +861,7 @@ kullanır: `page.mappers.ts` `mapPageLayoutToPreview` — layout varsa çizilen
|
|
|
844
861
|
> `add_component` ile yeniden kurmaktır (sonrasında Kural 2'deki flow yeniden kaydetme adımı
|
|
845
862
|
> ZORUNLU olur).
|
|
846
863
|
|
|
847
|
-
|
|
864
|
+
Mobil not: <768px'te ızgara tek kolona düşer (`RenderComponent` media query'si) — y sırası
|
|
848
865
|
dikey sıraya dönüşür, x/w yok sayılır. Yerleşimi masaüstü (breakpoint 1024) bloğuyla kur.
|
|
849
866
|
|
|
850
867
|
## Kural 1f-2 — Kapsayıcı düzeni: `flex` (varsayılan) ↔ `grid`
|
|
@@ -933,10 +950,10 @@ Beş şeyi bilmeden flex kurma:
|
|
|
933
950
|
4. **`layout: 'grid'` iken diğer altı prop ÖLÜDÜR.** Katalogda tanımlı oldukları için
|
|
934
951
|
doğrulama duvarı susar, renderer da okumaz: ızgara kapsayıcıya `direction: 'column'` yazmak
|
|
935
952
|
sessizce hiçbir şey yapmaz. Gateway bunu **PAGE-015 (uyarı)** ile söyler.
|
|
936
|
-
5. **Flex düzeni kırılım BİLMEZ.** `direction`/`gap`/hizalama masaüstü ve
|
|
937
|
-
sıra ve span'lar Desktop (1024) bloğundandır — Studio,
|
|
953
|
+
5. **Flex düzeni kırılım BİLMEZ.** `direction`/`gap`/hizalama masaüstü ve mobilde AYNIDIR;
|
|
954
|
+
sıra ve span'lar Desktop (1024) bloğundandır — Studio, mobil kırılım düzenlenirken flex
|
|
938
955
|
bölgeyi salt-okunur kilitler. Kırılım bilen yalnız `blocks[]` ve `appearance.hideOn`'dur;
|
|
939
|
-
|
|
956
|
+
mobilde farklı davranış gereken satır için `layout: 'grid'` kullan (Kural 1f mobil notu).
|
|
940
957
|
|
|
941
958
|
```jsonc
|
|
942
959
|
// Ortalanmış giriş kartı — style ile CSS hack'i YOK, kabın kendi düzeni
|
|
@@ -1080,45 +1097,6 @@ kendisi nesneye çevirir; Studio tablosunda `[object Object]` görünmesi normal
|
|
|
1080
1097
|
(`platform_guide('entity')` → "TEXT kolonunda JSON"). Ekranın görsel tarafı için **Kural 1h**:
|
|
1081
1098
|
tema `--ng-*` değişkenleriyle tek yerden çevrilir, `html` kaçış kapısına gerek kalmaz.
|
|
1082
1099
|
|
|
1083
|
-
## Kural 1g-2 — Mobil davranış: dört ayar, dört ayrı sahip
|
|
1084
|
-
|
|
1085
|
-
Mobil listelerin davranışı TEK bileşende toplanmaz. Hangi ayarın kimde olduğunu bilmeden yazılan
|
|
1086
|
-
şema sessizce çalışmaz — prop var olmayan bileşene yazılır ve `page_schema_patch` onu düşürmez,
|
|
1087
|
-
çizer yok sayar.
|
|
1088
|
-
|
|
1089
|
-
| Davranış | Sahip bileşen | Prop / olay |
|
|
1090
|
-
|---|---|---|
|
|
1091
|
-
| Çekerek yenile | `scroll-view` (listeyi SARAN kap) | `refreshable: true` + `refresh` olayı |
|
|
1092
|
-
| Sonsuz kaydırma | `scroll-view` | `scrollEnd` olayı (prop yok) |
|
|
1093
|
-
| Kaydırma eylemleri | `repeater` | `swipeActions: [{ key, label, tone, icon }]` + `swipe` olayı, payload `{ key, index, row }` |
|
|
1094
|
-
| Satıra dokunma | `repeater` | `itemPressable: true` + `itemPress` olayı, payload `{ index, row }` |
|
|
1095
|
-
|
|
1096
|
-
Çekerek yenileyi `repeater`'a yazmak en sık hatadır: liste kendi kaydırmasını yapmaz, onu saran
|
|
1097
|
-
`scroll-view` yapar. `repeater` kökteyse (kap yok) yenileme hiç çizilmez.
|
|
1098
|
-
|
|
1099
|
-
Satıra dokunmanın kartın `click`'iyle yapılan eski yolu mobilde bırakıldı: `itemPress` satır
|
|
1100
|
-
bağlamını payload'da taşır ve seçimi (`selectedIndex`) de yazar, yani akış satırı
|
|
1101
|
-
`<tekrarlayıcı>.selectedItem` ile okumaya devam eder.
|
|
1102
|
-
|
|
1103
|
-
### `redirect.presentation`
|
|
1104
|
-
|
|
1105
|
-
`redirect` adımının `args.presentation` alanı ekranın NASIL açıldığını söyler ve kapalı bir küme
|
|
1106
|
-
alır:
|
|
1107
|
-
|
|
1108
|
-
- `push` — yığına ekler, geri düğmesi önceki ekrana döner (**varsayılan**; alan yazılmayabilir)
|
|
1109
|
-
- `modal` — alttan açılan ayrı bir sunum; geri onu kapatır, altındaki ekran yerinde kalır
|
|
1110
|
-
- `replace` — geçerli ekranı değiştirir, geçmişe girmez (giriş → ana ekran için doğru olan)
|
|
1111
|
-
|
|
1112
|
-
Küme dışı bir değer **MOB-008** uyarısıdır ve backend doğrulayıcısı 422 döner. Alanı hiç yazmamak
|
|
1113
|
-
kusur değildir.
|
|
1114
|
-
|
|
1115
|
-
**Sekme hedefinde `modal` çalışmaz.** Hedef sayfa bir sekmeyse gezinme her zaman `navigate`'e
|
|
1116
|
-
düşer: sekme yığını kendi geçmişini tutar ve modal onu kırardı. `presentation`ı yazabilirsiniz,
|
|
1117
|
-
çizer sessizce yok sayar — sekme dışı bir sayfaya modal istiyorsanız o sayfayı sekme listesinden
|
|
1118
|
-
çıkarın.
|
|
1119
|
-
|
|
1120
|
-
Web uygulamasında alan yok sayılır; gateway web profilinde bu konuda bulgu üretmez.
|
|
1121
|
-
|
|
1122
1100
|
## Kural 1h — Tasarım: `style` prop'u ve tema değişkenleri
|
|
1123
1101
|
|
|
1124
1102
|
Her komponentin `style` prop'u vardır ve emotion `css()` bloğudur: iç seçiciler, pseudo-class'lar
|
|
@@ -1338,7 +1316,7 @@ budur — bir preset ya da `componentStyles` sizin değerinizi eziyorsa `styleLa
|
|
|
1338
1316
|
| Değişiklik | Tool | Neden |
|
|
1339
1317
|
|---|---|---|
|
|
1340
1318
|
| Komponent ekle/sil/taşı, prop, binding, event | `page_schema_patch` | Doğrulama duvarı + açık Studio canvas'ına SignalR canlı yayını + eşzamanlı yazar kilidi yalnız bu yolda çalışır |
|
|
1341
|
-
| Ad, slug, browserTitle, `browserTitleKey`, layout, roller, middleware | `page_update` | Üstbilgi alanları micro-op sözlüğünde yok. `browserTitleKey` sekme başlığını çeviri anahtarına bağlar: verilirse başlık sözlükten çözülür, boşsa `browserTitle` kullanılır. Başlık
|
|
1319
|
+
| Ad, slug, browserTitle, `browserTitleKey`, layout, roller, middleware | `page_update` | Üstbilgi alanları micro-op sözlüğünde yok. `browserTitleKey` sekme başlığını çeviri anahtarına bağlar: verilirse başlık sözlükten çözülür, boşsa `browserTitle` kullanılır. Başlık canlı dil değişimini izler; anahtarın o dilde değeri yoksa varsayılan dile düşer (`platform_guide('translation')`) |
|
|
1342
1320
|
|
|
1343
1321
|
Platformun `PUT /pages/...` ucu **replace**'tir: gönderilmeyen `schema`/`events`/`roleIds`
|
|
1344
1322
|
alanları silinir. Gateway bu yüzden `page_update`'te sayfayı önce okur, yalnız verdiğin
|
|
@@ -1853,7 +1831,7 @@ bağlanır, filtre `source:'expression'` + `value:'user.id'` olur.
|
|
|
1853
1831
|
| Kimlik alanları | `email` · `password` |
|
|
1854
1832
|
| Dosya | `fileUpload` (dropzone) · `fileInput` · `filebutton` · `file-viewer` |
|
|
1855
1833
|
| Liste | `table` · `datatable` (Kural 1e) · `repeater` (kart listesi VE dinamik form — Kural 1g) · `tree-view` (hiyerarşi; `isSearchable` ile istemci içi arama) · `timeline` (tarihli olay akışı) |
|
|
1856
|
-
| Pano / takvim | `kanban` (durum kolonlarında sürüklenebilir kartlar; taşıma `cardMove` ile `event.data`'dan okunur, kalıcılık AKIŞIN işidir) · `eventcalendar` (ay/hafta/gün; veri `rows`'a akışla yazılır, `monthChange`
|
|
1834
|
+
| Pano / takvim | `kanban` (durum kolonlarında sürüklenebilir kartlar; taşıma `cardMove` ile `event.data`'dan okunur, kalıcılık AKIŞIN işidir) · `eventcalendar` (ay/hafta/gün/ajanda; veri `rows`'a akışla yazılır, `monthChange`/`viewChange` görünen `start`/`end` aralığıyla tazeleme kancasıdır) |
|
|
1857
1835
|
| Kayıt detayı | `detailview` — tek kaydı etiket/değer ızgarası basar (alan başına format, iç içe alan yolu); OLAY YAYMAZ, tıklanabilirlik gerekiyorsa kapsayıcıya sar |
|
|
1858
1836
|
| Adımlı akış | `stepper` — tabs gibi her adım kendi droppable görünümünü taşır; ileri gidiş `canProceed` kapısıyla (`{{ form1.isValid === true }}` biçimi), adım `currentStep` setter'ıyla sürülür |
|
|
1859
1837
|
| İmza / CSV içe aktarma | `signature` (değer PNG data-URL ya da ham SVG; `change` setter'lı) · `importwizard` (3 adımlı sihirbaz; temiz+hatalı satırlar `complete` yükünde — satırları uca yazmak akışın işidir) |
|
|
@@ -175,11 +175,10 @@ motor olmasıdır (tarayıcı JS'i ve Jint).
|
|
|
175
175
|
verilmişse sekme başlığı çeviri sözlüğünden çözülür; anahtar boşsa `browserTitle` olduğu gibi
|
|
176
176
|
kullanılır. İkisi de boşsa sayfa adı yazılır.
|
|
177
177
|
|
|
178
|
-
> **Sekme başlığı
|
|
179
|
-
>
|
|
180
|
-
>
|
|
181
|
-
>
|
|
182
|
-
> çözülmesi. Sekme başlığının dilini doğrulayacaksan **yeniden yükleyerek** doğrula.
|
|
178
|
+
> **Sekme başlığı canlı dil değişimini İZLER.** `language-selector` ile dil değiştirildiğinde
|
|
179
|
+
> sayfa içeriğiyle birlikte sekme başlığı da yeni dilde çözülür; yeniden yükleme gerekmez
|
|
180
|
+
> (ölçüldü 2026-09-11). Anahtarın seçilen dilde değeri yoksa projenin varsayılan diline düşer.
|
|
181
|
+
> 2026-09-08 ölçümündeki "açılıştaki dilde kalır" davranışı düzeltildi.
|
|
183
182
|
|
|
184
183
|
## Doğrulama mesajları: `t:` öneki
|
|
185
184
|
|
|
@@ -209,7 +208,7 @@ gerekmez — `schema.ts`'e dokunulmaz, katalog yeniden yüklenmez.
|
|
|
209
208
|
`translation_update` artık uygulamanın bütün sayfalarının önbellek satırlarını düşürüyor
|
|
210
209
|
(`RefreshPageCacheWhenTranslationChangedCommand`), okuma yolu cache-aside olduğu için bir
|
|
211
210
|
sonraki `page_runtime_get` taze değeri kurar. Yazmadan hemen sonra okuyabilirsin.
|
|
212
|
-
- Mobil
|
|
211
|
+
- Mobil runtime (`apps/mobile`) bu özelliği henüz beslemiyor — yalnız web.
|
|
213
212
|
|
|
214
213
|
## Backend doğrulama sınırları (TR-001)
|
|
215
214
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"hash": "
|
|
3
|
-
"generatedAt": "2026-09-
|
|
2
|
+
"hash": "f37265d598ea468deb2157165891629c2e88c7fd2238e82ec60cda7f58f7de4c",
|
|
3
|
+
"generatedAt": "2026-09-18T12:57:15.416Z",
|
|
4
4
|
"types": 186,
|
|
5
5
|
"files": 108,
|
|
6
6
|
"note": "Şemaları üreten backend kaynaklarının parmak izi. Elle düzenlemeyin: 'npm run generate-schemas' yazar, 'npm run schema:check' denetler.",
|
|
@@ -95,6 +95,20 @@
|
|
|
95
95
|
"$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.Dependencies.DependencyNode"
|
|
96
96
|
},
|
|
97
97
|
"nullable": true
|
|
98
|
+
},
|
|
99
|
+
"bindings": {
|
|
100
|
+
"type": "array",
|
|
101
|
+
"items": {
|
|
102
|
+
"$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.Dependencies.DependencyNode"
|
|
103
|
+
},
|
|
104
|
+
"nullable": true
|
|
105
|
+
},
|
|
106
|
+
"functions": {
|
|
107
|
+
"type": "array",
|
|
108
|
+
"items": {
|
|
109
|
+
"$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.Dependencies.DependencyNode"
|
|
110
|
+
},
|
|
111
|
+
"nullable": true
|
|
98
112
|
}
|
|
99
113
|
},
|
|
100
114
|
"additionalProperties": false
|
|
@@ -189,6 +203,10 @@
|
|
|
189
203
|
},
|
|
190
204
|
"stepKind": {
|
|
191
205
|
"$ref": "#/components/schemas/NgApps.Domain.Contexts.Studio.Flows.StepKind"
|
|
206
|
+
},
|
|
207
|
+
"propertyName": {
|
|
208
|
+
"type": "string",
|
|
209
|
+
"nullable": true
|
|
192
210
|
}
|
|
193
211
|
},
|
|
194
212
|
"additionalProperties": false
|
package/dist/server.js
CHANGED
|
@@ -39,7 +39,6 @@ import { registerMergeTools } from "./tools/merges.js";
|
|
|
39
39
|
import { registerRevisionTools } from "./tools/revisions.js";
|
|
40
40
|
import { registerActivityTools } from "./tools/activities.js";
|
|
41
41
|
import { registerDtoTools } from "./tools/dtos.js";
|
|
42
|
-
import { registerMobileTools } from "./tools/mobile.js";
|
|
43
42
|
const moduleRegistrations = {
|
|
44
43
|
platform: registerPlatformTools,
|
|
45
44
|
project: registerProjectTools,
|
|
@@ -81,7 +80,6 @@ const moduleRegistrations = {
|
|
|
81
80
|
merge: registerMergeTools,
|
|
82
81
|
activity: registerActivityTools,
|
|
83
82
|
revision: registerRevisionTools,
|
|
84
|
-
mobile: registerMobileTools,
|
|
85
83
|
};
|
|
86
84
|
export function createGatewayServer(platform) {
|
|
87
85
|
const server = rejectUnknownArguments(instrumentServer(new McpServer({ name: "ngapps", version: "0.1.0" }), platform.config));
|
|
@@ -1,44 +1,6 @@
|
|
|
1
1
|
import { guid, pagingParams, readOnly, writes, updates, destructive } from './common.js';
|
|
2
2
|
import { handle } from '../platform/responses.js';
|
|
3
|
-
import { forgetApplication, readApplicationPlatform, resolveApplication } from '../knowledge/platform/resolve.js';
|
|
4
|
-
import { mobileTabsProblems, readMobileTabs } from '../knowledge/platform/mobileTabs.js';
|
|
5
|
-
import { findingLine } from '../knowledge/platform/profile.js';
|
|
6
3
|
import { z } from 'zod';
|
|
7
|
-
/**
|
|
8
|
-
* MOB-007 (sekme ayarı) — `properties.mobile.tabs` yazan mobil uygulama çağrısının denetimi. Yazım
|
|
9
|
-
* platforma YİNE gider (D3; backend `properties`'i doğrulamaz): bulgu `platformWarnings`'e düşer.
|
|
10
|
-
* Sayfa ve widget listesi okunamazsa o denetimler atlanır, biçim denetimi yine koşar.
|
|
11
|
-
*/
|
|
12
|
-
export async function mobileTabsWarnings(platform, applicationId, projectSlug, homepageId, properties) {
|
|
13
|
-
const tabs = readMobileTabs(properties);
|
|
14
|
-
if (tabs === undefined)
|
|
15
|
-
return [];
|
|
16
|
-
const pages = applicationId && projectSlug
|
|
17
|
-
? await platform.tenant('GET', projectSlug, `/pages/${applicationId}`, { query: { pageIndex: 0, pageLength: 200 } })
|
|
18
|
-
.then(response => (response?.data ?? []).map(page => ({ id: String(page.id ?? '') })))
|
|
19
|
-
.catch(() => undefined)
|
|
20
|
-
: undefined;
|
|
21
|
-
const widgetIds = applicationId && projectSlug
|
|
22
|
-
? await platform.tenant('GET', projectSlug, `/components/${applicationId}`, { query: { pageIndex: 0, pageLength: 999 } })
|
|
23
|
-
.then(response => new Set((response?.data ?? []).filter(entry => entry.kind === 'widget').map(entry => String(entry.id ?? ''))))
|
|
24
|
-
.catch(() => undefined)
|
|
25
|
-
: undefined;
|
|
26
|
-
return mobileTabsProblems(tabs, {
|
|
27
|
-
...(pages ? { pages } : {}),
|
|
28
|
-
...(homepageId ? { homepageId } : {}),
|
|
29
|
-
...(widgetIds ? { widgetIds } : {})
|
|
30
|
-
}).map(message => findingLine({
|
|
31
|
-
code: 'MOB-007',
|
|
32
|
-
severity: 'warn',
|
|
33
|
-
message,
|
|
34
|
-
guide: "platform_guide('mobile') §Gezinme"
|
|
35
|
-
}));
|
|
36
|
-
}
|
|
37
|
-
function withPlatformWarnings(response, warnings) {
|
|
38
|
-
if (warnings.length === 0 || !response || typeof response !== 'object' || Array.isArray(response))
|
|
39
|
-
return response;
|
|
40
|
-
return { ...response, platformWarnings: warnings };
|
|
41
|
-
}
|
|
42
4
|
export function registerApplicationTools(server, platform) {
|
|
43
5
|
const config = platform.config;
|
|
44
6
|
server.registerTool('application_list', {
|
|
@@ -72,14 +34,7 @@ export function registerApplicationTools(server, platform) {
|
|
|
72
34
|
notFoundPageId: guid.optional()
|
|
73
35
|
},
|
|
74
36
|
annotations: writes
|
|
75
|
-
}, handle(config,
|
|
76
|
-
const warnings = readApplicationPlatform(body.type) === 'mobile'
|
|
77
|
-
? await mobileTabsWarnings(platform, undefined, undefined, undefined, body.properties)
|
|
78
|
-
: [];
|
|
79
|
-
const response = await platform.org('POST', `/applications/${projectId}`, { body });
|
|
80
|
-
forgetApplication(platform);
|
|
81
|
-
return withPlatformWarnings(response, warnings);
|
|
82
|
-
}));
|
|
37
|
+
}, handle(config, ({ projectId, ...body }) => platform.org('POST', `/applications/${projectId}`, { body })));
|
|
83
38
|
server.registerTool('application_update', {
|
|
84
39
|
title: 'Application güncelle',
|
|
85
40
|
description: 'Application bilgilerini günceller; homepageId zorunludur (mevcut değeri application_get ile alın).',
|
|
@@ -94,23 +49,11 @@ export function registerApplicationTools(server, platform) {
|
|
|
94
49
|
notFoundPageId: guid.optional()
|
|
95
50
|
},
|
|
96
51
|
annotations: updates
|
|
97
|
-
}, handle(config,
|
|
98
|
-
const current = await resolveApplication(platform, id);
|
|
99
|
-
const warnings = current?.platform === 'mobile'
|
|
100
|
-
? await mobileTabsWarnings(platform, id, current.projectSlug, body.homepageId, body.properties)
|
|
101
|
-
: [];
|
|
102
|
-
const response = await platform.org('PUT', `/applications/${id}`, { body });
|
|
103
|
-
forgetApplication(platform, id);
|
|
104
|
-
return withPlatformWarnings(response, warnings);
|
|
105
|
-
}));
|
|
52
|
+
}, handle(config, ({ id, ...body }) => platform.org('PUT', `/applications/${id}`, { body })));
|
|
106
53
|
server.registerTool('application_delete', {
|
|
107
54
|
title: 'Application sil',
|
|
108
55
|
description: 'Application\'ı kalıcı olarak siler.',
|
|
109
56
|
inputSchema: { id: guid },
|
|
110
57
|
annotations: destructive
|
|
111
|
-
}, handle(config,
|
|
112
|
-
const response = await platform.org('DELETE', `/applications/${args.id}`);
|
|
113
|
-
forgetApplication(platform, args.id);
|
|
114
|
-
return response;
|
|
115
|
-
}));
|
|
58
|
+
}, handle(config, args => platform.org('DELETE', `/applications/${args.id}`)));
|
|
116
59
|
}
|
package/dist/tools/components.js
CHANGED
|
@@ -1,40 +1,25 @@
|
|
|
1
1
|
import { guid, projectParam, environmentParam, readOnly, writes, updates, destructive } from './common.js';
|
|
2
|
-
import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote,
|
|
2
|
+
import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote, withNormalization } from '../knowledge/normalize.js';
|
|
3
3
|
import { eventContractsFor, eventPayloadNote } from '../knowledge/componentEvents.js';
|
|
4
4
|
import { componentPresetDefaults, readProjectTheme } from '../knowledge/themeSchema.js';
|
|
5
5
|
import { knowledgeFor, knowledgeNote, APPEARANCE_TOKEN_SETS, STATE_FLAG_NOTES, INTERNAL_ROLES_BY_TYPE } from '../knowledge/componentCatalog.js';
|
|
6
|
-
import { MOBILE_STATE_FLAG_NOTES, mobileComponentKnowledge } from '../knowledge/mobileComponentCatalog.js';
|
|
7
|
-
import { mobileComponentEventContracts } from '../knowledge/mobileComponentEvents.js';
|
|
8
6
|
import { componentUpdateBody, fetchHost, schemaParam, unwrap } from './screens.js';
|
|
9
7
|
import { PlatformApiError } from '../platform/errors.js';
|
|
10
8
|
import { handle } from '../platform/responses.js';
|
|
11
|
-
import { applicationTypeField, resolveProfile } from '../knowledge/platform/resolve.js';
|
|
12
|
-
import { mobileComponentNotes } from '../knowledge/platform/mobileRules.js';
|
|
13
9
|
import { z } from 'zod';
|
|
14
|
-
const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform
|
|
10
|
+
const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform; varsayılan web');
|
|
15
11
|
const kindParam = z.enum(['component', 'widget']).optional()
|
|
16
12
|
.describe("component: sayfaya konan tekil eleman. widget: kendi şeması olan kapsayıcı (container/modal/drawer)");
|
|
17
13
|
const widgetTypeParam = z.enum(['container', 'modal', 'drawer']).optional()
|
|
18
14
|
.describe("kind:'widget' iken zorunlu");
|
|
19
|
-
/**
|
|
20
|
-
* Uç `type` verilmezse WEB kataloğunu döner (`GetComponentsQuery` `Type ?? Web`); mobil uygulamanın
|
|
21
|
-
* paleti, doğrulayıcısı ve widget'ları `type=mobile` satırlarıdır. Profil mobil derse sorgu tipi
|
|
22
|
-
* taşır; web'de sorgu profil öncesiyle aynıdır (G1 kilidi).
|
|
23
|
-
*/
|
|
24
15
|
async function listComponents(platform, project, environment, applicationId, scope) {
|
|
25
16
|
const path = scope === 'all' ? `/components/${applicationId}/all` : `/components/${applicationId}`;
|
|
26
|
-
const catalogType = scope === 'all' ? 'web' : (await resolveProfile(platform, applicationId)).profile.catalogType;
|
|
27
17
|
const response = await platform.tenant('GET', project, path, {
|
|
28
18
|
environment,
|
|
29
|
-
query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999
|
|
19
|
+
query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999 }
|
|
30
20
|
});
|
|
31
21
|
return response?.data ?? [];
|
|
32
22
|
}
|
|
33
|
-
/** Uygulamanın kayıtlı bileşen slug'ları (mobil profilin MOB-003 denetimi). */
|
|
34
|
-
export async function fetchCatalogSlugs(platform, project, environment, applicationId) {
|
|
35
|
-
const components = await listComponents(platform, project, environment, applicationId);
|
|
36
|
-
return new Set(components.map(component => String(component.slug ?? '')).filter(slug => slug.length > 0));
|
|
37
|
-
}
|
|
38
23
|
/**
|
|
39
24
|
* Yerleşim normalizasyonlarının ikisi de aynı katalog listesinden beslenir; tek okumada
|
|
40
25
|
* çıkarılır ki yazma yolları fazladan istek atmasın. Uygulamanın kendi sözlüğü okunur
|
|
@@ -53,17 +38,12 @@ export async function fetchComponentLayoutRules(platform, project, environment,
|
|
|
53
38
|
export function componentLayoutRules(components) {
|
|
54
39
|
const maxSizes = new Map();
|
|
55
40
|
const autoHeights = new Map();
|
|
56
|
-
const droppable = new Map();
|
|
57
41
|
for (const component of components) {
|
|
58
42
|
const slug = typeof component.slug === 'string' ? component.slug : undefined;
|
|
59
43
|
if (!slug)
|
|
60
44
|
continue;
|
|
61
45
|
if (typeof component.isDefaultAutoHeight === 'boolean')
|
|
62
46
|
autoHeights.set(slug, component.isDefaultAutoHeight);
|
|
63
|
-
// Kap bilgisi sözlükten gelir; düğümün `states.isDroppable`ı onu izler (Studio paleti de
|
|
64
|
-
// aynı alanı katalogdan yazar). `true` gören tip kap sayılır.
|
|
65
|
-
if (typeof component.isDroppable === 'boolean')
|
|
66
|
-
droppable.set(slug, component.isDroppable);
|
|
67
47
|
const blocks = (component.definition ?? {}).blocks;
|
|
68
48
|
if (!Array.isArray(blocks))
|
|
69
49
|
continue;
|
|
@@ -78,7 +58,7 @@ export function componentLayoutRules(components) {
|
|
|
78
58
|
});
|
|
79
59
|
}
|
|
80
60
|
}
|
|
81
|
-
return { maxSizes, autoHeights
|
|
61
|
+
return { maxSizes, autoHeights };
|
|
82
62
|
}
|
|
83
63
|
/**
|
|
84
64
|
* Katalog okuması başarısız olsa da yazma isteği gitmeli, ama iki normalizasyonun düşüş davranışı
|
|
@@ -89,21 +69,14 @@ export function componentLayoutRules(components) {
|
|
|
89
69
|
* varsayılanını (`fixed`, `DesignComponentManagementSchema.cs:24`) kabul etmek demektir; en fazla
|
|
90
70
|
* sekiz tipte (auth-layout/html/image/layout/qrcode/table/text-editor/video) fazladan yükseklik
|
|
91
71
|
* üretir, atlamak ise her tipte içerik kırpar.
|
|
92
|
-
* - `states.isDroppable` atlanır — katalog okunamadığında hangi tipin kap olduğu bilinmez ve
|
|
93
|
-
* uydurulmaz; düğüm bugünkü hâliyle yazılır.
|
|
94
72
|
*/
|
|
95
73
|
export async function applyCatalogLayoutRules(platform, project, environment, applicationId, nodes) {
|
|
96
74
|
try {
|
|
97
75
|
const rules = await fetchComponentLayoutRules(platform, project, environment, applicationId);
|
|
98
|
-
return {
|
|
99
|
-
clamped: clampBlockSizes(nodes, rules.maxSizes),
|
|
100
|
-
heights: normalizeHeightTypes(nodes, rules.autoHeights),
|
|
101
|
-
sizes: normalizeSizeStrings(nodes),
|
|
102
|
-
states: normalizeDroppableStates(nodes, rules.droppable)
|
|
103
|
-
};
|
|
76
|
+
return { clamped: clampBlockSizes(nodes, rules.maxSizes), heights: normalizeHeightTypes(nodes, rules.autoHeights), sizes: normalizeSizeStrings(nodes) };
|
|
104
77
|
}
|
|
105
78
|
catch {
|
|
106
|
-
return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes)
|
|
79
|
+
return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes) };
|
|
107
80
|
}
|
|
108
81
|
}
|
|
109
82
|
/**
|
|
@@ -143,7 +116,6 @@ export function registerComponentTools(server, platform) {
|
|
|
143
116
|
}, handle(config, async ({ project, environment, applicationId, scope, includeHidden }) => {
|
|
144
117
|
const components = await listComponents(platform, project, environment, applicationId, scope);
|
|
145
118
|
return {
|
|
146
|
-
...applicationTypeField(await resolveProfile(platform, applicationId)),
|
|
147
119
|
components: components
|
|
148
120
|
.filter(component => includeHidden === true || component.isHide !== true)
|
|
149
121
|
.map(component => ({
|
|
@@ -189,15 +161,6 @@ export function registerComponentTools(server, platform) {
|
|
|
189
161
|
: [];
|
|
190
162
|
const componentSlug = typeof component.slug === 'string' ? component.slug : undefined;
|
|
191
163
|
const knowledge = knowledgeFor(componentSlug);
|
|
192
|
-
// Mobil uygulamada kayıt mobil kataloğun satırıdır (`listComponents` type=mobile); davranış
|
|
193
|
-
// notları web runtime'ından gelir (`knowledge` — mobil şema web sınıfını genişletir), bileşenin
|
|
194
|
-
// mobil farkları `mobileKnowledge`'ta, bütün mobil bileşenlere geçen notlar `mobileNotes`'ta (G4).
|
|
195
|
-
// Web ikizi olmayan bileşende (`app-bar`, `tooltip`…) bilgi yalnız `mobileKnowledge`'tadır; olay
|
|
196
|
-
// yükleri de önce mobil sözlükten okunur (`mobileComponentEvents.ts`).
|
|
197
|
-
const mobile = (await resolveProfile(platform, applicationId)).profile.platform === 'mobile';
|
|
198
|
-
const mobileKnowledge = mobile && componentSlug !== undefined && Object.hasOwn(mobileComponentKnowledge, componentSlug)
|
|
199
|
-
? mobileComponentKnowledge[componentSlug]
|
|
200
|
-
: undefined;
|
|
201
164
|
// S-3 — `defaults` HAM katalogdur; Studio'da bırakılan düğüm ise temanın bileşen preseti
|
|
202
165
|
// kaplanmış katalogdan kurulur (`withThemeComponentDefaults`). Tema okunamazsa (uç düşer,
|
|
203
166
|
// yetki yoksa) alan yanıta HİÇ girmez: uydurulmuş bir varsayılan yanlış bilgidir.
|
|
@@ -214,7 +177,7 @@ export function registerComponentTools(server, platform) {
|
|
|
214
177
|
isDroppable: component.isDroppable,
|
|
215
178
|
props: definition.props,
|
|
216
179
|
defaults: definition.defaults,
|
|
217
|
-
events: eventContractsFor(componentSlug, eventNames
|
|
180
|
+
events: eventContractsFor(componentSlug, eventNames),
|
|
218
181
|
eventPayloadNote,
|
|
219
182
|
...(knowledge
|
|
220
183
|
? {
|
|
@@ -225,7 +188,7 @@ export function registerComponentTools(server, platform) {
|
|
|
225
188
|
},
|
|
226
189
|
...(knowledge.guide ? { guide: knowledge.guide } : {})
|
|
227
190
|
}
|
|
228
|
-
:
|
|
191
|
+
: { knowledgeNote }),
|
|
229
192
|
...(componentSlug && INTERNAL_ROLES_BY_TYPE[componentSlug]
|
|
230
193
|
? {
|
|
231
194
|
internalRoles: INTERNAL_ROLES_BY_TYPE[componentSlug],
|
|
@@ -233,9 +196,8 @@ export function registerComponentTools(server, platform) {
|
|
|
233
196
|
}
|
|
234
197
|
: {}),
|
|
235
198
|
...(themeDefaults ? { themeDefaults } : {}),
|
|
236
|
-
...(mobile ? { platform: 'mobile', ...(mobileKnowledge ? { mobileKnowledge } : {}), mobileNotes: mobileComponentNotes(componentSlug) } : {}),
|
|
237
199
|
appearanceValues: APPEARANCE_TOKEN_SETS,
|
|
238
|
-
stateFlags:
|
|
200
|
+
stateFlags: STATE_FLAG_NOTES,
|
|
239
201
|
validations: definition.validations,
|
|
240
202
|
sizes: definition.blocks
|
|
241
203
|
};
|
|
@@ -272,13 +234,11 @@ export function registerComponentTools(server, platform) {
|
|
|
272
234
|
const catalog = (body.schema ?? []).length > 0
|
|
273
235
|
? await applyCatalogLayoutRules(platform, project, environment, applicationId, body.schema)
|
|
274
236
|
: { clamped: [], heights: [], sizes: [] };
|
|
275
|
-
// Mobil uygulamanın widget'ı mobil katalog satırıdır; tip verilmezse uygulamanın tipi.
|
|
276
|
-
const defaultType = body.type ?? (await resolveProfile(platform, applicationId)).profile.catalogType;
|
|
277
237
|
return platform.tenant('POST', project, `/components/${applicationId}`, {
|
|
278
238
|
environment,
|
|
279
239
|
body: {
|
|
280
240
|
kind: 'component',
|
|
281
|
-
type:
|
|
241
|
+
type: 'web',
|
|
282
242
|
categories: [],
|
|
283
243
|
definition: {},
|
|
284
244
|
schema: [],
|