diff --git a/assets.go b/assets.go index b3ed90c1011a144565e9fc8f293473352ba6cba3..04eefe77f3c149c172a1f82c05428a1eadbb1eef 100644 --- a/assets.go +++ b/assets.go @@ -6,47 +6,42 @@ import ( "path/filepath" "git.perx.ru/perxis/perxis-go/pkg/errors" + "git.perx.ru/perxis/perxis-go/yaml" jsoniter "github.com/json-iterator/go" - "gopkg.in/yaml.v3" ) // Assets предоставляет методы для загрузки данных РёР· файловой системы type Assets[T any] struct { + FS fs.FS Constructor func() T } // NewAssets возвращает новый экземпляр загрузчика -func NewAssets[T any]() *Assets[T] { +func NewAssets[T any](fsys fs.FS) *Assets[T] { return &Assets[T]{ - Constructor: func() (t T) { return t }, + FS: fsys, + Constructor: func() (t T) { return t }, // РџРѕ умолчанию zero-value } } -type FromFSFunc[T any] func(fsys fs.FS) ([]T, error) -type FromFileFunc[T any] func(file fs.File) ([]T, error) - -func (a *Assets[T]) Funcs() (FromFSFunc[T], FromFileFunc[T]) { - return a.FromFS, a.FromFile -} - // WithConstructor устанавливает конструктор для создания новых экземпляров func (a *Assets[T]) WithConstructor(t func() T) *Assets[T] { a.Constructor = t return a } -// MustFrom возвращает РІСЃРµ записи РІ переданной файловой системе -func (a *Assets[T]) MustFrom(fsys fs.FS, path string) []T { - res, err := a.From(fsys, path) +// MustFrom возвращает РІСЃРµ записи РёР· переданного файла или директории +func (a *Assets[T]) MustFrom(path string) []T { + res, err := a.From(path) if err != nil { panic(err) } return res } -// MustOneFrom возвращает РѕРґРЅСѓ запись РёР· переданного файла -func (a *Assets[T]) MustOneFrom(fsys fs.FS, path string) T { - res, err := a.From(fsys, path) +// MustOneFrom возвращает РѕРґРЅСѓ запись РёР· переданного файла или директории +func (a *Assets[T]) MustOneFrom(path string) T { + res, err := a.From(path) if err != nil { panic(err) } @@ -59,9 +54,9 @@ func (a *Assets[T]) MustOneFrom(fsys fs.FS, path string) T { return res[0] } -// From возвращает записи РёР· переданного файла -func (a *Assets[T]) From(fsys fs.FS, path string) ([]T, error) { - f, err := fsys.Open(path) +// From возвращает записи РёР· переданного файла или директории +func (a *Assets[T]) From(path string) ([]T, error) { + f, err := a.FS.Open(path) if err != nil { return nil, err } @@ -74,13 +69,8 @@ func (a *Assets[T]) From(fsys fs.FS, path string) ([]T, error) { } if stat.IsDir() { - sub, err := fs.Sub(fsys, path) - if err != nil { - return nil, err - } - return a.FromFS(sub) + return a.FromDir(path) } - return a.FromFile(f) } @@ -107,10 +97,10 @@ func (a *Assets[T]) FromFile(file fs.File) ([]T, error) { return nil, errors.Errorf("file '%s' must be in JSON or YAML format", stat.Name()) } -// FromFS возвращает РІСЃРµ записи РІ переданной файловой системе -func (a *Assets[T]) FromFS(fsys fs.FS) (result []T, err error) { - if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, _ error) error { - file, err := fsys.Open(path) +// FromDir возвращает РІСЃРµ записи РёР· переданной папки рекурсивно +func (a *Assets[T]) FromDir(dir string) (result []T, err error) { + if err := fs.WalkDir(a.FS, dir, func(path string, d fs.DirEntry, _ error) error { + file, err := a.FS.Open(path) if err != nil { return err } @@ -128,8 +118,8 @@ func (a *Assets[T]) FromFS(fsys fs.FS) (result []T, err error) { } // FromJSON возвращает запись РёР· JSON -func (c *Assets[T]) FromJSON(r io.Reader) (T, error) { - entry := c.Constructor() +func (a *Assets[T]) FromJSON(r io.Reader) (T, error) { + entry := a.Constructor() data, err := io.ReadAll(r) if err != nil { return entry, err @@ -140,11 +130,11 @@ func (c *Assets[T]) FromJSON(r io.Reader) (T, error) { } // FromYAML возвращает записи РёР· YAML -func (c *Assets[T]) FromYAML(r io.Reader) (result []T, err error) { +func (a *Assets[T]) FromYAML(r io.Reader) (result []T, err error) { decoder := yaml.NewDecoder(r) for { var data interface{} - err = decoder.Decode(&data) + err = decoder.Decode(yaml.WithTagProcessor(a.FS)(&data)) if errors.Is(err, io.EOF) { break } @@ -157,7 +147,7 @@ func (c *Assets[T]) FromYAML(r io.Reader) (result []T, err error) { return nil, err } - entry := c.Constructor() + entry := a.Constructor() if err = jsoniter.Unmarshal(json, &entry); err != nil { return nil, err } diff --git a/assets_test.go b/assets_test.go index 69a71b8a5323ca6bd8d7b103f66a70b62054ef29..09c83ad02de471b558c9bc6d25298bdd43a5435f 100644 --- a/assets_test.go +++ b/assets_test.go @@ -26,7 +26,7 @@ type nested struct { Option *bool } -func TestFromFS(t *testing.T) { +func TestFromDir(t *testing.T) { tr := true i1 := &testEntry{ ID: "item1", @@ -46,8 +46,8 @@ func TestFromFS(t *testing.T) { i3 := *i1 i3.ID = "item3" - assets := NewAssets[*testEntry]() - r, err := assets.FromFS(os.DirFS("assets/tests/assets")) + assets := NewAssets[*testEntry](os.DirFS(".")) + r, err := assets.FromDir("assets/tests/assets") require.NoError(t, err) require.Len(t, r, 3) assert.ElementsMatch(t, []*testEntry{i1, &i2, &i3}, r) @@ -73,13 +73,14 @@ func TestFrom(t *testing.T) { i3 := *i1 i3.ID = "item3" - assets := NewAssets[*testEntry]() - r, err := assets.From(os.DirFS("assets"), "tests/assets") + assets := NewAssets[*testEntry](os.DirFS(".")) + r, err := assets.From("assets/tests/assets") require.NoError(t, err) require.Len(t, r, 3) assert.ElementsMatch(t, []*testEntry{i1, &i2, &i3}, r) - r, err = assets.From(os.DirFS("assets"), "tests/assets/items.yaml") + assets = NewAssets[*testEntry](os.DirFS("assets/tests")) + r, err = assets.From("assets/items.yaml") require.NoError(t, err) require.Len(t, r, 2) assert.Equal(t, []*testEntry{i1, &i2}, r) diff --git a/pkg/extension/extension.go b/pkg/extension/extension.go index 15b92676be86b1782eb0ca8e5feb98bf1f8ba186..432078899448d7f4875991e06fba44dd17830917 100644 --- a/pkg/extension/extension.go +++ b/pkg/extension/extension.go @@ -2,6 +2,7 @@ package extension import ( "context" + "io/fs" "go.uber.org/zap" @@ -40,9 +41,6 @@ var ( ErrUninstall = errors.New("uninstall failed") ErrNotInstalled = errors.New("not installed") ErrUnknownExtension = errors.New("unknown extension") - - ManifestAssets = perxis.NewAssets[*ExtensionDescriptor]() - ManifestFromFile = ManifestAssets.MustOneFrom ) // Runnable описывает интерфейс сервиса СЃ запуском Рё остановкой. Вызывается сервером расширений @@ -101,3 +99,8 @@ func UpdateExtensionCollections() setup.CollectionOption { } } } + +// LoadManifest загружает манифест РёР· файла manifest.yaml +func LoadManifest(fsys fs.FS) *ExtensionDescriptor { + return perxis.NewAssets[*ExtensionDescriptor](fsys).MustOneFrom("manifest.yml") +} diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index fdb402b412de15b3ba8aa9d2b0244ea3d22e8f09..7b337f8ab68f732fb3ab2ac804fe89e082c58c6a 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -4,7 +4,6 @@ import ( "context" "reflect" - "git.perx.ru/perxis/perxis-go" "git.perx.ru/perxis/perxis-go/pkg/errors" "git.perx.ru/perxis/perxis-go/pkg/expr" "git.perx.ru/perxis/perxis-go/pkg/schema/field" @@ -34,10 +33,6 @@ var ( Modify = modify.Modify Validate = validate.Validate Evaluate = field.Evaluate - - Assets = perxis.NewAssets[*Schema]().WithConstructor(func() *Schema { return New() }) - FromFS = Assets.FromFS - FromFile = Assets.FromFile ) func (s *Schema) Clone(reset bool) *Schema { diff --git a/pkg/schema/test/assets/invalid.json b/pkg/schema/test/assets/invalid.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/pkg/schema/test/assets/not_schema.txt b/pkg/schema/test/assets/not_schema.txt deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/pkg/schema/test/assets/web_pages.json b/pkg/schema/test/assets/web_pages.json deleted file mode 100644 index 652753c911e79dca0896b2c57587400202d0da69..0000000000000000000000000000000000000000 --- a/pkg/schema/test/assets/web_pages.json +++ /dev/null @@ -1,420 +0,0 @@ -{ - "ui": { - "widget": "Tabs", - "options": { - "description": "path", - "collection_icon": "ApartmentOutlined/FileTextOutlined", - "fields": [ - "content", - "seo", - "settings", - "advanced", - "design", - "variables" - ], - "title": "name", - "key": "path" - }, - "list_view": { - "options": { - "sort": [ - "path" - ], - "page_size": 50, - "fields": [ - "path", - "name", - "updated_at", - "updated_by", - "state" - ] - } - } - }, - "includes": [ - { - "ref": "hoop_item_options", - "optional": true - }, - { - "ref": "ext_web_pages_*", - "optional": true - } - ], - "type": "object", - "params": { - "inline": false, - "fields": { - "design": { - "title": "Дизайн", - "includes": [ - { - "ref": "web_design" - } - ], - "type": "object", - "params": { - "inline": false, - "fields": {} - } - }, - "variables": { - "title": "Переменные", - "ui": { - "options": { - "fields": [ - "variables" - ] - } - }, - "type": "object", - "params": { - "inline": true, - "fields": { - "variables": { - "type": "array", - "params": { - "item": { - "ui": { - "options": { - "collection_icon": "SettingOutlined/FileExcelOutlined", - "fields": [ - "id", - "name", - "value" - ] - }, - "list_view": { - "options": { - "fields": [ - "id", - "name", - "updated_at", - "updated_by", - "state" - ], - "page_size": 50 - } - } - }, - "type": "object", - "params": { - "inline": false, - "fields": { - "id": { - "title": "Рдентификатор переменной", - "text_search": true, - "options": { - "required": true - }, - "type": "string", - "params": {} - }, - "name": { - "title": "Название переменной", - "text_search": true, - "type": "string", - "params": {} - }, - "value": { - "title": "Значение переменной", - "type": "string", - "params": {} - } - } - } - } - } - } - } - } - }, - "content": { - "title": "Содержимое страницы", - "ui": { - "options": { - "fields": [ - "blocks" - ] - } - }, - "type": "object", - "params": { - "inline": true, - "fields": { - "blocks": { - "title": "Блоки", - "ui": { - "widget": "BlockList", - "options": { - "create": { - "classes": [ - "class_web_blocks" - ] - } - } - }, - "type": "array", - "params": { - "item": { - "title": "Блок", - "type": "reference", - "params": { - "allowedCollections": [ - "web_block_*" - ] - } - } - } - } - } - } - }, - "seo": { - "title": "SEO", - "includes": [ - { - "ref": "web_seo" - } - ], - "type": "object", - "params": { - "inline": false, - "fields": {} - } - }, - "settings": { - "title": "Настройки", - "ui": { - "options": { - "fields": [ - "name", - "parent", - "path", - "slug", - "section", - "datasource", - "redirect", - "redirect_path", - "redirect_url", - "outputs", - "navTitle", - "navHide", - "weight" - ] - } - }, - "type": "object", - "params": { - "inline": true, - "fields": { - "path": { - "title": "Путь", - "unique": true, - "text_search": true, - "options": { - "value": "$perxis.Item.Template == true ? _value : parent == nil ? '/' : slug == nil ? make_path(parent, slugify(replace_markers(name))) : make_path(parent, slugify(replace_markers(slug)))" - }, - "type": "string", - "params": {} - }, - "redirect_url": { - "title": "URL для перехода", - "condition": "redirect == true", - "type": "string", - "params": {} - }, - "outputs": { - "title": "Форматы страницы для вывода", - "type": "array", - "params": { - "item": { - "ui": { - "widget": "Lookup", - "options": { - "allowedCollections": [ - { - "collection": "web_outputs" - } - ] - } - }, - "type": "string", - "params": {} - } - } - }, - "weight": { - "title": "РџРѕСЂСЏРґРѕРє следования", - "ui": { - "widget": "NumberInput" - }, - "type": "number", - "params": { - "format": "int" - } - }, - "navHide": { - "title": "Скрыть страницу РёР· навигации", - "ui": { - "widget": "Checkbox" - }, - "type": "bool", - "params": {} - }, - "section": { - "title": "Раздел", - "ui": { - "widget": "Checkbox" - }, - "type": "bool", - "params": {} - }, - "parent": { - "title": "Родительский раздел", - "description": "Раздел сайта, РіРґРµ расположена страница", - "ui": { - "widget": "Lookup", - "options": { - "allowedCollections": [ - { - "collection": "web_pages" - } - ] - } - }, - "type": "string", - "params": {} - }, - "name": { - "title": "Название", - "indexed": true, - "text_search": true, - "options": { - "required": true, - "value": "$perxis.Item.Template == true ? _value : replace_markers(_value)" - }, - "type": "string", - "params": {} - }, - "navTitle": { - "title": "Название для навигации", - "type": "string", - "params": {} - }, - "redirect_path": { - "title": "Страница для перехода", - "ui": { - "widget": "Lookup", - "options": { - "allowedCollections": [ - { - "collection": "web_pages" - } - ] - } - }, - "condition": "redirect == true", - "type": "string", - "params": {} - }, - "datasource": { - "title": "Рсточник данных", - "description": "Рсточник данных РёР· которого Р±СѓРґСѓС‚ формироваться подстраницы раздела", - "ui": { - "widget": "Lookup", - "options": { - "allowedCollections": [ - { - "collection": "web_datasources" - } - ] - } - }, - "condition": "section == true", - "type": "string", - "params": {} - }, - "redirect": { - "title": "Перенаправление", - "description": "Страница РЅРµ имеет содержимого Рё перенаправляет посетителей РЅР° РґСЂСѓРіРѕР№ адрес", - "ui": { - "widget": "Checkbox" - }, - "type": "bool", - "params": {} - }, - "slug": { - "title": "Slug", - "description": "Рдентификатор страницы РІ адресе URL", - "text_search": true, - "options": { - "value": "$perxis.Item.Template == true ? _value : parent == nil ? nil : _value == nil ? slugify(replace_markers(name)) : slugify(replace_markers(_value))" - }, - "type": "string", - "params": {} - } - } - } - }, - "advanced": { - "title": "Расширенные настройки", - "ui": { - "options": { - "fields": [ - "scripts" - ] - } - }, - "type": "object", - "params": { - "inline": false, - "fields": { - "scripts": { - "title": "Дополнительные скрипты", - "type": "array", - "params": { - "item": { - "ui": { - "options": { - "fields": [ - "src", - "type", - "content" - ] - } - }, - "type": "object", - "params": { - "inline": false, - "fields": { - "type": { - "title": "Media Type скрипта", - "type": "string", - "params": {} - }, - "content": { - "title": "Содержимое скрипта", - "type": "string", - "params": {} - }, - "src": { - "title": "URL для загрузки скрипта", - "type": "string", - "params": {} - } - } - } - } - } - } - } - } - } - } - }, - "loaded": false, - "metadata": { - "extension": "perxisweb" - } -} \ No newline at end of file diff --git a/pkg/schema/test/assets/web_pages.yml b/pkg/schema/test/assets/web_pages.yml deleted file mode 100644 index 7fdfdd24fa9dcaa04d31ca1506955c86d6e3ce43..0000000000000000000000000000000000000000 --- a/pkg/schema/test/assets/web_pages.yml +++ /dev/null @@ -1,297 +0,0 @@ ---- -ui: - widget: Tabs - options: - description: path - collection_icon: ApartmentOutlined/FileTextOutlined - fields: - - content - - seo - - settings - - advanced - - design - - variables - title: name - key: path - list_view: - options: - sort: - - path - page_size: 50 - fields: - - path - - name - - updated_at - - updated_by - - state -includes: -- ref: hoop_item_options - optional: true -- ref: ext_web_pages_* - optional: true -type: object -params: - inline: false - fields: - design: - title: Дизайн - includes: - - ref: web_design - type: object - params: - inline: false - fields: {} - variables: - title: Переменные - ui: - options: - fields: - - variables - type: object - params: - inline: true - fields: - variables: - type: array - params: - item: - ui: - options: - collection_icon: SettingOutlined/FileExcelOutlined - fields: - - id - - name - - value - list_view: - options: - fields: - - id - - name - - updated_at - - updated_by - - state - page_size: 50 - type: object - params: - inline: false - fields: - id: - title: Рдентификатор переменной - text_search: true - options: - required: true - type: string - params: {} - name: - title: Название переменной - text_search: true - type: string - params: {} - value: - title: Значение переменной - type: string - params: {} - content: - title: Содержимое страницы - ui: - options: - fields: - - blocks - type: object - params: - inline: true - fields: - blocks: - title: Блоки - ui: - widget: BlockList - options: - create: - classes: - - class_web_blocks - type: array - params: - item: - title: Блок - type: reference - params: - allowedCollections: - - web_block_* - seo: - title: SEO - includes: - - ref: web_seo - type: object - params: - inline: false - fields: {} - settings: - title: Настройки - ui: - options: - fields: - - name - - parent - - path - - slug - - section - - datasource - - redirect - - redirect_path - - redirect_url - - outputs - - navTitle - - navHide - - weight - type: object - params: - inline: true - fields: - path: - title: Путь - unique: true - text_search: true - options: - value: "$perxis.Item.Template == true ? _value : parent == nil ? '/' - : slug == nil ? make_path(parent, slugify(replace_markers(name))) - : make_path(parent, slugify(replace_markers(slug)))" - type: string - params: {} - redirect_url: - title: URL для перехода - condition: redirect == true - type: string - params: {} - outputs: - title: Форматы страницы для вывода - type: array - params: - item: - ui: - widget: Lookup - options: - allowedCollections: - - collection: web_outputs - type: string - params: {} - weight: - title: РџРѕСЂСЏРґРѕРє следования - ui: - widget: NumberInput - type: number - params: - format: int - navHide: - title: Скрыть страницу РёР· навигации - ui: - widget: Checkbox - type: bool - params: {} - section: - title: Раздел - ui: - widget: Checkbox - type: bool - params: {} - parent: - title: Родительский раздел - description: Раздел сайта, РіРґРµ расположена страница - ui: - widget: Lookup - options: - allowedCollections: - - collection: web_pages - type: string - params: {} - name: - title: Название - indexed: true - text_search: true - options: - required: true - value: "$perxis.Item.Template == true ? _value : replace_markers(_value)" - type: string - params: {} - navTitle: - title: Название для навигации - type: string - params: {} - redirect_path: - title: Страница для перехода - ui: - widget: Lookup - options: - allowedCollections: - - collection: web_pages - condition: redirect == true - type: string - params: {} - datasource: - title: Рсточник данных - description: Рсточник данных РёР· которого Р±СѓРґСѓС‚ формироваться подстраницы - раздела - ui: - widget: Lookup - options: - allowedCollections: - - collection: web_datasources - condition: section == true - type: string - params: {} - redirect: - title: Перенаправление - description: Страница РЅРµ имеет содержимого Рё перенаправляет посетителей - РЅР° РґСЂСѓРіРѕР№ адрес - ui: - widget: Checkbox - type: bool - params: {} - slug: - title: Slug - description: Рдентификатор страницы РІ адресе URL - text_search: true - options: - value: "$perxis.Item.Template == true ? _value : parent == nil ? nil - : _value == nil ? slugify(replace_markers(name)) : slugify(replace_markers(_value))" - type: string - params: {} - advanced: - title: Расширенные настройки - ui: - options: - fields: - - scripts - type: object - params: - inline: false - fields: - scripts: - title: Дополнительные скрипты - type: array - params: - item: - ui: - options: - fields: - - src - - type - - content - type: object - params: - inline: false - fields: - type: - title: Media Type скрипта - type: string - params: {} - content: - title: Содержимое скрипта - type: string - params: {} - src: - title: URL для загрузки скрипта - type: string - params: {} -loaded: false -metadata: - extension: perxisweb diff --git a/pkg/schema/test/convert_test.go b/pkg/schema/test/convert_test.go deleted file mode 100644 index 5e791570ebfc12c9efc9a4c9295ce5dacced4af5..0000000000000000000000000000000000000000 --- a/pkg/schema/test/convert_test.go +++ /dev/null @@ -1,174 +0,0 @@ -package test - -import ( - "os" - "testing" - - "git.perx.ru/perxis/perxis-go/pkg/extension" - "git.perx.ru/perxis/perxis-go/pkg/references" - "git.perx.ru/perxis/perxis-go/pkg/schema" - "git.perx.ru/perxis/perxis-go/pkg/schema/field" - "git.perx.ru/perxis/perxis-go/pkg/schema/modify" - "git.perx.ru/perxis/perxis-go/pkg/schema/validate" - "github.com/stretchr/testify/require" -) - -func TestFromFiles(t *testing.T) { - t.Run("Non-existen path", func(t *testing.T) { - schemas, err := schema.FromFS(os.DirFS("non-existen")) - require.Error(t, err) - require.ErrorContains(t, err, "no such file or directory") - require.Nil(t, schemas) - }) - - t.Run("Success", func(t *testing.T) { - schemas, err := schema.FromFS(os.DirFS("assets")) - for _, s := range schemas { - s.ClearState() - } - require.NoError(t, err) - require.Len(t, schemas, 2, "Р’ директории хранятся РґРІРµ корректные схемы") - require.ElementsMatch(t, []*schema.Schema{getPagesSchema(), getPagesSchema()}, schemas, "Cхемы должны соответствовать объекту РёР· функции") - }) -} - -// Оригинальное объявление схемы Web/Страницы -// Значение констант подставлено вручную -func getPagesSchema() *schema.Schema { - content := field.Object( - true, "blocks", field.Array( - references.Field([]string{"web_block_*"}).SetTitle("Блок"), - ). - SetTitle("Блоки"). - WithUI(&field.UI{ - Widget: "BlockList", - Options: map[string]interface{}{ - "create": map[string]interface{}{ - "classes": []string{"class_web_blocks"}, - }, - }, - }), - ).SetTitle("Содержимое страницы") - - // SEO - seo := field.Object().WithIncludes("web_seo").SetTitle("SEO") - - //Settings - settings := field.Object(true, - "name", field.String( - validate.Required(), - modify.Value("$perxis.Item.Template == true ? _value : replace_markers(_value)"), - ).SetTitle("Название").SetTextSearch(true).SetIndexed(true), - "parent", field.String().SetTitle("Родительский раздел").SetDescription("Раздел сайта, РіРґРµ расположена страница").WithUI(&field.UI{ - Widget: "Lookup", - Options: map[string]interface{}{ - "allowedCollections": []interface{}{ - map[string]interface{}{"collection": "web_pages"}, - }, - }, - }), // TODO lookup "section == true" - "path", field.String( - modify.Value("$perxis.Item.Template == true ? _value : parent == nil ? '/' : slug == nil ? make_path(parent, slugify(replace_markers(name))) : make_path(parent, slugify(replace_markers(slug)))"), - ).SetTitle("Путь").SetUnique(true).SetTextSearch(true), // TODO readonly - "slug", field.String(modify.Value("$perxis.Item.Template == true ? _value : parent == nil ? nil : _value == nil ? slugify(replace_markers(name)) : slugify(replace_markers(_value))")).SetTitle("Slug").SetDescription("Рдентификатор страницы РІ адресе URL").SetTextSearch(true), - "section", field.Bool().SetTitle("Раздел").WithUI(&field.UI{Widget: "Checkbox"}), - "datasource", field.String().WithUI(&field.UI{ - Widget: "Lookup", - Options: map[string]interface{}{ - "allowedCollections": []interface{}{ - map[string]interface{}{"collection": "web_datasources"}, - }, - }, - }).SetTitle("Рсточник данных").SetDescription("Рсточник данных РёР· которого Р±СѓРґСѓС‚ формироваться подстраницы раздела").SetCondition("section == true"), - "redirect", field.Bool().SetTitle("Перенаправление").SetDescription("Страница РЅРµ имеет содержимого Рё перенаправляет посетителей РЅР° РґСЂСѓРіРѕР№ адрес").WithUI(&field.UI{Widget: "Checkbox"}), - "redirect_path", field.String().SetTitle("Страница для перехода").WithUI(&field.UI{ - Widget: "Lookup", - Options: map[string]interface{}{ - "allowedCollections": []interface{}{ - map[string]interface{}{"collection": "web_pages"}, - }, - }, - }).SetCondition("redirect == true"), - "redirect_url", field.String().SetTitle("URL для перехода").SetCondition("redirect == true"), - "outputs", field.Array(field.String().WithUI(&field.UI{ - Widget: "Lookup", - Options: map[string]interface{}{ - "allowedCollections": []interface{}{ - map[string]interface{}{"collection": "web_outputs"}, - }, - }, - })).SetTitle("Форматы страницы для вывода"), - "navTitle", field.String().SetTitle("Название для навигации"), - "navHide", field.Bool().SetTitle("Скрыть страницу РёР· навигации").WithUI(&field.UI{Widget: "Checkbox"}), - "weight", field.Number(field.NumberFormatInt).SetTitle("РџРѕСЂСЏРґРѕРє следования").WithUI(&field.UI{Widget: "NumberInput"}), - ).SetTitle("Настройки") - - // Advanced - advanced := field.Object( - "scripts", field.Array( - field.Object( - "src", field.String().SetTitle("URL для загрузки скрипта"), - "type", field.String().SetTitle("Media Type скрипта"), - "content", field.String().SetTitle("Содержимое скрипта"), - ), - ).SetTitle("Дополнительные скрипты"), - ).SetTitle("Расширенные настройки") - - // Design - design := field.Object().WithIncludes("web_design").SetTitle("Дизайн") - - //Variables - variables := field.Object(true, "variables", field.Array(getVarsField())).SetTitle("Переменные") - - // Page - page := schema.New( - "content", content, - "seo", seo, - "settings", settings, - "advanced", advanced, - "design", design, - "variables", variables, - ).WithMetadata(extension.MetadataKey, "perxisweb") - - // Includes - page.SetIncludes( - field.Include{Ref: "hoop_item_options", Optional: true}, - field.Include{Ref: "ext_web_pages_*", Optional: true}, - ) - - //UI - page.Field.UI.ListView = &field.View{Options: map[string]interface{}{ - "fields": []string{"path", "name", "updated_at", "updated_by", "state"}, - "sort": []string{"path"}, - "page_size": 50, - }} - page.Field.UI.Options["title"] = "name" - page.Field.UI.Options["key"] = "path" - page.Field.UI.Options["description"] = "path" - page.Field.UI.Widget = "Tabs" - page.Field.UI.Options["collection_icon"] = "ApartmentOutlined/FileTextOutlined" - - _ = page.ConvertTypes() - page.ClearState() - return page -} - -func getVarsSchema() (sch *schema.Schema) { - sch = schema.New( - "id", field.String(validate.Required()).SetTextSearch(true).SetTitle("Рдентификатор переменной"), - "name", field.String().SetTextSearch(true).SetTitle("Название переменной"), - "value", field.String().SetTitle("Значение переменной"), - ).WithMetadata(extension.MetadataKey, "perxisweb") - //UI - sch.Field.UI.ListView = &field.View{Options: map[string]interface{}{ - "fields": []string{"id", "name", "updated_at", "updated_by", "state"}, - "page_size": 50, - }} - - sch.Field.UI.Options["collection_icon"] = "SettingOutlined/FileExcelOutlined" - return sch -} - -func getVarsField() *field.Field { - return &getVarsSchema().Field -} diff --git a/pkg/setup/config.go b/pkg/setup/config.go index d7f68a90409ab338f8ff191e2f91bf80ddc0b130..48c763248b8c43afd05db3291ab4a1635890ba53 100644 --- a/pkg/setup/config.go +++ b/pkg/setup/config.go @@ -38,28 +38,20 @@ func (cfg *Config) Load(fsys fs.FS) (*Config, error) { return nil, errors.Wrapf(err, "Can't load config. (fs=%v)", fsys) } - if subFS, err := fs.Sub(fsys, "collections"); err == nil { - if err = cfg.Collections.Load(subFS); err != nil && !errors.Is(err, fs.ErrNotExist) { - return nil, err - } + if err := cfg.Collections.Load(fsys, "collections"); err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err } - if subFS, err := fs.Sub(fsys, "items"); err == nil { - if err = cfg.Items.Load(subFS, DecodeItem()); err != nil && !errors.Is(err, fs.ErrNotExist) { - return nil, err - } + if err := cfg.Items.Load(fsys, "items", DecodeItem()); err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err } - if subFS, err := fs.Sub(fsys, "roles"); err == nil { - if err = cfg.Roles.Load(subFS); err != nil && !errors.Is(err, fs.ErrNotExist) { - return nil, err - } + if err := cfg.Roles.Load(fsys, "roles"); err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err } - if subFS, err := fs.Sub(fsys, "clients"); err == nil { - if err = cfg.Clients.Load(subFS); err != nil && !errors.Is(err, fs.ErrNotExist) { - return nil, err - } + if err := cfg.Clients.Load(fsys, "clients"); err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err } return cfg, nil diff --git a/pkg/setup/entity.go b/pkg/setup/entity.go index 69cd2c8d5ef4224bbc270c0c8cbb8df1fdfa1bf1..f9d52a409287a3b63a2e242b7216762707771fe6 100644 --- a/pkg/setup/entity.go +++ b/pkg/setup/entity.go @@ -120,9 +120,9 @@ func (l *EntityList[C, T]) GetIDs() []string { } // Load загружает сущности РІ СЃРїРёСЃРѕРє EntityList РёР· указанной файловой системы -func (l *EntityList[C, T]) Load(fsys fs.FS, opt ...EntityOption[C, T]) error { - assets := perxis.NewAssets[T]() - items, err := assets.FromFS(fsys) +func (l *EntityList[C, T]) Load(fsys fs.FS, dir string, opt ...EntityOption[C, T]) error { + assets := perxis.NewAssets[T](fsys) + items, err := assets.FromDir(dir) if err != nil { return err } @@ -133,8 +133,8 @@ func (l *EntityList[C, T]) Load(fsys fs.FS, opt ...EntityOption[C, T]) error { } // MustLoad загружает сущности РІ СЃРїРёСЃРѕРє EntityList РёР· указанной файловой системы -func (l *EntityList[C, T]) MustLoad(fsys fs.FS, opt ...EntityOption[C, T]) { - if err := l.Load(fsys, opt...); err != nil { +func (l *EntityList[C, T]) MustLoad(fsys fs.FS, dir string, opt ...EntityOption[C, T]) { + if err := l.Load(fsys, dir, opt...); err != nil { panic(err) } }