تعريف العرض المبني على البيانات
معرّف المخطط: model-driven-view@2
المخطط القابل للقراءة آليًا: model-driven-view.schema.json
الإصدار المستبدَل: يبقى model-driven-view@1
(model-driven-view-v1.schema.json) منشورًا
ومسجَّلًا، كي يظل الحل المنشور سلفًا مقابله يُتحقق منه مقابل المخطط الذي أُلِّف عليه.
فالإصدار الثاني لا يضيف إلا خصائص اختيارية — وجدول «الشكل» أدناه هو القائمة الحالية — ومن ثم
فكل تعريف صالح في الإصدار الأول صالح في الإصدار الثاني أيضًا ولا حاجة إلى إعادة كتابة أي شيء.
التمثيل المرجعي لعرض في Model-Driven Apps (القسم 6.7) — و هو قائمة جدولية بالسجلات مع أعمدتها وتصفياتها وترتيباتها.
الشكل
| الحقل | النوع | مطلوب | ملاحظات |
|---|---|---|---|
logicalName | string | نعم | مسبوق ببادئة الناشر، بصيغة snake_case صغيرة. |
displayName | string | نعم | اسم العرض المقروء. |
entity | string | نعم | الاسم المنطقي للجدول المالك. |
description | string | لا | السطر الظاهر تحت العنوان في شريط عنوان العرض. |
icon | string | لا | الأيقونة الظاهرة على شريط عنوان العرض. |
viewType | string | لا | الغرض من العرض: Public (الافتراضي)، Lookup، QuickFind، Associated، QuickView، Card، SeedData. |
seedDataKind | string | في عرض SeedData | مطلوب في عرض SeedData ومرفوض في أي عرض آخر: Configuration (صفوف يحتاجها الحل ليعمل؛ يجلبها الاستيراد دائماً، حتى في Production) أو Demonstration (صفوف نموذجية؛ لا تُستورد إلا بتحديد تضمين بيانات العرض التوضيحي، ولا تذهب أبداً إلى Production). تنتقل إلى الحزمة بوصفها kind في مستند البيانات الأولية. |
columns | array | نعم | الأسماء المنطقية للحقول المعروضة بوصفها أعمدة. |
filters | array | لا | بنود تصفية مسطّحة (مربوطة بـ AND): field وoperator و(لمعاملات القيم) value. |
filterGroup | object | لا | شجرة تصفية هرمية AND/OR (على نمط البحث المتقدم)، تُربط بـ AND مع filters. |
sorts | array | لا | بنود الترتيب: field وdescending. |
actions | array | لا | إجراءات شريط أوامر قابلة للتصميم. |
hierarchy | object | لا | موجودة حين يُرسم العرض شجرةً لا شبكة. |
calendar | object | لا | موجود عندما يُرسم العرض على هيئة تقويم بدلًا من شبكة. لا يجتمع أبدًا مع hierarchy. |
columnProperties | array | لا | كيف تُعرَض الأعمدة فرادى — العنوان، العرض، التنسيق، المحاذاة، العنصر. متفرّقة. |
commandOverrides | array | لا | ما يغيّره هذا العرض في الأوامر التي تملكها المنصّة. |
commandOrder | array | لا | شريط واحد، ترتيب واحد: الأوامر المدمجة وأوامر الصانع متشابكة، بالمعرّف. |
rowSelection | boolean | لا | هل تحمل الصفوف مربّع اختيار. true افتراضًا. |
المعاملات: Equals، NotEquals، Contains، GreaterThan، LessThan، IsNull،
IsNotNull. ويجب أن يكون كل حقل مشار إليه (في الأعمدة والتصفيات وشروط مجموعة التصفية
والترتيبات) موجودًا على الجدول.
viewType
نوع العرض يحدد أي واجهة تقرؤه. ويمكن للجدول الواحد أن يحمل عرضًا افتراضيًا من كل نوع في الوقت نفسه، لأنها تجيب عن أسئلة مختلفة:
| القيمة | الغرض منها |
|---|---|
Public | صفحة القائمة العادية للجدول. وهو الافتراضي، وهو ما يكون عليه أي تعريف بلا viewType. |
Lookup | الأعمدة الظاهرة داخل لوحة نتائج حقل البحث — وعادةً من عمودين إلى أربعة. |
QuickFind | أعمدة البحث: أي الأعمدة التي يطابقها البحث المكتوب. فأعمدة columns فيه هي المجموعة التي يجري البحث فيها؛ ولا تُقرأ تصفياته ولا ترتيباته. |
SeedData | الصفوف والأعمدة التي تسافر مع الحل (PF22). لا يُعرض أبدًا: يشغّله تصدير الحل — تحدد filters فيه الصفوف وcolumns الحقول — ويحزم النتيجة وثيقةَ seed-data@1 يدرجها الاستيراد أو يحدّثها بحسب المعرِّف. الجدول الذي له عدة عروض من هذا النوع يستخدم الافتراضي منها، وإلا فالأول بترتيب الاسم المنطقي. |
Associated | الشبكة الفرعية للسجلات المرتبطة. محجوز — ولا شيء يعرضه بعد. |
وحقل البحث الذي لا يسمّي عرضًا يحلّ عرضًا تلقائيًا: العرض Lookup الافتراضي للجدول
الهدف، وإلا فعرضه Public الافتراضي مقتطعًا عند أعمدته الثلاثة الأولى، وإلا فالحقل
الأساسي للجدول وحده. والبحث الذي لا يوجد له عرض QuickFind يطابق الحقل الأساسي فقط.
ويجب أن تكون أعمدة البحث حقولًا نصية، لأن المطابقة من نوع "يحتوي" غير حساسة لحالة
الأحرف.
calendar (عرض يُرسم على هيئة تقويم)
العرض الذي يحمل بلوك calendar يضع سجلاته على ورقة يوم أو أسبوع أو شهر وفق حقلَي تاريخ من حقوله
هو، لا في شبكة. غيابه يعني الشبكة، تمامًا كما مع hierarchy، فيبقى كل عرض مخزَّن صا لحًا. ويُرفض العرض
الذي يحمل البلوكين معًا: العرض يُرسم بطريقة واحدة.
هو ربط، لا نموذج بيانات. لا يوجد جدول حجوزات ولا نوع موعد في المنصّة: أي جدول عليه تاريخ يمكن وضعه على تقويم، وأي من تواريخه يعني «يبدأ» أمرٌ يقرّره صانع التطبيق.
| الحقل | النوع | مطلوب | ملاحظات |
|---|---|---|---|
start | string | نعم | حقل التاريخ والوقت الذي يوضع عنده المكعّب. الدور المطلوب الوحيد: سجل بلا بداية لا يمكن وضعه على ورقة أصلًا، فلا شيء يُرجع إليه. ويُسمح بحقل نطامي — created_at_utc يرتّب السجلات وفق وقت وصولها. |
end | string | لا | حقل التاريخ والوقت الذي ينتهي عنده المكعّب. غيابه لجدول يسجّل لحظة لا مدة، فيصير طول كل مكعّب defaultDurationMinutes — لا صفرًا، لأن مكعّبًا بلا ارتفاع لا يمكن النقر عليه. |
title | string | لا | الحقل الذي يُقرأ منه السطر الأول للمكعّب. غيابه يعني الحقل الأساسي للجدول، وهو ما تعرضه الشبكة ولوحة البحث ومسار التنقل أصلًا. |
category | string | لا | حقل قائمة اختيار أو حالة أو سبب تُلوّن خياراته المكعّبات وتملأ مفتاح الألوان. |
bookedFor | string | لا | الحقل الذي يسمّي صاحب الفترة، ويظهر بهدوء تحت العنوان. أي نوع: الربط يتحوّل إلى اسم السجل المقصود. |
note | string | لا | الحقل الذي يظهر على مكعّب يتّسع لسطر ثالث، وفي تلميحه إن لم يتّسع. |
defaultScale | string | لا | الورقة التي يُفتح عليها العرض: Day أو Week (الافتراضي) أو Month. |
startHour | integer | لا | أول ساعة تعرضها ورقتا اليوم والأسبوع، 0–23. الافتراضي 0. |
endHour | integer | لا | الساعة التي تنتهي عندها، 1–24، وأكبر من startHour. الافتراضي 24. |
defaultDurationMinutes | integer | لا | طول الفترة حين ينقر القارئ مكانًا فارغًا — وهو ما يصل به السجل الجديد — وارتفاع كل مكعّب في عرض بلا end. واحد على الأقل؛ الافتراضي 60. |
🔴 يجب أن يكون start وend حقلَي تاريخ ووقت، وأن يحمل category ألوانًا. كلاهما مرفوض عند الحفظ،
لأن كليهما يفشل بصمت على الشاشة: start الذي يكون عمودًا نصيًا يرسم ورقة فارغة، تُقرأ «لا حجز هذا
الأسبوع» — وهي الخلاصة الوحيدة التي يتصرّف القارئ بناءً عليها ولا يستطيع التحقق منها. اللون يعيش على
خيارات قائمة الاختيار ن فسها، وهو ما يجعل «الامتحان كهرماني» يُقال مرة واحدة ويُقرأ في التقويم وخلية
الشبكة والرسم البياني معًا.
startHour وendHour هما الفرق بين ورقة حجز صالحة وأخرى تُفتح وثلثاها فارغ: عيادة تعمل من 8 إلى 19 لا
تريد ستة عشر سطرًا من منتصف الليل. وهما يحدّدان أين يُفتح العرض — يبقى للقارئ تبديل المقياس وتضييق
الساعات من رأس الورقة نفسها، لأن هذه النافذة نافذته لا نافذة الصانع.
لا يوجد دور resource عمدًا. الأوراق ترتّب الأيام في أعمدة، فحقل يسمّي العمود الذي ينتمي إليه المكعّب
سيكون ربطًا يصنعه الصانع ثم يراه بلا أثر. يأتي مع المحور الذي يرسمه.
hierarchy (عرض يُرسم شجرةً)
العرض الذي يحمل كتلة hierarchy يرسم سجلّاته متداخلةً عبر بحث (Lookup) — مخطّطًا تنظيميًّا مع
الأشخاص في كل وحدة، شجرة تصنيفات، قائمة مكوّنات — بدلًا من شبكة. وغيابها هو الشبكة التي كان عليها كل
عرض دائمًا، ولهذا يبقى كل عرض مخزَّن صالحًا.
وما الشجرة لأجله هو التنقّل: تُجلب الصفوف نافذةً بعد نافذة، فيُفتح مخطّط فيه خمسون ألف شخص دون تحميل أيٍّ منهم.
| الحقل | النوع | مطلوب | ملاحظات |
|---|---|---|---|
nodeTypes | array | نعم | كل نوع عقدة تستطيع الشجرة رسمه. واحد على الأقل. |
order | array | لا | ترتيب رسم المقاطع تحت عقدة واحدة، بمعرّف نوع العقدة. وغيابه يعني ترتيب الإعلان. |
rootPicker | boolean | لا | هل يستطيع القارئ تركيز الشجرة على عقدة واحدة — أن يفتح على مدينة بدل المؤسسة كلها. |
expandRoots | boolean | لا | هل ينفتح المستوى الأول عند التحميل. true افتراضًا. |
كل مُدخَل في nodeTypes:
| الحقل | النوع | مطلوب | ملاحظات |
|---|---|---|---|
id | string | نعم | اسم هذا النوع داخل الكتلة — unit، person. فريد هنا، وهو ما يشير إليه order وكل childOf.of. وقد يظهر الجدول نفسه مرّتين في مخطّط واحد، ولهذا هي كلمة الصانع لا اسم الجدول. |
entity | string | نعم | الجدول الذي هذه العقد سجلّات فيه. |
childOf | object | نعم | كيف يتعلّق هذا النوع تحت أبيه — انظر أدناه. |
label | string | لا | الحقل الذي قيمته سطر العقدة. وغيابه يعني الحقل الأساسي للجدول. |
secondary | string | لا | الحقل الذي يظهر بهدوء بعد التسمية. غيابه يعني الحقل الثانوي للجدول نفسه؛ والسلسلة الفارغة تعني لا شيء — فاسم الأب على وحدةٍ هو الصف الذي فوقها مباشرة، والمخطّط أحد المواضع التي يكون فيها السطر الثاني الافتراضي خاطئًا. |
icon | string | لا | الرمز على الصف. وغيابه يعني رمز الجدول نفسه. |
image | boolean | لا | هل يحمل الصف صورة السجل. |
detail | object | لا | ما يملأ اللوح بجانب المخطّط عند اختيار واحدة. وغيابه يعني النموذج الرئيسي للجدول. |
يأخذ childOf حقل field — وهو البحث على جدول هذا النوع الذي يحمل سجل الأب — وof اختياريًّا،
أي نوع العقدة الذي يتعلّق تحته، بالمعرّف.
🔴 نوع عقدة واحد بالضبط يترك of. ذاك هو جدول الشجرة نفسه متداخلًا تحت ذاته، وسجلّاته ذات الأب
الفارغ هي أعلى مستوى في المخطّط؛ وكل نوع آخر يسمّي ما يتعلّق تحته. والعقد غير المتجانسة هي الحالة
العامة لا إضافة ملحقة: الوحدات، ثم الأشخاص فيها هي الآلية نفسها التي في محافظة ← مدينة ← فرع
مُنمذجةً بثلاثة جداول.
والبحث الذي يسمّيه childOf.field يجب أن يستهدف ج دول نوع الأب — وجدوله هو نفسه لنوع الجذر. وبحثٌ
يشير إلى غير ذلك لا يصف تداخلًا، ويُرفض عند الحفظ بدل أن يرسم مستوًى لا شيء تحته.
يأخذ detail قيمة kind: إما Form (نموذج الجدول نفسه، يُحفظ عبر مسار كتابة نموذج السجل)، أو
Card (عرض بطاقة مُخطَّط ليُقرأ لا ليُكتب فيه، وهو عادةً ما يريده شخص تحت وحدة)، أو None (لنوع ليس
إلا بنية)، مع name اختياري لأي نموذج أو عرض بطاقة.
columnProperties (كيف يُعرَض عمود)
قائمة متفرّقة: لا تظهر فيها إلا الأعمدة التي هيّأها الصانع، والعمود الذي لا مُدخَل له يُرسم من
بيانات حقله وحدها. وهي تقع بجانب columns بدل تحويل تلك إلى قائمة كائنات، فيبقى كل تعريف من الإصدار
الأول صالحًا، ويبقى كل قارئ لا يحتاج إلا معرفة أي الأعمدة في العرض دون مساس.
| الحقل | النوع | مطلوب | ملاحظات |
|---|---|---|---|
field | string | نعم | العمود الذي يهيّئه هذا المُدخَل. ويجب أن يكون أحد columns العرض. |
label | string | null | لا | استبدال للعنوان. وغيابه يعني اسم عرض الحقل. |
width | integer | null | لا | العرض بالبكسل، من ٤٠ إلى ١٢٠٠. وغيابه يترك العمود يقيس نفسه. |
format | string | null | لا | تنسيق القيمة. ولعمود تاريخ ووقت، مجموعة الرموز نفسها التي تقبلها عناصر التاريخ في النموذج (yyyy، yy، MM، dd، HH، mm، ss) — مفردات تنسيق واحدة في المنتج كله. |
align | string | null | لا | start أو center أو end. منطقية لا يمين/يسار، فتتبع اتجاه القراءة (§6.13.6). |
controlType | string | null | لا | العنصر الذي يُرسم به العمود — رمز مفتاح لقيمة منطقية، تاريخ فارسي لتاريخ. |
يأخذ controlType: Text وTextArea وCheck وToggle وDate وDateTime وTime
وPersianDate وPersianDateTime وPersianTime وLookup وPolymorphicLookup وDropdown أو
Label. وغيابه يرث افتراضي الحقل نفسه ثم افتراضي نوع البيانات.
🔴 يُرسم دائمًا للقراءة فقط. فالشبكة لا تحرير فيها داخل الصف، فالمفتاح هنا يُظهر الحالة ولا
يستقبل نقرة. وهو أيضًا الطريق الوحيد لأن ي عرض عمود تقويمًا جلاليًّا في مستأجر ميلادي، لأن format
نمطٌ لا تقويم مرفق به.
commandOverrides (تغيير أمر تملكه المنصّة)
ما يغيّره هذا العرض في الأوامر المدمجة — جديد، تحرير، حذف، تحديث، حفظ، حفظ وإغلاق، تثبيت. وغيابها لا يغيّر شيئًا، وهو معنى كل عرض أُلِّف قبل وجود هذه الخاصية.
| الحقل | النوع | مطلوب | ملاحظات |
|---|---|---|---|
command | string | نعم | المعرّف الثابت للأمر الذي يُستبدَل. |
label | string | لا | يستبدل تسمية المنصّة. وغيابه يبقيها — بترجماتها، وهي ما يفقده استبدالٌ مكتوب بالضرورة. |
icon | string | لا | يستبدل رمز المنصّة. |
initiallyHidden | boolean | لا | هل يبدأ الأمر مخفيًّا. |
initiallyDisabled | boolean | لا | هل يبدأ الأمر معطَّلًا. |
🔴 مفتاحه معرّف الأمر الثابت، لا التسمية ولا الموضع. فالمعرّف اسم المن صّة نفسها ولا يتغيّر بتغيّر التسمية، فلا ينفصل الاستبدال عمّا يستبدله لحظة يحرّر أحدهم التسمية — ويمكن لأمر مدمج أن يُعاد تسميته أو يُتقاعد لاحقًا دون أن تحتاج كل وثيقة مخزَّنة إلى مصالحة، لأن استبدالًا يسمّي أمرًا لم يعد موجودًا يُتجاهل ببساطة.
🔴 للصانع أن يُخفي ويُعطّل، لا أن يُظهر أو يُفعّل. فالمشغّل يخفي «جديد» عمّن لا يستطيع الإنشاء ويعطّل «حذف» حين لا شيء مختار؛ واستبدالٌ يقدر على نقض ذلك يبني شريطًا يعرض ما سيرفضه الخادم.
و«ابتداءً» هي كل الكلمة. إنها الحالة التي يُفتح بها الشريط، لا شرطٌ دائم — فقاعدة عمل أو سكربت الأمر نفسه قد يُظهره بعد ذلك. أما أمر يجب ألّا يظهر أبدًا لأحدهم فليس هذا؛ ذاك إذن وصول، يُقرَّر على الخادم حيث لا يستطيع المتصفّح مجادلته.
commandOrder (شريط واحد، ترتيب واحد)
الأوامر المدمجة وأوامر الصانع، متشابكة كما رتّبها الصانع، بالمعرّف.
قائمة صريحة لا رتبة على كل أمر، لأن الرتبة يجب أن تُعاد كتابتها على كل الأوامر كلما تحرّك واحد، ولأن أمرين قد يحملان الرتبة نفسها — وهي عقدة يفكّها الراسم عندئذٍ على غير ما فكّها به المصمّم.
🔴 وكل ما لا تذكره هذه القائمة يبقى في موضعه الطبيعي، في النهاية. وهذا ما يُبقي القاعدة صالحة مع الزمن: أمرٌ مدمج يُضاف إلى المنصّة العام المقبل، أو أمرٌ تأتي به ترقية، يظهر ولا يختفي لأن ترتيبًا مخزَّنًا سبقه. والمعرّف الذي يسمّي شيئًا لم يعد موجودًا يُتخطّى.
rowSelection (هل تحمل الصفوف مربّع اختيار)
true افتراضًا، وهو معنى كل عرض أُلِّف قبل وجود هذه الخاصية: تحصل الشبكة على عنوان «اختيار الكل»
ومربّعات لكل صف، وهو ما يعمل عليه شريط الأوامر.
وfalse لعرضٍ لا يُفعل به إلا القراءة — قائمة لا يحذف منها أحد ولا يعيد إسناد شيء — حيث يعرض
مربّع الاختيار تحديدًا متعدّدًا لا فائدة منه لهذا السطح، ويكلّف عرض عمود.
filterGroup (AND/OR الهرمية)
الـ filterGroup عقدة تكرارية تجمع أعضاءها بواسطة connector:
| الحقل | النوع | مطلوب | ملاحظات |
|---|---|---|---|
connector | string | نعم | And (تطابق كل الأعضاء) أو Or (يطابق أي عضو). |
conditions | array | لا | الشروط الطرفية (field وoperator وvalue) في هذه المجموعة. |
groups | array | لا | مجموعات فرعية متداخلة (بالشكل نفسه)، لتداخل AND/OR بأي عمق. |
مثال
{
"logicalName": "par_invoice_active",
"displayName": "Active Invoices",
"entity": "par_invoice",
"viewType": "Public",
"columns": ["par_name", "par_total"],
"filters": [ { "field": "par_total", "operator": "GreaterThan", "value": 0 } ],
"filterGroup": {
"connector": "And",
"conditions": [ { "field": "par_name", "operator": "Contains", "value": "INV" } ],
"groups": [
{
"connector": "Or",
"conditions": [
{ "field": "par_total", "operator": "GreaterThan", "value": 1000 },
{ "field": "par_total", "operator": "IsNull" }
]
}
]
},
"sorts": [ { "field": "par_name", "descending": false } ]
}
مثال — عرض بحث
{
"logicalName": "par_contact_pick",
"displayName": "Contact Lookup",
"entity": "par_contact",
"viewType": "Lookup",
"columns": ["par_name", "par_email", "par_city"],
"sorts": [ { "field": "par_name", "descending": false } ]
}
مثال — عرض بحث سريع
لا يُقرأ سوى columns: فهي الأعمدة التي يطابقها البحث المكتوب.
{
"logicalName": "par_contact_find",
"displayName": "Contact Quick Find",
"entity": "par_contact",
"viewType": "QuickFind",
"columns": ["par_name", "par_email", "par_accountnumber"]
}