@rt-tools/agent-kit 0.3.0 → 0.5.0
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 +194 -30
- package/assets/agents/business-analyst.md +74 -0
- package/assets/agents/project-manager.md +70 -0
- package/assets/agents/qa-engineer.md +72 -0
- package/assets/agents/skill-curator.md +110 -0
- package/assets/agents/spec-critic.md +44 -0
- package/assets/agents/spec-writer.md +50 -0
- package/assets/checks/board.github.mjs +329 -0
- package/assets/checks/check-board.github.mjs +181 -0
- package/assets/checks/check-doc-paths.mjs +163 -0
- package/assets/checks/check-dupes.mjs +277 -0
- package/assets/checks/check-lib-layers.mjs +573 -0
- package/assets/checks/check-reuse.mjs +208 -0
- package/assets/checks/check-schema-drift.mjs +186 -0
- package/assets/checks/check-specs.mjs +1086 -0
- package/assets/checks/check-styles.mjs +109 -0
- package/assets/checks/rt-kit-checks.config.mjs +134 -0
- package/assets/checks/task-new.github.mjs +198 -0
- package/assets/commands/skill-curator.md +70 -0
- package/assets/defaults/gate-map.sh +106 -0
- package/assets/defaults/project.sh +204 -0
- package/assets/hooks/browser-device-id.sh +0 -0
- package/assets/hooks/browser-guard-device-id.sh +2 -1
- package/assets/hooks/browser-guard-no-asking.sh +27 -0
- package/assets/hooks/browser-guard-no-listing.sh +2 -1
- package/assets/hooks/browser-guard-no-other-drivers.sh +2 -1
- package/assets/hooks/browser-guard-require-select.sh +2 -1
- package/assets/hooks/commit-msg.sh +1 -1
- package/assets/hooks/constitution-index.sh +5 -4
- package/assets/hooks/dev-server-guard.sh +8 -6
- package/assets/hooks/docs-guard.sh +223 -37
- package/assets/hooks/git-guard-delivery.sh +171 -31
- package/assets/hooks/git-guard-main.sh +1 -0
- package/assets/hooks/git-guard-push-tests.sh +34 -13
- package/assets/hooks/glossary-load.sh +23 -0
- package/assets/hooks/grill-gate.sh +96 -0
- package/assets/hooks/lint-after-edit.sh +155 -30
- package/assets/hooks/qa-dataid-guard.sh +72 -32
- package/assets/hooks/reuse-first-guard.sh +105 -34
- package/assets/hooks/skill-gate-rearm.sh +1 -0
- package/assets/hooks/skill-gate.sh +75 -15
- package/assets/hooks/skill-loaded.sh +1 -0
- package/assets/hooks/sql-guard.sh +606 -56
- package/assets/hooks/task-context-load.sh +100 -0
- package/assets/hooks/task-flow-guard.sh +118 -0
- package/assets/laws/{access.md → application/access.md} +1 -4
- package/assets/laws/{locales.md → application/locales.md} +1 -3
- package/assets/laws/application/money.md +41 -0
- package/assets/laws/application/ownership.md +32 -0
- package/assets/laws/{search-visibility.md → application/search-visibility.md} +1 -1
- package/assets/laws/code-structure.md +7 -6
- package/assets/laws/delivery.md +53 -3
- package/assets/laws/entity-editing.md +49 -55
- package/assets/laws/entity-models.md +4 -14
- package/assets/laws/frontend-application.md +5 -5
- package/assets/laws/lib-imports.md +14 -1
- package/assets/laws/lists.md +33 -0
- package/assets/laws/navigation.md +40 -0
- package/assets/laws/project-documentation.md +27 -8
- package/assets/laws/reuse-first.md +26 -21
- package/assets/laws/shared-code.md +13 -1
- package/assets/laws/verifiability.md +30 -1
- package/assets/laws/work-conduct.md +59 -0
- package/assets/patterns/admin-lists-screen.md +131 -0
- package/assets/patterns/admin-nav-item.md +71 -0
- package/assets/patterns/angular-patterns-state.md +29 -22
- package/assets/patterns/api-layer-pair.md +40 -30
- package/assets/patterns/browser-verification-measure.md +41 -38
- package/assets/patterns/browser-verification-stand.md +106 -42
- package/assets/patterns/component-structure-new.md +33 -32
- package/assets/patterns/dependencies-upgrade.md +65 -0
- package/assets/patterns/doc-style-sweep.md +65 -28
- package/assets/patterns/doc-style-write.md +36 -33
- package/assets/patterns/entity-aside.md +136 -0
- package/assets/patterns/entity-models-new.md +124 -0
- package/assets/patterns/entity-store.md +91 -0
- package/assets/patterns/git-workflow-commit.azure.md +259 -0
- package/assets/patterns/git-workflow-commit.github.md +337 -0
- package/assets/patterns/git-workflow-commit.gitlab.md +283 -0
- package/assets/patterns/git-workflow-merge.md +42 -25
- package/assets/patterns/git-workflow-migration.md +61 -31
- package/assets/patterns/git-workflow-restart.md +20 -20
- package/assets/patterns/lib-layers-move.md +50 -32
- package/assets/patterns/lib-layers-new.md +41 -29
- package/assets/patterns/ownership-scope-resolve.md +69 -0
- package/assets/patterns/permissions-procedure.md +35 -33
- package/assets/patterns/platform-access-di.md +39 -25
- package/assets/patterns/pricing-quote.md +71 -0
- package/assets/patterns/reuse-first-extend.md +22 -22
- package/assets/patterns/seo-page.md +52 -40
- package/assets/patterns/seo-verify.md +48 -29
- package/assets/patterns/shared-code-new.md +37 -31
- package/assets/patterns/spec-driven-domain.md +60 -37
- package/assets/patterns/spec-driven-rule.md +55 -40
- package/assets/patterns/styling-bem-component.md +43 -32
- package/assets/patterns/styling-bem-layout.md +30 -24
- package/assets/patterns/task-flow-close.md +154 -0
- package/assets/patterns/task-flow-resume.md +94 -0
- package/assets/patterns/task-flow-start.md +129 -0
- package/assets/patterns/testing-e2e.md +53 -51
- package/assets/patterns/testing-unit.md +70 -46
- package/assets/patterns/translations-key.md +32 -19
- package/assets/patterns/ts-procedure.md +24 -25
- package/assets/rules/angular-patterns.md +50 -27
- package/assets/rules/api-layer.md +46 -28
- package/assets/rules/browser-verification.md +67 -48
- package/assets/rules/component-structure.md +43 -27
- package/assets/rules/dependencies.md +66 -0
- package/assets/rules/doc-style.md +95 -39
- package/assets/rules/entity-conventions.md +78 -0
- package/assets/rules/entity-models.md +70 -0
- package/assets/rules/git-workflow.azure.md +116 -0
- package/assets/rules/git-workflow.github.md +123 -0
- package/assets/rules/git-workflow.gitlab.md +113 -0
- package/assets/rules/lib-layers.md +56 -30
- package/assets/rules/lists.md +73 -0
- package/assets/rules/navigation.md +78 -0
- package/assets/rules/ownership-scope.md +63 -0
- package/assets/rules/permissions.md +43 -25
- package/assets/rules/platform-access.md +57 -29
- package/assets/rules/pricing.md +64 -0
- package/assets/rules/reuse-first.md +57 -43
- package/assets/rules/seo.md +51 -30
- package/assets/rules/shared-code.md +51 -26
- package/assets/rules/spec-driven.md +107 -51
- package/assets/rules/styling-bem.md +54 -39
- package/assets/rules/task-flow.md +150 -0
- package/assets/rules/testing.md +78 -47
- package/assets/rules/translations.md +48 -31
- package/assets/rules/typescript-conventions.md +57 -27
- package/assets/skills/agent-kit.md +85 -0
- package/assets/skills/write-a-skill.md +108 -0
- package/assets/templates/gate-map.sh +23 -15
- package/assets/templates/implementation.md +14 -8
- package/assets/templates/pattern.md +1 -1
- package/assets/templates/project.sh +32 -19
- package/assets/templates/rule.md +2 -2
- package/assets/variants.json +20 -0
- package/assets/workflows/feature.js +134 -0
- package/assets/workflows/plan.js +150 -0
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +78 -5
- package/bin/agent-kit.js.map +1 -1
- package/bin/prompt.d.ts +5 -0
- package/bin/prompt.d.ts.map +1 -1
- package/bin/prompt.js +19 -7
- package/bin/prompt.js.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/lib/assets.d.ts +8 -3
- package/lib/assets.d.ts.map +1 -1
- package/lib/assets.js +13 -3
- package/lib/assets.js.map +1 -1
- package/lib/catalog.d.ts +52 -5
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +104 -16
- package/lib/catalog.js.map +1 -1
- package/lib/commands.d.ts +22 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +202 -14
- package/lib/commands.js.map +1 -1
- package/lib/companion.d.ts +5 -1
- package/lib/companion.d.ts.map +1 -1
- package/lib/companion.js +29 -2
- package/lib/companion.js.map +1 -1
- package/lib/config.d.ts +26 -9
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +41 -15
- package/lib/config.js.map +1 -1
- package/lib/freshness.d.ts +14 -0
- package/lib/freshness.d.ts.map +1 -0
- package/lib/freshness.js +116 -0
- package/lib/freshness.js.map +1 -0
- package/lib/hooks-map.d.ts +27 -0
- package/lib/hooks-map.d.ts.map +1 -0
- package/lib/hooks-map.js +77 -0
- package/lib/hooks-map.js.map +1 -0
- package/lib/integrity.d.ts +36 -0
- package/lib/integrity.d.ts.map +1 -0
- package/lib/integrity.js +44 -0
- package/lib/integrity.js.map +1 -0
- package/lib/picker.d.ts +11 -1
- package/lib/picker.d.ts.map +1 -1
- package/lib/picker.js +44 -6
- package/lib/picker.js.map +1 -1
- package/lib/sync.d.ts +26 -0
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +59 -4
- package/lib/sync.js.map +1 -1
- package/lib/variants.d.ts +44 -0
- package/lib/variants.d.ts.map +1 -0
- package/lib/variants.js +82 -0
- package/lib/variants.js.map +1 -0
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.5.0.tgz +0 -0
- package/assets/laws/admin-lists.md +0 -35
- package/assets/laws/admin-navigation.md +0 -38
- package/assets/patterns/git-workflow-commit.md +0 -175
- package/assets/rules/git-workflow.md +0 -106
- package/rt-tools-agent-kit-0.3.0.tgz +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Закон о фронтовом приложении
|
|
2
2
|
|
|
3
|
-
Как устроено то, что рисует экран. Закон
|
|
3
|
+
Как устроено то, что рисует экран. Закон общий для всех приложений сразу: экран, устроенный
|
|
4
4
|
иначе соседнего, пользователь читает заново, а разработчик правит вслепую.
|
|
5
5
|
|
|
6
6
|
## Статьи
|
|
@@ -18,6 +18,6 @@
|
|
|
18
18
|
рабочим и молча ничего не делает.
|
|
19
19
|
- **Набор записей приходит с сервера страницей, а не целиком.** Список, растущий вместе с
|
|
20
20
|
данными, однажды перестаёт открываться, и заметно это становится уже у пользователя.
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
- **Окружение, которого нет на сервере, приходит экрану извне, а не берётся у среды.**
|
|
22
|
+
Взятое напрямую, оно компилируется и падает при отдаче страницы сервером — то есть у гостя,
|
|
23
|
+
а не у того, кто это написал. Места, где иначе нельзя, названы поимённо.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Закон об импортах между либами
|
|
2
2
|
|
|
3
3
|
Кто кого видит. Приложение нарезано на либы, и у каждой объявлен список тех, от кого ей
|
|
4
4
|
разрешено зависеть: так домен, которому незачем знать про чужой транспорт или чужие экраны,
|
|
@@ -16,3 +16,16 @@
|
|
|
16
16
|
дописывается строкой с объяснением, зачем оно понадобилось.
|
|
17
17
|
- **У либы, общей всем трём приложениям, список зависимостей пуст.** Её видит и бэкенд, и
|
|
18
18
|
любая её зависимость стала бы общей для всех сразу.
|
|
19
|
+
- **Место общего символа выбирается по тому, кому он нужен, а не по тому, о чём он.**
|
|
20
|
+
Разложенные по предмету, символы одного предмета всё равно разъезжаются: часть из них
|
|
21
|
+
тянет за собой то, что доступно не каждому потребителю.
|
|
22
|
+
- **Своя либа заводится тогда, когда ни одна существующая потребителям не видна.** Заведённая
|
|
23
|
+
раньше, она стоит пустая: у механики, у которой нет ни экранов, ни состояния, ни запросов,
|
|
24
|
+
заполнять слои нечем.
|
|
25
|
+
- **У домена заполнен не один слой, а если один — это решено и объяснено.** Домен с
|
|
26
|
+
единственным заполненным слоем неотличим от заготовки под будущую работу, и заготовка,
|
|
27
|
+
простоявшая полгода, читается как домен.
|
|
28
|
+
- **Повтор, у которого не совпало имя, находит читатель правки, а не проверка.** Копию с тем
|
|
29
|
+
же именем или тем же набором значений видно сверкой, а ту же логику, написанную заново под
|
|
30
|
+
другим именем, — нет. Признак, который ловил бы её, отбивал бы заодно и законное: две
|
|
31
|
+
одинаковые по форме проверки из разных доменов копией не считаются.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Закон о списке записей
|
|
2
|
+
|
|
3
|
+
Как пользователь видит список записей и что делает с ними, не открывая ни одну. Правила общие
|
|
4
|
+
для всех списков: список, устроенный иначе остальных, пользователь читает заново.
|
|
5
|
+
|
|
6
|
+
Открытая запись, попадание в список и объём данных на строку — предмет других законов.
|
|
7
|
+
|
|
8
|
+
## Статьи
|
|
9
|
+
|
|
10
|
+
- **Каждая запись показана отдельной строкой, а каждое её свойство — своим столбцом.**
|
|
11
|
+
- **Нажатие на строку открывает запись.** Действия над записью вынесены отдельно: иначе, чтобы
|
|
12
|
+
открыть запись, пришлось бы сначала выбирать действие.
|
|
13
|
+
- **Пока список читается, на месте строк видно, что идёт чтение.** Пустую область не отличить
|
|
14
|
+
от списка, в котором ничего нет.
|
|
15
|
+
- **Пустой список объясняет, почему он пуст.**
|
|
16
|
+
- **На узком экране строка перестраивается так, чтобы её свойства читались без прокрутки
|
|
17
|
+
вбок.**
|
|
18
|
+
- **Состав и порядок столбцов выбирает пользователь, и выбор сохраняется, когда он уходит с
|
|
19
|
+
экрана и возвращается.**
|
|
20
|
+
- **Отбор и сортировка стоят отдельно от действий над списком.** Вперемешку они читаются как
|
|
21
|
+
один набор кнопок, и непонятно, что меняет показанное, а что — сами записи.
|
|
22
|
+
- **Действие, которое с этой записью сейчас сделать нельзя, в её меню не показано.** Что можно
|
|
23
|
+
с записью, зависит от её состояния и меняется от строки к строке: перечислять в каждой
|
|
24
|
+
недоступное — показывать пользователю список запретов вместо списка действий.
|
|
25
|
+
- **У записи, с которой нельзя сделать ничего, меню нет вовсе.**
|
|
26
|
+
- **Действие, которое нельзя отменить, спрашивает подтверждение и называет последствие.**
|
|
27
|
+
- **Если список не прочитался, пользователю сказано почему, и повторить попытку можно одним
|
|
28
|
+
действием.**
|
|
29
|
+
- **Пользователь видит ту сортировку и тот отбор, которые на самом деле применены.**
|
|
30
|
+
Сортировка по умолчанию видна сразу, а условие, которое сервер не принял, не остаётся на
|
|
31
|
+
экране как действующее.
|
|
32
|
+
- **Подписи списка берутся из словаря, а не написаны в разметке.** Заголовки столбцов, тексты
|
|
33
|
+
состояний и названия действий меняются вместе с языком.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Закон о навигации по разделам
|
|
2
|
+
|
|
3
|
+
Как пользователь находит раздел и попадает в него. Правила общие для всех разделов сразу:
|
|
4
|
+
раздел, который ведёт себя иначе остальных, выглядит сломанным.
|
|
5
|
+
|
|
6
|
+
## Статьи
|
|
7
|
+
|
|
8
|
+
- **Пункт меню ведёт на отдельный экран со своим адресом,** а не на вкладку внутри чужого
|
|
9
|
+
экрана и не на что-то всплывающее поверх него. Такой адрес открывается по прямой ссылке,
|
|
10
|
+
работает после перезагрузки и его можно передать другому человеку.
|
|
11
|
+
- **Раздел, ни один пункт которого пользователю не виден, в меню не показан.**
|
|
12
|
+
- **Адрес открывается только тому, кто видит ведущий на него пункт.**
|
|
13
|
+
- **Видимость пункта и доступ к его адресу считаются по одному и тому же объявлению.** Два
|
|
14
|
+
объявления рядом рано или поздно разойдутся, и получится, что пункта не видно, а страница
|
|
15
|
+
открывается.
|
|
16
|
+
- **Чтобы раздел был виден, достаточно любого одного из перечисленных у него прав.** Части
|
|
17
|
+
экрана закрываются отдельно: экран бывает полезен и тому, кто видит одну его половину, и
|
|
18
|
+
тому, кто видит другую.
|
|
19
|
+
- **Пункт, у которого экрана ещё нет, виден всем.** Права на него не выдаются: право открывает
|
|
20
|
+
экран, а экрана нет.
|
|
21
|
+
- **Пункт раздела, которого ещё нет, остаётся видимым.** Исчезнувший пункт не отличить от
|
|
22
|
+
того, которого никогда и не было. Пункт, закрытый правом, — другое дело: раздел существует,
|
|
23
|
+
и решает право, поэтому такой пункт не показан вовсе.
|
|
24
|
+
- **Подсказка есть только у пункта, который не нажимается, и объясняет почему.** У остальных
|
|
25
|
+
она дословно повторяет подпись рядом и ничего не добавляет.
|
|
26
|
+
- **На такой пункт можно навести курсор и попасть с клавиатуры.** Иначе его подсказку не
|
|
27
|
+
прочитать.
|
|
28
|
+
- **Адрес экрана начинается с адреса раздела, в котором стоит его пункт.**
|
|
29
|
+
- **Активный раздел отмечен, даже когда открыт его вложенный экран.**
|
|
30
|
+
- **Подписи разделов берутся из словаря и меняются вместе с языком без перезагрузки.**
|
|
31
|
+
- **Вложенные пункты раскрываются и наведением, и нажатием.** На сенсорном экране наведения
|
|
32
|
+
нет, и без второго способа такой раздел не открыть.
|
|
33
|
+
- **Вложенные пункты разбиты на группы с названиями.** Полтора десятка пунктов подряд одним
|
|
34
|
+
списком не читаются.
|
|
35
|
+
- **Раскрытые пункты помещаются на экран целиком.** Иначе дальний край уходит за границу
|
|
36
|
+
экрана, и о том, что там что-то есть, пользователь не узнает.
|
|
37
|
+
- **По пункту видно, раскроется ли он.** Иначе пользователь наводит наугад.
|
|
38
|
+
- **На узком экране меню убирается, но раскрывается тем же составом и теми же группами.**
|
|
39
|
+
Деление на группы там нужно не меньше, чем на широком.
|
|
40
|
+
- **Меню, которое не помещается по высоте, прокручивается.**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Закон о документации проекта
|
|
2
2
|
|
|
3
3
|
Что должно быть верно про тексты, которые проект о себе пишет. Расхождение документа с
|
|
4
4
|
работающим приложением беззвучно: ни сборка, ни проверки текстов не читают, поэтому
|
|
@@ -11,16 +11,35 @@
|
|
|
11
11
|
для которых не заведено места, вспоминаются уже после выкатки.
|
|
12
12
|
- **Каждое утверждение документа привязано к месту, где оно исполняется.** Утверждение без
|
|
13
13
|
такого места — намерение, и называть его действующим нельзя.
|
|
14
|
+
- **Предстоящая работа перечислена в одном месте — в очереди работ.** Документ второго списка
|
|
15
|
+
не заводит: два списка об одной работе расходятся молча, и по ним потом не понять, что
|
|
16
|
+
сделано, а что нет. Документу остаётся то, что задачей не бывает, — договорённость и
|
|
17
|
+
решение, которое решено не править.
|
|
14
18
|
- **Привязка не ведёт в код, который никто не зовёт.** Объявленный и никем не используемый
|
|
15
19
|
символ ничего не исполняет, а проверка на нём остаётся зелёной.
|
|
16
20
|
- **Путь, названный в документе, существует.** Ссылка на переехавший файл читается как
|
|
17
21
|
действующее указание, и следующий читатель заводит снятое заново.
|
|
18
22
|
- **Документ, разошедшийся с приложением, правится тогда же, когда замечено расхождение.**
|
|
19
23
|
Отложенная правка не случается: расхождение перестаёт быть заметным на следующий день.
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
- **Расхождение чинится в той стороне, которая неправа, и это не всегда документ.**
|
|
25
|
+
Состояние, описанное как существующее, но недостижимое в приложении, — дефект приложения:
|
|
26
|
+
строка читается справкой о работающем, на неё ссылаются как на проверенное, и правка
|
|
27
|
+
документа под код закрепила бы дыру вместо того, чтобы её показать.
|
|
28
|
+
- **Документ не утверждает о будущем, и следит за этим автор.** «Не планируется», «не будет»
|
|
29
|
+
— это намерение, а не свойство приложения: сверить его не с чем, и оно проходит любую
|
|
30
|
+
проверку. Машине это не поручить: открытый вопрос пишется теми же словами, что и обещание,
|
|
31
|
+
и проверка отбивала бы оба.
|
|
32
|
+
- **Документ утверждает о состоявшемся, а не о том, что должно сработать.** Лечение,
|
|
33
|
+
записанное готовым до того, как его прогнали, дороже отсутствия записи: следующий читатель
|
|
34
|
+
берёт его за проверенное — и берёт в тот день, когда лечение понадобилось, а времени на
|
|
35
|
+
разбор нет. Непрогнанное либо не пишется вовсе, либо названо непроверенным тем же
|
|
36
|
+
предложением.
|
|
37
|
+
- **Число в тексте пересчитывается тем же изменением, которым пишется, и за этим тоже следит
|
|
38
|
+
автор.** Устаревшее число выглядит так же, как свежее, а машине их не различить: дата,
|
|
39
|
+
версия и номер — такие же числа, и проверка, которая знает один способ записи, на другом
|
|
40
|
+
ошибается молча.
|
|
41
|
+
- **Отказ от слова распространяется на всё, что уже прочитано снаружи, а не только на файлы.**
|
|
42
|
+
Название работы, её описание и запись о правке живут вне дерева: поиск по файлам их не
|
|
43
|
+
видит, проверки текстов на них не смотрят, и отказ выглядит сделанным ровно до того, как
|
|
44
|
+
читатель наткнётся на снятое слово в заголовке. Читатель при этом заключает, что от слова
|
|
45
|
+
не отказывались вовсе.
|
|
@@ -1,26 +1,31 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Закон о единообразии приложения
|
|
2
2
|
|
|
3
|
-
Одинаковые
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
основ, а не написаны заново каждая под себя.
|
|
3
|
+
Одинаковые по смыслу вещи выглядят и ведут себя одинаково во всех частях приложения. Так
|
|
4
|
+
получается потому, что части собраны из одного набора готовых элементов, а не написаны каждая
|
|
5
|
+
по-своему.
|
|
7
6
|
|
|
8
|
-
Закон говорит о том, что верно для
|
|
9
|
-
его предмет.
|
|
7
|
+
Закон говорит о том, что верно для пользователя. Как готовое устроено в коде — не его предмет.
|
|
10
8
|
|
|
11
9
|
## Статьи
|
|
12
10
|
|
|
13
|
-
- **Готовое
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
11
|
+
- **Готовое берут, а не пишут заново.** Своя копия расходится с оригиналом с первой же правки,
|
|
12
|
+
и одинаковые с виду места начинают вести себя по-разному.
|
|
13
|
+
- **Отойти от общего вида может решить только владелец.** Сделать своё вместо готового
|
|
14
|
+
спрашивают у него до того, как написана первая строка.
|
|
15
|
+
- **Одинаковые по смыслу элементы ведут себя одинаково везде.** Поле ввода отвечает на ошибку
|
|
16
|
+
так же, как соседнее; форма правки закрывается так же, как в другой части приложения; об
|
|
17
|
+
удаче и неудаче сообщают одинаково на любом экране. Когда одинаковое по смыслу выглядит
|
|
18
|
+
по-разному, пользователь думает, что приложение в разных состояниях.
|
|
19
|
+
- **Раскладка страниц, форм и окон задана один раз и действует на всё приложение.** Отступы,
|
|
20
|
+
заголовок, полоса действий и место под содержимое у всех одинаковы и меняются разом.
|
|
21
|
+
- **Оформление хранится там же, где сама часть приложения.** Заданное прямо в разметке, оно
|
|
22
|
+
меняет только свой экран, а соседний остаётся с прежним видом.
|
|
23
|
+
- **Отступление от готового останавливается до того, как написан файл.** Замеченное на
|
|
24
|
+
чтении правки не ловится: своя разметка сама по себе исправна, и расхождение видно только
|
|
25
|
+
тому, кто помнит, что готовое для этого уже есть.
|
|
26
|
+
- **Накопленное до запрета сосчитано и не растёт.** Запрет, поставленный на новое, о старом
|
|
27
|
+
не говорит ничего: без числа накопленное выглядит то ли исчезнувшим, то ли неисчислимым, и
|
|
28
|
+
сокращать нечего.
|
|
29
|
+
- **Повторяющаяся механика держится в одном месте, а каждый случай объявляет только своё.**
|
|
30
|
+
Оставленная договорённостью, она пишется заново при каждом применении, и применения
|
|
31
|
+
незаметно расходятся между собой.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Закон об общем коде приложений
|
|
2
2
|
|
|
3
3
|
Что сайт, админка и бэкенд понимают одинаково: размер страницы, набор операторов условия,
|
|
4
4
|
направление порядка, длину поля. Записанное дважды расходится по одному значению за раз, и
|
|
@@ -13,7 +13,19 @@
|
|
|
13
13
|
объявлениями, и одно из них успело стать `25` против `20` у остальных.
|
|
14
14
|
- **Набор значений, уже объявленный в общем пакете, заново не объявляется.** Оператор условия
|
|
15
15
|
и направление порядка лежали на бэкенде рукописной копией того же набора.
|
|
16
|
+
- **Одно и то же значение, записанное в двух местах, считается одним понятием, как бы оно ни
|
|
17
|
+
называлось.** Совпадение имён обманчиво в обе стороны: одно имя носят разные вещи, а одно и
|
|
18
|
+
то же понятие расходится по именам — и второе прячет копию надёжнее первого.
|
|
16
19
|
- **Значение из конечного набора сверяется с набором, а не приводится к типу.** Приведение
|
|
17
20
|
принимает любую строку, и порядок молча становится нечитаемым.
|
|
18
21
|
- **Номер страницы меньше единицы читается как первая.** Отрицательный номер доходил до
|
|
19
22
|
переключателя страниц как есть.
|
|
23
|
+
- **Значение, у которого есть общее умолчание, доводом не принимается.** Пока его можно
|
|
24
|
+
передать, каждый случай вправе назвать своё число, — так размер страницы у одного списка и
|
|
25
|
+
стал отличаться от остальных.
|
|
26
|
+
- **Клиент и сервер описывают одно и то же одними моделями.** Свои понятия про то же самое
|
|
27
|
+
расходятся молча: у сервера они успели разойтись с клиентом на отрицательном номере
|
|
28
|
+
страницы.
|
|
29
|
+
- **Промах в значении выборки на клиенте берёт умолчание, а на сервере становится отказом.**
|
|
30
|
+
Общим чтением это не покрывается: сервер, принявший неизвестное значение молча, отдаёт не
|
|
31
|
+
то, что просили, и об этом никто не узнаёт.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Закон о проверяемости
|
|
2
2
|
|
|
3
3
|
Что считается подтверждением того, что работа сделана. Закон нужен потому, что пересказ
|
|
4
4
|
выглядит так же уверенно, как проверенное утверждение, и отличить их потом нечем: код,
|
|
@@ -12,9 +12,38 @@
|
|
|
12
12
|
выглядит так же, как покрытый сценарий, и долг перестаёт быть заметным.
|
|
13
13
|
- **Тест, проверяющий часть обещанного, считается долгом, а не покрытием.** Иначе сводка
|
|
14
14
|
показывает выполненным то, что выполнено наполовину.
|
|
15
|
+
- **Обещание, данное пользователю, закрывается тестом, который идёт его путём.** Тот же
|
|
16
|
+
расчёт, проверенный мимо экрана, верен — и обещания не закрывает: между верным решением и
|
|
17
|
+
тем, что человек его видит, лежит всё, чего проверка не касалась.
|
|
18
|
+
- **Тест, выключенный признаком окружения, покрытием не считается.** В обычном прогоне он не
|
|
19
|
+
исполняется ни разу, а в сводке выглядит так же, как исполненный.
|
|
15
20
|
- **Упоминание в тесте сценария, которого нет, — отказ.** Так ловится переименованный или
|
|
16
21
|
выкинутый сценарий: без этого он пропадает молча.
|
|
17
22
|
- **Работающее приложение проверяется там, где его видит пользователь.** Отладочный режим
|
|
18
23
|
ведёт себя иначе рабочего, и проверка в нём подтверждает не то, что будет у пользователя.
|
|
24
|
+
- **Перед отправкой правка проверяется тем же набором, что и конвейер, и теми же командами.**
|
|
25
|
+
Набор, собранный по изменённым файлам, пропускает то, до чего правка дошла связями: проверка
|
|
26
|
+
зелёная, а конвейер красный. Что проверять, считает инструмент от той же базы, а не память
|
|
27
|
+
автора.
|
|
28
|
+
- **Проверка признака окружения относится только к тому пути запуска, на котором она
|
|
29
|
+
сделана.** Пути, которыми одно и то же приложение поднимается, задают признаки по-разному,
|
|
30
|
+
и подтверждённое на одном из них на остальных неверно — а выглядит проверенным целиком.
|
|
19
31
|
- **Разметка проверяется замером, а не взглядом.** На глаз не отличить отступ от поля и
|
|
20
32
|
выравнивание от совпадения, и расхождение находится уже после выкатки.
|
|
33
|
+
- **Успешный ответ команды означает, что она отработала, а не что нужное состояние
|
|
34
|
+
наступило.** Часть запросов выполняется наполовину, и об отклонённой части в ответе ничего
|
|
35
|
+
нет: по коду возврата такой вызов не отличить от исполненного. Поэтому результат читают
|
|
36
|
+
отдельным запросом, и в отчёт идёт то, что прочитали, а не то, что заказывали.
|
|
37
|
+
- **Служба считается поднятой, когда она выполнила задание, а не когда сообщила о
|
|
38
|
+
готовности.** Сообщение о готовности говорит лишь, что служба себя объявила: та, которой не
|
|
39
|
+
досталось ни одного задания, выглядит в нём точно так же, как работающая. Проверяются обе
|
|
40
|
+
стороны связи — что заказчик выбирает именно её и что задание через неё прошло.
|
|
41
|
+
- **Причина отказа, на которой строится решение, подтверждается измерением, а не
|
|
42
|
+
правдоподобием.** Объяснение, пришедшее первым, объясняет наблюдаемое не хуже верного:
|
|
43
|
+
свойство среды и собственный промах выглядят в отказе одинаково, и разводит их только замер,
|
|
44
|
+
поставленный так, чтобы одно из двух не прошло. Решение, выведенное из неподтверждённой
|
|
45
|
+
причины, лечит не то — и стоит отката всей работы, а не одной правки.
|
|
46
|
+
- **Если инструмент проверки запрещает приём, которым здесь пользуются постоянно, его правило
|
|
47
|
+
выключают в настройке инструмента, а не обходят в каждом месте.** Обход приходится повторять
|
|
48
|
+
столько раз, сколько таких мест, и ни в одном из них не написано, зачем он: со стороны это
|
|
49
|
+
выглядит ошибкой автора, а не решением.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Закон о ведении работы
|
|
2
|
+
|
|
3
|
+
Что должно быть верно про то, как работа идёт от просьбы владельца до её закрытия. Работа
|
|
4
|
+
длится дольше одного захода и переживает перерывы: между заходами исполнитель не помнит
|
|
5
|
+
ничего, а владелец помнит и вынужден пересказывать. Пересказ каждый раз выходит короче
|
|
6
|
+
предыдущего, и работа доделывается по обрывку исходной просьбы.
|
|
7
|
+
|
|
8
|
+
## Статьи
|
|
9
|
+
|
|
10
|
+
- **Работа не начинается раньше, чем исполнитель понял, о чём его просят.** Пробел в
|
|
11
|
+
понимании сам не закрывается: он всплывает в готовой правке и стоит переделки там, где
|
|
12
|
+
стоил бы вопроса.
|
|
13
|
+
- **Пробел закрывается вопросом владельцу, а не догадкой.** Догадка неотличима от знания:
|
|
14
|
+
она попадает в работу молча и обнаруживается только при приёмке, когда переделывать дороже
|
|
15
|
+
всего.
|
|
16
|
+
- **Владельцу не задаётся вопрос, ответ на который уже записан.** Записанное читают до
|
|
17
|
+
разговора, а не вместо ответа: вопрос о том, что уже решено, обесценивает и остальные.
|
|
18
|
+
- **Решение, однажды записанное, действует, пока его не отменили, и читается до того, как
|
|
19
|
+
принимается заново.** Отменённое решение следа в работе не оставляет — по результату не
|
|
20
|
+
видно ни того, что его принимали, ни того, что от него отказались. Принятое заново оно
|
|
21
|
+
расходится с прежним молча и стоит той же работы второй раз.
|
|
22
|
+
- **Понимание записано там, где идёт работа.** Оставленное в переписке живёт у одного
|
|
23
|
+
участника и до следующего дня; работу продолжает тот, у кого этой переписки нет.
|
|
24
|
+
- **Сказанное владельцем записывается его словами и задним числом не переписывается.**
|
|
25
|
+
Пересказ незаметно подгоняется под уже сделанное, и сверять результат становится не с чем.
|
|
26
|
+
- **Договорённость о том, как продукт себя ведёт, записана раньше кода, который её
|
|
27
|
+
исполняет.** Записанная после, она пишется по коду и повторяет его ошибки: разойтись ей
|
|
28
|
+
уже не с чем, а значит она ничего не проверяет.
|
|
29
|
+
- **Описание приведено к сделанному прежде, чем работа закрыта.** Договорённость пишется до
|
|
30
|
+
кода и описывает замысел, а к концу работы приложение отличается и от замысла тоже.
|
|
31
|
+
Расхождение, отложенное на потом, не находится: назавтра оно уже незаметно, а описание
|
|
32
|
+
продолжают читать как верное.
|
|
33
|
+
- **Состояние незаконченной работы восстанавливается без участия владельца.** Иначе каждый
|
|
34
|
+
перерыв стоит ему пересказа, а очередь работ показывает начатое и не говорит, что внутри
|
|
35
|
+
него сделано.
|
|
36
|
+
- **Замысел и ход работы — разные записи.** Замысел — то, с чем сверяют результат при
|
|
37
|
+
приёмке; правленный по ходу, он перестаёт отличаться от отчёта, и приёмке сверять нечего.
|
|
38
|
+
- **Сделанное отмечается в одном месте.** Две записи об одном разъезжаются молча, и после
|
|
39
|
+
этого ни по одной не видно, что осталось.
|
|
40
|
+
- **Решение, принятое по ходу работы, записывается вместе с причиной.** Без причины оно
|
|
41
|
+
читается как случайное и отменяется следующим заходом, а отменённое возвращается третьим.
|
|
42
|
+
- **Граница работы названа до её начала.** Не названная вслух граница не существует: правка
|
|
43
|
+
расползается на соседнее, и снимать её приходится вручную.
|
|
44
|
+
- **Признак закрытия работы назван до её начала и проверяем.** «Работает» признаком не
|
|
45
|
+
является: под ним каждый заход понимает своё, и работа закрывается тогда, когда надоела.
|
|
46
|
+
- **Начатая и брошенная работа видна.** Брошенное на середине выглядит так же, как
|
|
47
|
+
нетронутое, и второй заход начинает его заново.
|
|
48
|
+
- **Записи о законченной работе не лежат среди записей о текущей.** Закрытое, лежащее рядом
|
|
49
|
+
с действующим, читается как действующее — тем убедительнее, чем оно старше.
|
|
50
|
+
- **Законченная работа убирает за собой до того, как войдёт в общее дерево.** Потом за
|
|
51
|
+
оставленным уже никто не следит: работа перешла к следующей задаче, а правки, которой это
|
|
52
|
+
убрали бы заодно, больше нет.
|
|
53
|
+
- **Достаточность понимания судит тот, кто просил.** Машине видно наличие записи, но не то,
|
|
54
|
+
что в ней закрыты все пробелы: запись из одной строки проходит так же, как разбор на сто.
|
|
55
|
+
Признак достаточности, выведенный из объёма или числа вопросов, сам становится целью —
|
|
56
|
+
исполнитель добирает его, не приближаясь к пониманию.
|
|
57
|
+
- **Незаданный вопрос замечает только тот, кто знает, чего хотел.** Вопрос, которого не
|
|
58
|
+
задали, следа не оставляет: работа выглядит понятой ровно до приёмки, и вывести отсутствие
|
|
59
|
+
вопроса не из чего.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: admin-lists-screen
|
|
3
|
+
kind: pattern
|
|
4
|
+
rule: lists
|
|
5
|
+
description: Паттерн правила lists. Брать при сборке или правке списочного экрана админки — готовый порядок блоков, разметка <префикс>-table, клик по строке, меню строки с vmTableRowActionsRowType, сортируемый заголовок, слоты тулбара, тост отказа.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Собрать списочный экран
|
|
9
|
+
|
|
10
|
+
Паттерн правила `lists`. Что при этом должно быть верно — закон
|
|
11
|
+
`docs/constitution/lists.md`.
|
|
12
|
+
|
|
13
|
+
## Когда брать
|
|
14
|
+
|
|
15
|
+
- Заводится новый экран со списком записей.
|
|
16
|
+
- Правится существующий: столбцы, меню строки, тулбар, сортировка.
|
|
17
|
+
|
|
18
|
+
## Порядок блоков
|
|
19
|
+
|
|
20
|
+
Раскладку даёт общий блок `<префикс>-page` из слоя приложения, а не стили экрана. Экран отвечает за
|
|
21
|
+
порядок:
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<ng-container rtBlock="<префикс>-page">
|
|
25
|
+
<header rtElem="header">
|
|
26
|
+
<!-- div rtElem="header-main" c h1 rtElem="title" + p rtElem="hint" -->
|
|
27
|
+
<<префикс>-toolbar>
|
|
28
|
+
<!-- vmToolbarLeft / vmToolbarRight -->
|
|
29
|
+
<div rtElem="scroll">
|
|
30
|
+
<!-- overflow-x: auto -->
|
|
31
|
+
<<префикс>-table rtElem="table">
|
|
32
|
+
<!-- min-width: max-content -->
|
|
33
|
+
<<префикс>-pagination>
|
|
34
|
+
</div>
|
|
35
|
+
</header>
|
|
36
|
+
</ng-container>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Оба правила прокрутки нужны вместе: с одним контейнером столбцы сжимаются вместо сдвига.
|
|
40
|
+
Тулбар и пагинация своих классов не носят — промежуток задаёт сам `<префикс>-page`.
|
|
41
|
+
|
|
42
|
+
## Таблица
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<<префикс>-table #rowsTable="vmTable" rtElem="table" clickable [ariaLabel]="'bookingsTableAria' | transloco" [emptyMessage]="'bookingsEmpty'
|
|
46
|
+
| transloco" [tableId]="tableId" [dataSource]="rows()" [columnsConfig]="columnsConfig()" [rowHasActions]="hasRowActions"
|
|
47
|
+
[loading]="loading()">
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- `tableId` — ключ, под которым хранится выбор столбцов; он же уходит в асайд настроек.
|
|
51
|
+
- `[columnsConfig]`, а не голый список ключей: из него берутся подписи и для панели настроек, и
|
|
52
|
+
для карточек на узком экране.
|
|
53
|
+
|
|
54
|
+
## Клик по строке
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<tr
|
|
58
|
+
*cdkRowDef="let row; columns: rowsTable.displayedColumns()"
|
|
59
|
+
cdk-row
|
|
60
|
+
qa-dataid="bookings-row"
|
|
61
|
+
vmTableRow
|
|
62
|
+
(activated)="openAside(row)"></tr>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Строки объявляются на `rowsTable.displayedColumns()`: столбец с меню таблица добавляет сама.
|
|
66
|
+
|
|
67
|
+
## Меню строки
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<ng-template vmTableRowActions let-row [vmTableRowActionsRowType]="rows()"></ng-template>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
protected readonly hasRowActions = (row: IBooking.State): boolean => row.canConfirm || row.canReject;
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Доступность действия лежит полем строки (`canConfirm`, `canReject`), а не вызовом метода
|
|
78
|
+
компонента. Действие, которого записи нельзя сделать, из меню убирается целиком. Необратимое
|
|
79
|
+
несёт `danger`, `confirmTitle` и `confirmMessage` с последствием — не «Вы уверены?», а что
|
|
80
|
+
именно произойдёт.
|
|
81
|
+
|
|
82
|
+
## Сортируемый заголовок
|
|
83
|
+
|
|
84
|
+
```html
|
|
85
|
+
<th *cdkHeaderCellDef cdk-header-cell vmSortHeader="checkIn">{{ 'bookingsCheckIn' | transloco }}</th>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Колонка помечается `sortable: true` в `columnsConfig`. Заголовок переключает сортировку по
|
|
89
|
+
кругу и отдаёт выбранное событием `(sortChange)`; саму выборку делает экран. Подпись остаётся
|
|
90
|
+
внутри кнопки — из неё берётся доступное имя.
|
|
91
|
+
|
|
92
|
+
Список приходит уже отсортированным, поэтому экран передаёт таблице текущую сортировку —
|
|
93
|
+
`[sort]="sortModel()"`, — и стрелка стоит на нужной колонке сразу, до первого нажатия. Без
|
|
94
|
+
этого список выглядит неотсортированным, хотя он отсортирован.
|
|
95
|
+
|
|
96
|
+
## Тулбар
|
|
97
|
+
|
|
98
|
+
Тулбар поделён на две части слотами: `vmToolbarLeft` — то, что меняет выборку,
|
|
99
|
+
`vmToolbarRight` — действия над списком. Своей раскладки внутри тулбара экран не заводит.
|
|
100
|
+
|
|
101
|
+
Левый слот — фильтры и поиск. Правый — иконки `<префикс>-icon-button variant="primary"` с парой
|
|
102
|
+
`tooltip` + `ariaLabel` одного текста: обновление (`sync`), настройки столбцов (`sliders-v`),
|
|
103
|
+
создание (`plus`). Если список не прочитался, повторяют той же кнопкой обновления.
|
|
104
|
+
|
|
105
|
+
## Отказ загрузки
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
this.#notifications.error(this.#transloco.translate(this.#store.errorKey() ?? 'bookingsLoadFailed'));
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Ключ читается сразу после запроса, а не подпиской на сигнал стора: стор делят список и панель
|
|
112
|
+
правки, и подписка показала бы один отказ дважды. Строк `<p role="alert">` над таблицей не
|
|
113
|
+
заводить.
|
|
114
|
+
|
|
115
|
+
## Проверить
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npx nx build admin
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Продовая сборка обязательна: без `[vmTableRowActionsRowType]` тип `let-row` выводится как
|
|
122
|
+
`unknown`, и падает только она — юниты и дев-сервер проходят.
|
|
123
|
+
|
|
124
|
+
## Частые промахи
|
|
125
|
+
|
|
126
|
+
- Свой `@if (rows().length === 0)` — экран собран мимо таблицы.
|
|
127
|
+
- Свой список столбцов вместо `displayedColumns()` — пропадает столбец с меню.
|
|
128
|
+
- Доступность действия считается методом компонента — пересчёт на каждой проверке.
|
|
129
|
+
- `[rowHasActions]` не задан — кнопка «…» висит у строки без действий.
|
|
130
|
+
- Заголовок вложен в тулбар вместо своего `<header>`.
|
|
131
|
+
- `qa-dataid` не проставлен на таблицу, строку, ячейки и элементы тулбара.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: admin-nav-item
|
|
3
|
+
kind: pattern
|
|
4
|
+
rule: navigation
|
|
5
|
+
description: Паттерн правила navigation. Брать при заведении пункта меню админки, раздела с панелью или нового адреса раздела — одна декларация на пункт и маршрут, флаг раздела без экрана, вложение адреса, подсказка у недоступного пункта. Не брать для панели правки записи — это паттерн entity-aside.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Пункт меню и адрес раздела
|
|
9
|
+
|
|
10
|
+
Паттерн правила `navigation`. Что при этом должно быть верно — закон
|
|
11
|
+
`docs/constitution/navigation.md`.
|
|
12
|
+
|
|
13
|
+
## Когда брать
|
|
14
|
+
|
|
15
|
+
- Заводится пункт меню админки или раздел с панелью.
|
|
16
|
+
- Появляется новый экран, которому нужен адрес.
|
|
17
|
+
- Пункт надо показать, пока экрана под ним нет.
|
|
18
|
+
|
|
19
|
+
## Одна декларация на пункт и маршрут
|
|
20
|
+
|
|
21
|
+
Декларация меню — данные: адреса, ключи словаря, права и флаг раздела. Живёт в
|
|
22
|
+
`libs/admin/common/container/util` и служит и источником пунктов, и источником гейтинга
|
|
23
|
+
маршрутов. Второе объявление рядом с маршрутами разошлось бы с первым, и получилось бы «пункта
|
|
24
|
+
не видно, а страница открывается».
|
|
25
|
+
|
|
26
|
+
Декларация не импортирует ни один `shell`: иначе граф замкнётся и `npm run check:layers`
|
|
27
|
+
встанет.
|
|
28
|
+
|
|
29
|
+
## Пункт без экрана
|
|
30
|
+
|
|
31
|
+
Объявляется **без прав и без адреса**: право открывает экран, а экрана нет. Виден он при этом
|
|
32
|
+
всем. Появится экран — снимается флаг и добавляются права, больше в объявлении править нечего.
|
|
33
|
+
|
|
34
|
+
Подпись видна, нажатие ничего не делает, подсказка объясняет почему. Носитель подсказки —
|
|
35
|
+
обёртка вокруг кнопки, а сам пункт выключается `aria-disabled`, не нативным `disabled`:
|
|
36
|
+
нативно отключённая кнопка не принимает фокус, и с клавиатуры объяснение недостижимо.
|
|
37
|
+
|
|
38
|
+
К `aria-disabled` обязательно идёт парное правило стилей `[aria-disabled='true']` — браузер
|
|
39
|
+
этот атрибут сам не рисует. Обработчика нажатия у такого пункта нет вовсе.
|
|
40
|
+
|
|
41
|
+
## Адрес повторяет раздел
|
|
42
|
+
|
|
43
|
+
Всё, что стоит в разделе, лежит под его сегментом: экран из «Настроек» — под `/settings`.
|
|
44
|
+
Вложение делается в `apps/admin/src/app/app.routes.ts` через `children` у сегмента раздела;
|
|
45
|
+
`shell` домена монтируется внутрь. Своей либы под раздел не нужно.
|
|
46
|
+
|
|
47
|
+
Подсветка активного раздела считается префиксом адреса, и списка исключений для неё не
|
|
48
|
+
заводится.
|
|
49
|
+
|
|
50
|
+
## Данные домена приходят в шапку токеном
|
|
51
|
+
|
|
52
|
+
Счётчики непрочитанного объявляются интерфейсом и `InjectionToken` в
|
|
53
|
+
`libs/admin/common/container/util`, а связывает токен с реализацией композиционный корень
|
|
54
|
+
(`provideAdminEnvironment`). Права на чужую либу получает только корень — одной строкой в его
|
|
55
|
+
конфиге границ.
|
|
56
|
+
|
|
57
|
+
Признак доходит до кита предикатом по идентификатору пункта, а не своим полем в декларации:
|
|
58
|
+
раздел домена назван идентификатором своего пункта.
|
|
59
|
+
|
|
60
|
+
## Частые промахи
|
|
61
|
+
|
|
62
|
+
- Второе объявление прав рядом с маршрутами.
|
|
63
|
+
- Раздел с панелью, которому дали свой адрес: адрес есть только у пунктов, а раздел виден,
|
|
64
|
+
если виден хотя бы один пункт внутри.
|
|
65
|
+
- Обход одного верхнего ряда при поиске владельца адреса: разделы обходятся вместе с пунктами
|
|
66
|
+
их панелей, иначе вложенный экран остаётся без гейтинга.
|
|
67
|
+
- Подсказка у доступного пункта: она дословно повторяет подпись рядом и не добавляет ничего.
|
|
68
|
+
- `vmPopoverTrigger` не поставлен явно: директива попапа по умолчанию открывается нажатием, и
|
|
69
|
+
два соседних элемента одного ряда ведут себя по-разному.
|
|
70
|
+
- Переезд адреса без правки сквозных спек: они ходят по адресам, и прогон станет красным.
|
|
71
|
+
- Иконка, подобранная «похожая»: отсутствующая добавляется в спрайт и в `<префикс>-icon-names.ts`.
|