İzin modeli#
İzinler varsayılan olarak açıktır; kısıtlamaya bir bayrağı false yaparak katılırsınız.
interface Permissions {
drag: boolean; // kanvas ve katmanlarda taşıma
delete: boolean; // tekli/toplu silme ve kesme
duplicate: boolean; // çoğaltma ve yeni id ile yapıştırma
edit: boolean; // Inspector alanlarının düzenlenmesi
[key: string]: boolean; // host’a özel ek izinler
}Bir düğümün etkin izni katmanların birleşimidir; sonraki katman öncekini ezer:
varsayılan < config.permissions < component.permissions < component.resolvePermissions(props) < düğümün _locked kilidiconst editorConfig: StudioConfig = {
permissions: { delete: false }, // genel: hiçbir şey silinemez
components: {
Header: {
permissions: { drag: false }, // header taşınamaz
resolvePermissions: (props) => ({ edit: !props.locked }),
render: (p) => <header className={p.className} />,
},
Hero: {
permissions: { delete: true }, // Hero için silmeye yeniden izin ver
render: (p) => <section className={p.className} />,
},
},
};- Kısıtlar motor seviyesinde uygulanır: düğme gizlemekle kalmaz; klavye kısayolları (
⌘D,Delete), sağ tık menüsü ve pano işlemleri de aynı kurala uyar. edit: falseInspector alanlarını salt okunur yapar.- Delete izni olmayan düğümde kes işlemi düz kopyalamaya döner.
- Eksik anahtar ya da
resolvePermissions’ın fırlattığı hata izinleri sıkılaştırmaz; o katman bir alttakinden devralınır. Hatalı bir çözümleyici kullanıcıyı kilitlemez. - Katmanlar panelindeki kilit (
_locked) aynı izin sistemini kullanır. Kilitli düğüm seçilebilir kalır (kilidi açabilmek için).
Dinamik izinler#
resolvePermissions?: (props: any, ctx: { changed: Record<string, boolean>; lastProps: Record<string, any> | null }) => Partial<Permissions>;ctx.changed son çözümden beri değişen prop’ları, ctx.lastProps önceki anlık görüntüyü verir (ilk çalıştırmada null); yalnız ilgili alan değiştiğinde yeniden hesap yapmak için kullanın.
Veri migration’ı#
Bir bileşenin tip adı ya da prop şeması değiştiğinde önceden kaydedilmiş sayfalar eski şemada kalır. migrations, belge editörde yüklenirken ve TecofRender ile render edilirken otomatik uygulanır.
interface MigrationConfig {
version?: number; // hedef şema sürümü
renameComponents?: Record<string, string>; // { eskiTip: yeniTip }
transformProps?: Record<string, (props: any) => any>; // YENİ tip adına göre
migrate?: (doc: TecofDocument) => TecofDocument; // son, serbest geçiş
}const editorConfig: StudioConfig = {
components,
migrations: {
version: 3,
renameComponents: { OldHero: "Hero" },
transformProps: {
// Rename SONRASI tipe göre aranır: anahtar "Hero"
Hero: (props) => ({ ...props, eyebrow: props.eyebrow ?? "", title: props.headline ?? props.title }),
},
migrate: (doc) => doc,
},
};Çalışma sırası#
renameComponentsile her düğümüntype’ı değiştirilir.- Yeni tip adına göre
transformProps[type]çalışır; düğümid’si her zaman korunur. - Varsa tüm belgeye
migrate(doc)uygulanır. versiontanımlıysa hedef sürümroot.props._schemaVersion’a yazılır.
İdempotentlik#
version verildiyse, _schemaVersion’ı zaten o sürümde ya da üstünde olan belge dokunulmadan döner. version verilmezse geçiş her yüklemede çalışır; bu durumda transformProps ve migrate kendi başlarına idempotent olmalıdır. Bir dönüşüm hata fırlatırsa o düğüm/belge değişmeden bırakılır; tek bir hata sayfayı kilitlemez.