Initial SFERA platform baseline
@@ -0,0 +1,25 @@
|
|||||||
|
# Codex Instructions for SFERA
|
||||||
|
|
||||||
|
Путь проекта для Windows-команд: `R:\codex\SFERA`.
|
||||||
|
|
||||||
|
Диск `R:` смонтирован на `\\nas\MST`; используй `R:\codex\SFERA` вместо UNC-пути `\\nas\MST\codex\SFERA`, чтобы Windows/Node/Next не упирались в ограничения сетевого current directory.
|
||||||
|
|
||||||
|
Всегда читай:
|
||||||
|
|
||||||
|
1. `docs/design-system.md`
|
||||||
|
2. `docs/component-architecture.md`
|
||||||
|
3. `docs/codex-ui-guidelines.md`
|
||||||
|
|
||||||
|
Перед созданием UI:
|
||||||
|
- определи бизнес-сущность
|
||||||
|
- выбери стандартный page pattern
|
||||||
|
- проверь наличие базовых компонентов
|
||||||
|
- не создавай новый UI primitive, если есть shadcn/ui компонент
|
||||||
|
- делай маленькие файлы
|
||||||
|
|
||||||
|
После создания UI:
|
||||||
|
- добавь loading/error/empty states
|
||||||
|
- проверь accessibility
|
||||||
|
- проверь responsive
|
||||||
|
- проверь TypeScript
|
||||||
|
- добавь комментарии только там, где они реально помогают
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
description: SFERA UI rules
|
||||||
|
globs:
|
||||||
|
- "src/**/*.tsx"
|
||||||
|
- "src/**/*.ts"
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# SFERA UI Rules
|
||||||
|
|
||||||
|
Use:
|
||||||
|
- Next.js
|
||||||
|
- React
|
||||||
|
- TypeScript
|
||||||
|
- Tailwind
|
||||||
|
- shadcn/ui
|
||||||
|
- lucide-react
|
||||||
|
- TanStack Table
|
||||||
|
- Zod
|
||||||
|
- React Hook Form
|
||||||
|
|
||||||
|
Do not use:
|
||||||
|
- Bootstrap
|
||||||
|
- random colors
|
||||||
|
- inline styles
|
||||||
|
- huge components
|
||||||
|
- business logic inside JSX
|
||||||
|
|
||||||
|
Every page must include:
|
||||||
|
- loading state
|
||||||
|
- error state
|
||||||
|
- empty state
|
||||||
|
- permission state where applicable
|
||||||
|
|
||||||
|
Visual style:
|
||||||
|
- enterprise
|
||||||
|
- minimal
|
||||||
|
- rounded-2xl
|
||||||
|
- soft shadows
|
||||||
|
- clear hierarchy
|
||||||
|
- dark/light ready
|
||||||
|
|
||||||
|
AI actions must show:
|
||||||
|
- selected model
|
||||||
|
- token usage
|
||||||
|
- project/user limits
|
||||||
|
- audit log entry
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.git
|
||||||
|
.pytest_cache
|
||||||
|
.venv
|
||||||
|
**/__pycache__
|
||||||
|
**/*.pyc
|
||||||
|
frontend/sfera-web/.next
|
||||||
|
frontend/sfera-web/node_modules
|
||||||
|
rust/target
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
SFERA_ENV=local
|
||||||
|
SFERA_LOG_LEVEL=INFO
|
||||||
|
# Optional: path to compiled Rust BSL parser executable.
|
||||||
|
# Windows example: rust\target\debug\bsl-parser.exe
|
||||||
|
SFERA_BSL_PARSER=
|
||||||
|
POSTGRES_DSN=postgresql://sfera:sfera@localhost:5432/sfera
|
||||||
|
NEO4J_URI=bolt://docker-test.cin.su:17687
|
||||||
|
NEO4J_USER=neo4j
|
||||||
|
NEO4J_PASSWORD=password
|
||||||
|
QDRANT_URL=http://localhost:6333
|
||||||
|
REDIS_URL=redis://localhost:6379/0
|
||||||
|
|
||||||
|
# Optional local 1C/EDT imports. Do not store infobase passwords here.
|
||||||
|
RUNTIME_ADAPTER_MODE=mock
|
||||||
|
RUNTIME_ADAPTER_URL=http://localhost:8010
|
||||||
|
ONEC_DESIGNER_PATH=C:\Program Files\1cv8\8.5.1.1150\bin\1cv8.exe
|
||||||
|
SFERA_EDT_PROJECTS_PATH=C:\EDT\projects
|
||||||
|
SFERA_UPO_EDT_PATH=C:\EDT\projects\iFCM-UPO\upo\src
|
||||||
|
SFERA_UPO_INFOBASE='Srvr="192.168.200.95";Ref="upo";'
|
||||||
|
|
||||||
|
# Optional official 1C documentation access. Put real credentials only in .env.local.
|
||||||
|
SFERA_ITS_URL=https://its.1c.ru/db/v838doc#browse:13:-1:7
|
||||||
|
SFERA_ITS_USERNAME=<set locally>
|
||||||
|
SFERA_ITS_PASSWORD=<set locally>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
python:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: astral-sh/setup-uv@v4
|
||||||
|
- run: uv sync --all-packages
|
||||||
|
- run: uv run ruff check .
|
||||||
|
- run: uv run mypy packages services || true
|
||||||
|
- run: uv run pytest packages/sir/tests
|
||||||
|
|
||||||
|
rust:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- run: cd rust && cargo test
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
.venv/
|
||||||
|
__pycache__/
|
||||||
|
*.egg-info/
|
||||||
|
.pytest_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
target/
|
||||||
|
node_modules/
|
||||||
|
.next/
|
||||||
|
*.tsbuildinfo
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
.sfera/
|
||||||
|
tmp/
|
||||||
|
tmp-*/
|
||||||
|
api_server_diag.py
|
||||||
|
*.pyc
|
||||||
|
*.log
|
||||||
|
*smoke-debug.png
|
||||||
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# AGENTS.md instructions for SFERA
|
||||||
|
|
||||||
|
## Shared Test Docker Host
|
||||||
|
|
||||||
|
- Test and stand verification must be done on the shared Docker host, not on a local Docker Engine.
|
||||||
|
- Use SSH alias `test-docker` / `docker-test`.
|
||||||
|
- Host: `docker-test.cin.su` (`192.168.200.61`).
|
||||||
|
- SSH user: `test`.
|
||||||
|
- Preferred Docker endpoint when Docker CLI is available: `ssh://test-docker`.
|
||||||
|
- Deploy both backend/server services and frontend services on `docker-test` for integrated testing.
|
||||||
|
- Portainer: `http://docker-test.cin.su:9000/`, user `admin`.
|
||||||
|
- Do not store the password in repositories or project files; use an SSH key for persistent access.
|
||||||
|
|
||||||
|
## Local Workspace Path
|
||||||
|
|
||||||
|
- The project is available locally at `Z:\codex\SFERA`.
|
||||||
|
- `Z:\codex\SFERA` is a mapped network folder for `\\nas\MST\codex\SFERA`.
|
||||||
|
- Prefer `Z:\codex\SFERA` for Windows tooling and frontend commands.
|
||||||
|
- Do not fall back to UNC current directories for npm/cmd workflows; Windows `cmd.exe` does not support UNC current directories reliably.
|
||||||
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# Codex Instructions for SFERA
|
||||||
|
|
||||||
|
Ты реализуешь SFERA по шагам. Не перескакивай к AI и UI, пока не работает semantic core.
|
||||||
|
|
||||||
|
## Абсолютные правила
|
||||||
|
|
||||||
|
1. Не писать autonomous code generation до готового SIR + parser + graph.
|
||||||
|
2. Каждый parser bug превращать в golden fixture.
|
||||||
|
3. Не писать напрямую в Neo4j вне `projection-engine`.
|
||||||
|
4. Все изменения в будущем должны быть связаны с task/session/user, но в Phase 1 можно оставить placeholders.
|
||||||
|
5. Русский UI и команды по умолчанию, но должен быть выбор английского интерфейса/команд; internal models — English.
|
||||||
|
6. BSL parser обязан поддерживать смешанный русский/английский синтаксис 1С в одном тексте.
|
||||||
|
7. Любые integration/security/agent слои делать только после core.
|
||||||
|
|
||||||
|
## Test stand and workspace
|
||||||
|
|
||||||
|
- Тестирование интегрированного проекта проводить на `docker-test` / `test-docker`, а не на локальном Docker Engine.
|
||||||
|
- На `docker-test` разворачивать обе части: backend/server services и frontend.
|
||||||
|
- Docker endpoint: `ssh://test-docker`.
|
||||||
|
- Host: `docker-test.cin.su` (`192.168.200.61`), SSH user: `test`.
|
||||||
|
- Portainer: `http://docker-test.cin.su:9000/`, user `admin`; пароль не сохранять в репозитории и проектных файлах.
|
||||||
|
- Локальный рабочий путь проекта: `Z:\codex\SFERA`.
|
||||||
|
- `Z:\codex\SFERA` — подмонтированная сетевая папка `\\nas\MST\codex\SFERA`.
|
||||||
|
- Для Windows/npm/frontend команд использовать `Z:\codex\SFERA`, не UNC current directory.
|
||||||
|
|
||||||
|
## Frontend contract
|
||||||
|
|
||||||
|
Перед любым изменением frontend:
|
||||||
|
|
||||||
|
1. Прочитать `docs/frontend/SFERA_FRONTEND_PRODUCT_CONTRACT.md`.
|
||||||
|
2. Прочитать `docs/frontend/SFERA_IDE_UI_CONTRACT.md`.
|
||||||
|
3. Если меняется дерево 1С - прочитать `docs/frontend/SFERA_METADATA_TREE_CONTRACT.md`.
|
||||||
|
4. Если меняются настройки проекта - прочитать `docs/frontend/SFERA_PROJECT_SETTINGS_CONTRACT.md`.
|
||||||
|
5. Если контракт устарел - сначала обновить контракт, затем код.
|
||||||
|
6. Все UI-изменения фиксировать в `docs/frontend/SFERA_FRONTEND_CHANGELOG.md`.
|
||||||
|
|
||||||
|
Не ломать принятую модель: SFERA = metadata-first semantic configurator for 1C, основной экран = IDE последнего проекта, проект выбирается сверху, левая панель = дерево текущего проекта, основная конфигурация и расширения = configuration-like roots одного уровня, центр = рабочая область, правая панель = контекстные свойства, низ = открытые объекты, tools и status.
|
||||||
|
|
||||||
|
Для 1C-specific поведения использовать official 1C docs через ITS/v8.1c.ru/1C DN или локальные knowledge packs. ITS credentials брать только из `.env.local`; реальные credentials не коммитить, не писать в markdown/Dockerfile и не выводить в logs.
|
||||||
|
|
||||||
|
## Текущий приоритет
|
||||||
|
|
||||||
|
Реализовать Phase 1:
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/sir
|
||||||
|
rust/crates/bsl-parser
|
||||||
|
packages/semantic-kernel
|
||||||
|
packages/projection-engine
|
||||||
|
packages/incremental-indexer
|
||||||
|
```
|
||||||
|
|
||||||
|
## Стиль кода
|
||||||
|
|
||||||
|
- Python 3.12+.
|
||||||
|
- Pydantic v2.
|
||||||
|
- Async где есть IO.
|
||||||
|
- Rust parser сначала простой и детерминированный.
|
||||||
|
- Тесты обязательны.
|
||||||
|
- Минимальная магия.
|
||||||
|
|
||||||
|
## Definition of Done Phase 1
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. BSL procedures extracted.
|
||||||
|
2. Calls extracted.
|
||||||
|
3. Queries extracted.
|
||||||
|
4. Writes extracted.
|
||||||
|
5. SIR snapshot validates.
|
||||||
|
6. Neo4j projection works.
|
||||||
|
7. Incremental update works on changed file.
|
||||||
|
```
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# SFERA — полный анализ проекта для Codex
|
||||||
|
|
||||||
|
## Что строим
|
||||||
|
|
||||||
|
SFERA — серверная semantic SDLC платформа для 1С:
|
||||||
|
|
||||||
|
- semantic graph 1С-конфигурации;
|
||||||
|
- полноценная IDE-среда для ручной и AI-assisted разработки 1С;
|
||||||
|
- object-level versioning вместо обязательного Git;
|
||||||
|
- task-linked изменения;
|
||||||
|
- review/impact/runtime intelligence;
|
||||||
|
- knowledge-aware AI, который умеет анализировать, писать и изменять 1С-код и metadata;
|
||||||
|
- агенты EPF/CFE;
|
||||||
|
- marketplace/download center;
|
||||||
|
- многопользовательская серверная консоль.
|
||||||
|
|
||||||
|
## Продуктовая формула
|
||||||
|
|
||||||
|
```text
|
||||||
|
SIR + Lineage + Object Versioning + Runtime Overlay + Knowledge Base + Collaboration
|
||||||
|
```
|
||||||
|
|
||||||
|
Расширенная формула продукта:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Semantic Core + 1C IDE + AI Pair Programmer + Object/Form Designer + Guarded Apply
|
||||||
|
```
|
||||||
|
|
||||||
|
## Что не делаем в начале
|
||||||
|
|
||||||
|
- автоприменение изменений в production;
|
||||||
|
- автономное применение AI-изменений без preview/diff/approval;
|
||||||
|
- полный live debugger;
|
||||||
|
- сложную marketplace-экосистему;
|
||||||
|
- heavy frontend до ядра.
|
||||||
|
|
||||||
|
## IDE и authoring стратегия
|
||||||
|
|
||||||
|
SFERA должна уметь всё, что ожидается от современной IDE для 1С, но опираясь на semantic graph и структуру конфигурации:
|
||||||
|
|
||||||
|
- ручное редактирование BSL-кода с подсветкой, диагностикой, навигацией, поиском ссылок и refactoring;
|
||||||
|
- AI autocomplete и продолжение кода с учётом текущей процедуры, локальных переменных, параметров, доступных реквизитов, табличных частей, форм, команд, ролей и связей объекта;
|
||||||
|
- AI generation для процедур, функций, обработчиков команд, запросов, движений регистров и безопасных шаблонов 1С;
|
||||||
|
- создание и изменение объектов 1С: документы, справочники, регистры, общие модули, реквизиты, табличные части, команды, формы и отчёты;
|
||||||
|
- visual/object designer для metadata, форм, команд, реквизитов, табличных частей и отчётов;
|
||||||
|
- preview/diff всех изменений перед применением;
|
||||||
|
- guarded apply: проверка impact, прав, privacy, review findings, style rules и AI policy до записи изменений;
|
||||||
|
- AI объясняет, почему предлагает именно такой код, какие объекты будут затронуты и какие риски есть.
|
||||||
|
|
||||||
|
## Что берём из 1С Конфигуратора
|
||||||
|
|
||||||
|
SFERA не копирует старый интерфейс Конфигуратора, но сохраняет его сильную рабочую модель, знакомую 1С-разработчикам:
|
||||||
|
|
||||||
|
- дерево конфигурации как основной навигатор по метаданным, модулям, формам, реквизитам, командам, ролям и регистрам;
|
||||||
|
- отдельные рабочие режимы для модуля, формы, реквизитов/табличных частей, команд, свойств, событий и обработчиков;
|
||||||
|
- вкладки открытых объектов и быстрый переход между модулем объекта, модулем формы, дизайнером формы, свойствами и событиями;
|
||||||
|
- правый инспектор свойств/событий, который меняет содержимое по выбранному объекту или элементу формы;
|
||||||
|
- нижние панели проблем, ссылок, output, preview, diff и статуса выполнения;
|
||||||
|
- поиск по дереву, объектам, процедурам, событиям, формам и документации.
|
||||||
|
|
||||||
|
Поверх этой модели SFERA добавляет то, чего нет в классическом Конфигураторе как единой среды:
|
||||||
|
|
||||||
|
- object-level версии и rollback для каждого изменения;
|
||||||
|
- semantic diff, impact analysis и guarded apply перед записью;
|
||||||
|
- документацию проекта, vendor/BSP docs, базу знаний, паттерны команды и историю решений прямо в IDE;
|
||||||
|
- обучение и подсказки для разработчиков по текущему объекту, коду и стандартам команды;
|
||||||
|
- AI pair programmer, который умеет читать контекст 1С, писать код, создавать объекты/формы/отчёты и объяснять риски;
|
||||||
|
- task/session binding, audit trail, права доступа, privacy policy и учёт AI token/cost impact.
|
||||||
|
|
||||||
|
## Первый технический proof
|
||||||
|
|
||||||
|
```text
|
||||||
|
BSL file
|
||||||
|
↓
|
||||||
|
Rust parser
|
||||||
|
↓
|
||||||
|
SIR Snapshot
|
||||||
|
↓
|
||||||
|
Neo4j graph
|
||||||
|
↓
|
||||||
|
find_callers / find_callees
|
||||||
|
```
|
||||||
|
|
||||||
|
## Языковая стратегия
|
||||||
|
|
||||||
|
- UI по умолчанию русский.
|
||||||
|
- В интерфейсе и командах русский язык используется по умолчанию.
|
||||||
|
- Пользователь должен иметь возможность выбрать английский язык интерфейса и английский вариант написания команд.
|
||||||
|
- Внутренний код/модели — английский.
|
||||||
|
- BSL parser обязан понимать русские и английские ключевые слова: `Процедура/Procedure`, `Функция/Function`, `КонецПроцедуры/EndProcedure` и т.д.
|
||||||
|
- В одном BSL-тексте 1С допустима смесь русских и английских ключевых слов/команд; SFERA обязана это поддерживать.
|
||||||
|
|
||||||
|
## Git strategy
|
||||||
|
|
||||||
|
Git не является обязательным source of truth. История SFERA хранится в Semantic Object Version Store. Git — только optional import/export adapter.
|
||||||
@@ -0,0 +1,726 @@
|
|||||||
|
# SFERA Platform
|
||||||
|
|
||||||
|
**SFERA — Semantic Operating Platform for 1C Ecosystems**
|
||||||
|
|
||||||
|
SFERA — enterprise semantic platform для анализа, понимания, индексирования, визуализации и AI-оркестрации экосистем 1С.
|
||||||
|
|
||||||
|
SFERA также является современной IDE/authoring-средой для 1С: пользователь должен уметь вручную писать код, создавать и менять объекты, формы, команды и отчёты, а AI должен помогать как pair programmer, который видит текущий код, metadata, связи объектов, доступные переменные и правила платформы.
|
||||||
|
|
||||||
|
Платформа строит детерминированное semantic core ядро поверх:
|
||||||
|
- 1C BSL
|
||||||
|
- XML metadata
|
||||||
|
- CF/CFE
|
||||||
|
- integrations
|
||||||
|
- access topology
|
||||||
|
- UI semantics
|
||||||
|
- scheduled jobs
|
||||||
|
- object dependencies
|
||||||
|
- runtime graph
|
||||||
|
|
||||||
|
SFERA проектируется как:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Enterprise AI Operating System
|
||||||
|
for 1C ecosystems
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Core Philosophy
|
||||||
|
|
||||||
|
```text
|
||||||
|
Semantic truth first.
|
||||||
|
AI later.
|
||||||
|
```
|
||||||
|
|
||||||
|
AI не является источником истины.
|
||||||
|
|
||||||
|
Сначала:
|
||||||
|
- deterministic parsing
|
||||||
|
- semantic graph
|
||||||
|
- metadata topology
|
||||||
|
- impact analysis
|
||||||
|
- dependency resolution
|
||||||
|
- integration discovery
|
||||||
|
- access analysis
|
||||||
|
|
||||||
|
И только потом:
|
||||||
|
- AI copilots
|
||||||
|
- AI review
|
||||||
|
- AI reasoning
|
||||||
|
- AI onboarding
|
||||||
|
- AI architecture analysis
|
||||||
|
- AI migration planning
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# High-Level Architecture
|
||||||
|
|
||||||
|
```text
|
||||||
|
1C BSL/XML/CF/CFE
|
||||||
|
↓
|
||||||
|
Rust BSL Parser
|
||||||
|
↓
|
||||||
|
SIR Snapshot
|
||||||
|
↓
|
||||||
|
Semantic Kernel
|
||||||
|
↓
|
||||||
|
Neo4j Semantic Graph
|
||||||
|
↓
|
||||||
|
Incremental Indexing
|
||||||
|
↓
|
||||||
|
Impact Analysis
|
||||||
|
↓
|
||||||
|
AI Operating Layer
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Main Goals
|
||||||
|
|
||||||
|
## Semantic Understanding of 1C
|
||||||
|
|
||||||
|
SFERA должна понимать:
|
||||||
|
|
||||||
|
- объекты 1С
|
||||||
|
- формы
|
||||||
|
- команды
|
||||||
|
- реквизиты
|
||||||
|
- табличные части
|
||||||
|
- роли
|
||||||
|
- права доступа
|
||||||
|
- BSL dependencies
|
||||||
|
- integrations
|
||||||
|
- scheduled jobs
|
||||||
|
- runtime topology
|
||||||
|
- object impact
|
||||||
|
- UI semantics
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1C IDE and Authoring
|
||||||
|
|
||||||
|
SFERA должна давать возможности современной IDE для 1С:
|
||||||
|
|
||||||
|
- BSL editor: подсветка, диагностика, folding, outline, go to definition, find references, rename, extract method и безопасные refactoring actions.
|
||||||
|
- Semantic autocomplete: продолжение кода с учётом текущей процедуры, параметров, локальных переменных, реквизитов объекта, табличных частей, форм, команд, ролей, интеграций и доступных методов 1С.
|
||||||
|
- AI pair programmer: генерация процедур, функций, запросов, обработчиков команд, движений регистров, проверок заполнения и обработчиков форм.
|
||||||
|
- Object designer: создание и изменение документов, справочников, регистров, общих модулей, реквизитов, табличных частей, команд и форм.
|
||||||
|
- Form/report designer: работа с формами, элементами, командами, обработчиками и отчётами в visual/object-oriented интерфейсе.
|
||||||
|
- Diff/preview/apply: любое AI- или ручное изменение проходит через preview, semantic diff, impact analysis, review и подтверждение.
|
||||||
|
- Context-aware hints: подсказки не просто по словам, а по текущему объекту 1С, доступным данным, связям, query/write context и runtime/knowledge facts.
|
||||||
|
|
||||||
|
AI не ограничивается анализом. Он должен уметь писать код и предлагать структурные изменения, но SFERA обязана показывать последствия и держать контроль применения у пользователя.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Enterprise AI Layer
|
||||||
|
|
||||||
|
Поверх semantic graph строится AI operating layer:
|
||||||
|
|
||||||
|
- AI code completion
|
||||||
|
- AI code generation
|
||||||
|
- AI object/form/report generation
|
||||||
|
- AI guarded refactoring
|
||||||
|
- AI code review
|
||||||
|
- AI impact analysis
|
||||||
|
- AI onboarding
|
||||||
|
- AI architecture assistant
|
||||||
|
- AI dependency explorer
|
||||||
|
- AI migration assistant
|
||||||
|
- AI semantic search
|
||||||
|
- AI documentation generation
|
||||||
|
- AI risk analysis
|
||||||
|
- AI integration analysis
|
||||||
|
|
||||||
|
AI должен работать поверх semantic truth: перед предложением кода он учитывает текущий BSL-контекст, AST/SIR, metadata object, форму, доступные реквизиты, табличные части, команды, роли, запросы, регистры, интеграции, knowledge records и privacy policy.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1C Knowledge Coverage
|
||||||
|
|
||||||
|
`GET /projects/{project_id}/knowledge/schema-coverage` показывает покрытие knowledge-records для документов, справочников, реквизитов и табличных частей.
|
||||||
|
|
||||||
|
`GET /projects/{project_id}/review` добавляет INFO `Missing 1C schema knowledge`, если узел схемы 1С не связан ни с одной knowledge-записью.
|
||||||
|
|
||||||
|
`POST /knowledge/packs` импортирует BSP/vendor documentation pack как набор `KnowledgeRecord` с тегами `pack:{pack_id}` и `vendor:{vendor}`. `GET /knowledge/packs` показывает установленные пакеты знаний.
|
||||||
|
|
||||||
|
`GET /projects/{project_id}/patterns` выполняет детерминированный pattern mining по SIR: повторяющиеся чтения таблиц, записи таблиц и совпадающие read/write формы процедур.
|
||||||
|
|
||||||
|
## 1C Ownership
|
||||||
|
|
||||||
|
`POST /projects/{project_id}/comments` добавляет обсуждение к `target_id` внутри проекта, а `GET /projects/{project_id}/comments/{target_id}` возвращает комментарии по конкретному объекту, задаче или lineage.
|
||||||
|
|
||||||
|
`POST /projects/{project_id}/ownership` назначает ответственного на 1С-объект по `lineage_id`.
|
||||||
|
|
||||||
|
`GET /projects/{project_id}/objects/ownership/{object_name}` возвращает владельцев документа, справочника, регистра, общего модуля и других корневых объектов 1С.
|
||||||
|
|
||||||
|
`GET /projects/{project_id}/review` добавляет INFO `Missing 1C object owner` для 1С-объектов без назначенного владельца, а `GET /projects/{project_id}/report` включает `ownership_count`, `unowned_object_count` и `unowned_objects`.
|
||||||
|
|
||||||
|
## 1C Privacy
|
||||||
|
|
||||||
|
`POST /projects/{project_id}/privacy/markers` назначает privacy-классификацию на `lineage_id`: `PUBLIC`, `INTERNAL`, `CONFIDENTIAL`, `PERSONAL_DATA`, `SECRET`.
|
||||||
|
|
||||||
|
`GET /projects/{project_id}/objects/privacy/{object_name}` возвращает privacy-маркеры самого 1С-объекта и его прямых реквизитов/табличных частей/форм.
|
||||||
|
|
||||||
|
`GET /projects/{project_id}/review` добавляет INFO `Unclassified sensitive 1C field` для реквизитов с чувствительными именами вроде ИНН, паспорт, телефон, email, адрес, если они ещё не классифицированы.
|
||||||
|
|
||||||
|
## AI Usage Governance
|
||||||
|
|
||||||
|
`POST /ai/usage` записывает факт AI-действия: проект, пользователь, модель, операция, prompt/completion токены и стоимость.
|
||||||
|
|
||||||
|
`GET /ai/usage/summary` агрегирует AI usage по проекту, пользователю, модели и операции. `GET /ai/policy` показывает текущий token limit и остаток для пользователя.
|
||||||
|
|
||||||
|
`GET /projects/{project_id}/report` включает `ai_usage_request_count`, `ai_usage_total_tokens` и `ai_usage_cost`.
|
||||||
|
|
||||||
|
`POST /projects/{project_id}/ai/answer-policy` проверяет, можно ли отвечать на AI-вопрос по выбранному 1С-контексту: учитывает token budget, knowledge records, privacy markers и запрет external model calls.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Monorepo Structure
|
||||||
|
|
||||||
|
```text
|
||||||
|
sfera-platform/
|
||||||
|
|
||||||
|
packages/
|
||||||
|
bsl-parser-rs/
|
||||||
|
sir/
|
||||||
|
semantic-kernel/
|
||||||
|
neo4j-projection/
|
||||||
|
indexing/
|
||||||
|
integrations/
|
||||||
|
api/
|
||||||
|
ai/
|
||||||
|
|
||||||
|
frontend/
|
||||||
|
sfera-web/
|
||||||
|
|
||||||
|
docs/
|
||||||
|
architecture/
|
||||||
|
frontend/
|
||||||
|
operations/
|
||||||
|
ai/
|
||||||
|
prompts/
|
||||||
|
|
||||||
|
.codex/
|
||||||
|
.cursor/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Technology Stack
|
||||||
|
|
||||||
|
## Backend
|
||||||
|
|
||||||
|
```text
|
||||||
|
Python
|
||||||
|
FastAPI
|
||||||
|
Rust
|
||||||
|
Neo4j
|
||||||
|
PostgreSQL
|
||||||
|
Pydantic
|
||||||
|
NetworkX
|
||||||
|
asyncio
|
||||||
|
uv
|
||||||
|
```
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
```text
|
||||||
|
Next.js
|
||||||
|
React
|
||||||
|
TypeScript
|
||||||
|
Tailwind CSS
|
||||||
|
shadcn/ui
|
||||||
|
TanStack Table
|
||||||
|
TanStack Query
|
||||||
|
Zustand
|
||||||
|
Framer Motion
|
||||||
|
Recharts / ECharts
|
||||||
|
```
|
||||||
|
|
||||||
|
## AI Layer
|
||||||
|
|
||||||
|
```text
|
||||||
|
OpenAI-compatible APIs
|
||||||
|
Local LLM support
|
||||||
|
Multi-model routing
|
||||||
|
AI policy engine
|
||||||
|
AI audit system
|
||||||
|
Context orchestration
|
||||||
|
Token accounting
|
||||||
|
Semantic AI routing
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Quick Start
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
uv sync --all-packages
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pytest packages/sir/tests
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run Rust parser
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo run -p bsl-parser -- ../tests/golden/english_module.bsl
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Development Philosophy
|
||||||
|
|
||||||
|
SFERA строится как:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Deterministic semantic platform first.
|
||||||
|
AI-enhanced operating system second.
|
||||||
|
```
|
||||||
|
|
||||||
|
Главный приоритет:
|
||||||
|
- reproducibility
|
||||||
|
- deterministic parsing
|
||||||
|
- semantic correctness
|
||||||
|
- graph consistency
|
||||||
|
- auditability
|
||||||
|
- incremental scalability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Semantic Intermediate Representation (SIR)
|
||||||
|
|
||||||
|
Rust parser возвращает deterministic JSON contract:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"procedures": [],
|
||||||
|
"calls": [],
|
||||||
|
"queries": [],
|
||||||
|
"writes": [],
|
||||||
|
"diagnostics": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
SIR является semantic truth snapshot проекта.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Supported 1C Metadata
|
||||||
|
|
||||||
|
## Core metadata objects
|
||||||
|
|
||||||
|
```text
|
||||||
|
Catalog
|
||||||
|
Document
|
||||||
|
Register
|
||||||
|
CommonModule
|
||||||
|
ExchangePlan
|
||||||
|
ScheduledJob
|
||||||
|
BusinessProcess
|
||||||
|
Task
|
||||||
|
Role
|
||||||
|
Form
|
||||||
|
Command
|
||||||
|
Attribute
|
||||||
|
TabularSection
|
||||||
|
Element
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Semantic Graph Relations
|
||||||
|
|
||||||
|
## Main graph relations
|
||||||
|
|
||||||
|
```text
|
||||||
|
CALLS
|
||||||
|
WRITES
|
||||||
|
READS
|
||||||
|
USES_INTEGRATION
|
||||||
|
HANDLES
|
||||||
|
CONTAINS
|
||||||
|
HAS_FORM
|
||||||
|
HAS_COMMAND
|
||||||
|
HAS_ATTRIBUTE
|
||||||
|
HAS_TABULAR_SECTION
|
||||||
|
HAS_ROLE
|
||||||
|
HAS_ELEMENT
|
||||||
|
RUNS
|
||||||
|
GRANTS_ACCESS
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Object Impact Analysis
|
||||||
|
|
||||||
|
SFERA умеет строить object-level impact:
|
||||||
|
|
||||||
|
- реквизиты
|
||||||
|
- табличные части
|
||||||
|
- формы
|
||||||
|
- команды
|
||||||
|
- BSL handlers
|
||||||
|
- registers
|
||||||
|
- integrations
|
||||||
|
- scheduled jobs
|
||||||
|
- roles/access
|
||||||
|
- UI semantics
|
||||||
|
- cross-module dependencies
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Incremental Indexing
|
||||||
|
|
||||||
|
SFERA поддерживает incremental semantic updates.
|
||||||
|
|
||||||
|
Изменение:
|
||||||
|
- `.bsl`
|
||||||
|
- `.xml`
|
||||||
|
- metadata object
|
||||||
|
- forms
|
||||||
|
- handlers
|
||||||
|
|
||||||
|
перестраивает только affected semantic graph sections.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Neo4j Projection
|
||||||
|
|
||||||
|
Semantic graph может быть выгружен в Neo4j:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SIR Snapshot
|
||||||
|
↓
|
||||||
|
Neo4j Projection
|
||||||
|
↓
|
||||||
|
Cypher Queries
|
||||||
|
↓
|
||||||
|
Graph Analytics
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Integration Topology
|
||||||
|
|
||||||
|
SFERA извлекает integrations из:
|
||||||
|
|
||||||
|
- HTTPConnection
|
||||||
|
- HTTPСоединение
|
||||||
|
- WSProxy
|
||||||
|
- FTPConnection
|
||||||
|
- COMObject
|
||||||
|
- ExchangePlan
|
||||||
|
- URL strings
|
||||||
|
- external services
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Scheduled Jobs
|
||||||
|
|
||||||
|
Регламентные задания индексируются как runtime semantic graph:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ScheduledJob
|
||||||
|
RUNS
|
||||||
|
Procedure
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Access Model
|
||||||
|
|
||||||
|
Для ролей 1С извлекаются:
|
||||||
|
|
||||||
|
- object permissions
|
||||||
|
- rights
|
||||||
|
- grants
|
||||||
|
- access topology
|
||||||
|
|
||||||
|
Graph relation:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Role GRANTS_ACCESS Object
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# UI Semantics
|
||||||
|
|
||||||
|
SFERA анализирует UI layer:
|
||||||
|
|
||||||
|
- forms
|
||||||
|
- commands
|
||||||
|
- command handlers
|
||||||
|
- form elements
|
||||||
|
- UI actions
|
||||||
|
- BSL bindings
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# API Examples
|
||||||
|
|
||||||
|
## Object impact
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /projects/{project_id}/objects/impact/{object_name}
|
||||||
|
```
|
||||||
|
|
||||||
|
## UI semantics
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /projects/{project_id}/objects/ui/{object_name}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integrations
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /projects/{project_id}/integrations
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scheduled jobs
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /projects/{project_id}/jobs/scheduled
|
||||||
|
```
|
||||||
|
|
||||||
|
## Access graph
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /projects/{project_id}/access/roles/{role_name}/objects
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Frontend Philosophy
|
||||||
|
|
||||||
|
SFERA UI — не обычная CRM.
|
||||||
|
|
||||||
|
Интерфейс должен ощущаться как:
|
||||||
|
|
||||||
|
- Linear
|
||||||
|
- Stripe Dashboard
|
||||||
|
- Notion
|
||||||
|
- Attio
|
||||||
|
- Plane
|
||||||
|
- Enterprise AI Workspace
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Frontend Stack
|
||||||
|
|
||||||
|
```text
|
||||||
|
Next.js
|
||||||
|
React
|
||||||
|
TypeScript
|
||||||
|
Tailwind CSS
|
||||||
|
shadcn/ui
|
||||||
|
TanStack Table
|
||||||
|
Framer Motion
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Enterprise UI Principles
|
||||||
|
|
||||||
|
## Main principles
|
||||||
|
|
||||||
|
- clean enterprise minimalism
|
||||||
|
- dark/light mode
|
||||||
|
- modular workspace
|
||||||
|
- AI-native UX
|
||||||
|
- semantic navigation
|
||||||
|
- adaptive layouts
|
||||||
|
- contextual side panels
|
||||||
|
- command palette
|
||||||
|
- realtime analytics
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# AI-Assisted Development
|
||||||
|
|
||||||
|
Проект проектируется для работы через:
|
||||||
|
|
||||||
|
- Codex
|
||||||
|
- Cursor
|
||||||
|
- v0
|
||||||
|
- AI code review
|
||||||
|
- AI UI generation
|
||||||
|
- AI semantic assistants
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Codex Workflow
|
||||||
|
|
||||||
|
В репозитории присутствуют:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.codex/
|
||||||
|
.cursor/
|
||||||
|
docs/design-system.md
|
||||||
|
docs/component-architecture.md
|
||||||
|
docs/codex-ui-guidelines.md
|
||||||
|
prompts/
|
||||||
|
```
|
||||||
|
|
||||||
|
Codex обязан:
|
||||||
|
- соблюдать architecture rules
|
||||||
|
- соблюдать design system
|
||||||
|
- генерировать production-ready TypeScript
|
||||||
|
- использовать reusable components
|
||||||
|
- учитывать AI limits/audit/token usage
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Frontend Design System
|
||||||
|
|
||||||
|
Frontend design system основан на:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Tailwind CSS
|
||||||
|
shadcn/ui
|
||||||
|
Radix UI
|
||||||
|
Design Tokens
|
||||||
|
Enterprise Layout Rules
|
||||||
|
```
|
||||||
|
|
||||||
|
Основной принцип:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Enterprise AI Operating System
|
||||||
|
instead of legacy CRM UI
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# AI Operating Layer
|
||||||
|
|
||||||
|
Будущие AI возможности:
|
||||||
|
|
||||||
|
- AI semantic copilots
|
||||||
|
- AI impact prediction
|
||||||
|
- AI migration planning
|
||||||
|
- AI documentation generation
|
||||||
|
- AI integration analysis
|
||||||
|
- AI security review
|
||||||
|
- AI onboarding assistant
|
||||||
|
- AI dependency graph reasoning
|
||||||
|
- AI runtime diagnostics
|
||||||
|
- AI topology explorer
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Infrastructure
|
||||||
|
|
||||||
|
Docker Engine локально для development stand не обязателен.
|
||||||
|
|
||||||
|
Общий infrastructure host:
|
||||||
|
|
||||||
|
```text
|
||||||
|
docker-test
|
||||||
|
test-docker
|
||||||
|
```
|
||||||
|
|
||||||
|
Infrastructure documentation:
|
||||||
|
|
||||||
|
```text
|
||||||
|
docs/operations/STAND_RUNBOOK.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# First Demo Target
|
||||||
|
|
||||||
|
```bsl
|
||||||
|
Процедура Проведение()
|
||||||
|
ПроверитьОстатки();
|
||||||
|
Движения.ОстаткиТоваров.Записать();
|
||||||
|
КонецПроцедуры
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected semantic graph:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Проведение CALLS ПроверитьОстатки
|
||||||
|
Проведение WRITES РегистрНакопления.ОстаткиТоваров
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Long-Term Vision
|
||||||
|
|
||||||
|
SFERA — это не просто analyzer.
|
||||||
|
|
||||||
|
Цель проекта:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Semantic Operating System
|
||||||
|
for enterprise 1C ecosystems
|
||||||
|
```
|
||||||
|
|
||||||
|
Где:
|
||||||
|
- semantic graph
|
||||||
|
- runtime topology
|
||||||
|
- integrations
|
||||||
|
- access model
|
||||||
|
- UI semantics
|
||||||
|
- AI reasoning
|
||||||
|
- enterprise workflows
|
||||||
|
- impact analysis
|
||||||
|
|
||||||
|
становятся единой operating platform.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Core Principles
|
||||||
|
|
||||||
|
```text
|
||||||
|
Deterministic.
|
||||||
|
Semantic.
|
||||||
|
Incremental.
|
||||||
|
Observable.
|
||||||
|
AI-Ready.
|
||||||
|
Enterprise-Scale.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Future Roadmap
|
||||||
|
|
||||||
|
## Phase 1
|
||||||
|
|
||||||
|
- Rust parser
|
||||||
|
- SIR
|
||||||
|
- semantic graph
|
||||||
|
- Neo4j projection
|
||||||
|
- incremental indexing
|
||||||
|
|
||||||
|
## Phase 2
|
||||||
|
|
||||||
|
- semantic APIs
|
||||||
|
- integrations topology
|
||||||
|
- access graph
|
||||||
|
- UI semantics
|
||||||
|
|
||||||
|
## Phase 3
|
||||||
|
|
||||||
|
- enterprise frontend
|
||||||
|
- AI copilots
|
||||||
|
- semantic search
|
||||||
|
- AI review
|
||||||
|
|
||||||
|
## Phase 4
|
||||||
|
|
||||||
|
- distributed indexing
|
||||||
|
- multi-project graph
|
||||||
|
- semantic federation
|
||||||
|
- AI orchestration
|
||||||
|
- autonomous semantic agents
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# 1C Metadata Object Catalog
|
||||||
|
|
||||||
|
This catalog is the product source of truth for the 1C metadata tree. It is backed by the official EDT mdclass metamodel and exposed by `/metadata/catalog`.
|
||||||
|
|
||||||
|
Primary sources:
|
||||||
|
|
||||||
|
- EDT mdclass package: https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/package-summary.html
|
||||||
|
- EDT HTTPService: https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/HTTPService.html
|
||||||
|
- 1C HTTP services guide: https://1c-dn.com/1c_enterprise/http_services/
|
||||||
|
|
||||||
|
Root configuration objects are maintained in `packages/one-c-normalizer/src/one_c_normalizer/metadata_catalog.py` as `METADATA_TYPE_SPECS` plus descriptions in `METADATA_TYPE_DESCRIPTIONS`.
|
||||||
|
|
||||||
|
Child metadata elements are maintained in the same module as `METADATA_CHILD_OBJECT_SPECS`.
|
||||||
|
|
||||||
|
Important documented structures:
|
||||||
|
|
||||||
|
- HTTP service: HTTP service -> URL templates -> methods -> module.
|
||||||
|
- Web service: Web service -> operations -> parameters -> module.
|
||||||
|
- Integration service: Integration service -> channels -> messages -> module.
|
||||||
|
- Registers: register -> dimensions -> resources -> requisites -> forms -> commands -> templates -> rights -> record set/manager modules.
|
||||||
|
- Catalogs/plans/documents: object -> requisites -> tabular sections -> forms -> commands -> templates -> rights -> modules, with type-specific groups such as movements or predefined data.
|
||||||
@@ -0,0 +1,411 @@
|
|||||||
|
# Структура объектов метаданных 1С для дерева SFERA
|
||||||
|
|
||||||
|
Дата фиксации: 2026-05-09.
|
||||||
|
|
||||||
|
Назначение документа: единая опорная модель для загрузчика метаданных из 1С и дерева SFERA IDE. Реальные объекты, имена и состав узлов должны приходить из выгрузки конфигурации 1С/SIR. В коде интерфейса допустимо хранить только типы объектов, правила группировки, иконки и шаблоны подчинённых узлов.
|
||||||
|
|
||||||
|
## Источники
|
||||||
|
|
||||||
|
- 1C:Enterprise 8.3.23 Developer Guide, "Configuration objects": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.2._Configuration_objects/
|
||||||
|
- 1C:Enterprise 8.3.23 Developer Guide, "The concept of configuration": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.1._The_concept_of__configuration_/
|
||||||
|
- 1C:Enterprise 8.3.23 Developer Guide, "Modules": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.5._Modules/
|
||||||
|
- 1C:Enterprise 8.3.23 Developer Guide, "Common attributes": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_5._Configuration_objects/5.3.__Common__configuration_branch/5.3.5._Common_attributes/
|
||||||
|
- 1C:Enterprise 8.3.23 Developer Guide, "Functional options": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_5._Configuration_objects/5.3.__Common__configuration_branch/5.3.10._Functional_options_and_functional_option_parameters/
|
||||||
|
- 1C:Enterprise 8.3.23 Developer Guide, "Commands": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_6._Command_interface/6.2._Global_command_interface_structure/6.2.2._Commands/
|
||||||
|
- 1C:Enterprise 8.3.23 Developer Guide, "Templates": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.6._Templates/
|
||||||
|
|
||||||
|
Отдельной публичной документации `1C:Enterprise 8.5 Developer Guide` на kb.1ci.com при проверке не найдено. До появления официальной ветки 8.5 используем модель 8.3 как базовую и оставляем место под версионные отличия.
|
||||||
|
|
||||||
|
## Принципы дерева
|
||||||
|
|
||||||
|
1. В Designer/Конфигураторе типы объектов метаданных сгруппированы в дереве конфигурации.
|
||||||
|
2. Объект метаданных описывает структуру и поведение, но не хранит конкретные пользовательские данные.
|
||||||
|
3. Внутри объектов есть подчинённые объекты: реквизиты, табличные части, формы, команды, макеты, модули, измерения, ресурсы, права и т.д.
|
||||||
|
4. SFERA не должна создавать плоский список. Дерево строится по типу объекта и подчинённым коллекциям.
|
||||||
|
5. Узел `Задачи 1С` внутри конфигуратора является типом метаданных 1С. Узел `Задачи` верхнего уровня SFERA является системой разработки.
|
||||||
|
|
||||||
|
## Корневые ветки конфигурации
|
||||||
|
|
||||||
|
```text
|
||||||
|
Конфигурация
|
||||||
|
├── Общие
|
||||||
|
├── Константы
|
||||||
|
├── Справочники
|
||||||
|
├── Документы
|
||||||
|
├── Журналы документов
|
||||||
|
├── Перечисления
|
||||||
|
├── Отчеты
|
||||||
|
├── Обработки
|
||||||
|
├── Планы видов характеристик
|
||||||
|
├── Планы счетов
|
||||||
|
├── Планы видов расчета
|
||||||
|
├── Регистры сведений
|
||||||
|
├── Регистры накопления
|
||||||
|
├── Регистры бухгалтерии
|
||||||
|
├── Регистры расчета
|
||||||
|
├── Бизнес-процессы
|
||||||
|
├── Задачи
|
||||||
|
├── Внешние источники данных
|
||||||
|
└── Расширения конфигурации
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ветка "Общие"
|
||||||
|
|
||||||
|
```text
|
||||||
|
Общие
|
||||||
|
├── Подсистемы
|
||||||
|
├── Общие модули
|
||||||
|
├── Параметры сеанса
|
||||||
|
├── Роли
|
||||||
|
├── Общие реквизиты
|
||||||
|
├── Планы обмена
|
||||||
|
├── Критерии отбора
|
||||||
|
├── Подписки на события
|
||||||
|
├── Регламентные задания
|
||||||
|
├── Функциональные опции
|
||||||
|
├── Параметры функциональных опций
|
||||||
|
├── Определяемые типы
|
||||||
|
├── Хранилища настроек
|
||||||
|
├── Общие команды
|
||||||
|
├── Группы команд
|
||||||
|
├── Общие формы
|
||||||
|
├── Общие макеты
|
||||||
|
├── Общие картинки
|
||||||
|
├── XDTO-пакеты
|
||||||
|
├── Web-сервисы
|
||||||
|
├── HTTP-сервисы
|
||||||
|
├── WS-ссылки
|
||||||
|
├── WebSocket-клиенты
|
||||||
|
├── Сервисы интеграции
|
||||||
|
├── Цвета палитры
|
||||||
|
├── Элементы стиля
|
||||||
|
├── Стили
|
||||||
|
└── Языки
|
||||||
|
```
|
||||||
|
|
||||||
|
## Шаблоны подчинённых узлов
|
||||||
|
|
||||||
|
### Справочник
|
||||||
|
|
||||||
|
```text
|
||||||
|
Справочники
|
||||||
|
└── <ИмяСправочника>
|
||||||
|
├── Реквизиты
|
||||||
|
├── Табличные части
|
||||||
|
│ └── <ИмяТабличнойЧасти>
|
||||||
|
│ ├── Реквизиты
|
||||||
|
│ └── Индексы
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль объекта
|
||||||
|
├── Модуль менеджера
|
||||||
|
├── Права
|
||||||
|
├── Предопределенные данные
|
||||||
|
└── SFERA: Версии / Проверки / Инциденты / Знания
|
||||||
|
```
|
||||||
|
|
||||||
|
### Документ
|
||||||
|
|
||||||
|
```text
|
||||||
|
Документы
|
||||||
|
└── <ИмяДокумента>
|
||||||
|
├── Реквизиты
|
||||||
|
├── Табличные части
|
||||||
|
│ └── <ИмяТабличнойЧасти>
|
||||||
|
│ ├── Реквизиты
|
||||||
|
│ └── Индексы
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Движения
|
||||||
|
│ ├── Регистры сведений
|
||||||
|
│ ├── Регистры накопления
|
||||||
|
│ ├── Регистры бухгалтерии
|
||||||
|
│ └── Регистры расчета
|
||||||
|
├── Последовательности
|
||||||
|
├── Нумераторы
|
||||||
|
├── Модуль объекта
|
||||||
|
├── Модуль менеджера
|
||||||
|
├── Права
|
||||||
|
└── SFERA: Версии / Проверки / Инциденты / Знания
|
||||||
|
```
|
||||||
|
|
||||||
|
### Журнал документов
|
||||||
|
|
||||||
|
```text
|
||||||
|
Журналы документов
|
||||||
|
└── <ИмяЖурнала>
|
||||||
|
├── Графы
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль менеджера
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Перечисление
|
||||||
|
|
||||||
|
```text
|
||||||
|
Перечисления
|
||||||
|
└── <ИмяПеречисления>
|
||||||
|
├── Значения
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль менеджера
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Отчет
|
||||||
|
|
||||||
|
```text
|
||||||
|
Отчеты
|
||||||
|
└── <ИмяОтчета>
|
||||||
|
├── СКД
|
||||||
|
│ ├── Наборы данных
|
||||||
|
│ ├── Запросы
|
||||||
|
│ ├── Поля
|
||||||
|
│ ├── Ресурсы
|
||||||
|
│ ├── Группировки
|
||||||
|
│ ├── Отборы
|
||||||
|
│ └── Варианты
|
||||||
|
├── Реквизиты
|
||||||
|
├── Табличные части
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль объекта
|
||||||
|
├── Модуль менеджера
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Обработка
|
||||||
|
|
||||||
|
```text
|
||||||
|
Обработки
|
||||||
|
└── <ИмяОбработки>
|
||||||
|
├── Реквизиты
|
||||||
|
├── Табличные части
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль объекта
|
||||||
|
├── Модуль менеджера
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### План видов характеристик
|
||||||
|
|
||||||
|
```text
|
||||||
|
Планы видов характеристик
|
||||||
|
└── <ИмяПВХ>
|
||||||
|
├── Реквизиты
|
||||||
|
├── Табличные части
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль объекта
|
||||||
|
├── Модуль менеджера
|
||||||
|
├── Предопределенные данные
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### План счетов
|
||||||
|
|
||||||
|
```text
|
||||||
|
Планы счетов
|
||||||
|
└── <ИмяПланаСчетов>
|
||||||
|
├── Признаки учета
|
||||||
|
├── Признаки учета субконто
|
||||||
|
├── Табличные части
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль объекта
|
||||||
|
├── Модуль менеджера
|
||||||
|
├── Предопределенные данные
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### План видов расчета
|
||||||
|
|
||||||
|
```text
|
||||||
|
Планы видов расчета
|
||||||
|
└── <ИмяПВР>
|
||||||
|
├── Реквизиты
|
||||||
|
├── Табличные части
|
||||||
|
├── Вытесняющие виды расчета
|
||||||
|
├── Ведущие виды расчета
|
||||||
|
├── Базовые виды расчета
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль объекта
|
||||||
|
├── Модуль менеджера
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Регистр сведений
|
||||||
|
|
||||||
|
```text
|
||||||
|
Регистры сведений
|
||||||
|
└── <ИмяРегистра>
|
||||||
|
├── Измерения
|
||||||
|
├── Ресурсы
|
||||||
|
├── Реквизиты
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль набора записей
|
||||||
|
├── Модуль менеджера
|
||||||
|
├── Кто пишет
|
||||||
|
├── Кто читает
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Регистр накопления
|
||||||
|
|
||||||
|
```text
|
||||||
|
Регистры накопления
|
||||||
|
└── <ИмяРегистра>
|
||||||
|
├── Измерения
|
||||||
|
├── Ресурсы
|
||||||
|
├── Реквизиты
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль набора записей
|
||||||
|
├── Модуль менеджера
|
||||||
|
├── Кто пишет
|
||||||
|
├── Кто читает
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Регистр бухгалтерии
|
||||||
|
|
||||||
|
```text
|
||||||
|
Регистры бухгалтерии
|
||||||
|
└── <ИмяРегистра>
|
||||||
|
├── Измерения
|
||||||
|
├── Ресурсы
|
||||||
|
├── Реквизиты
|
||||||
|
├── Признаки учета
|
||||||
|
├── Признаки учета субконто
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль набора записей
|
||||||
|
├── Модуль менеджера
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Регистр расчета
|
||||||
|
|
||||||
|
```text
|
||||||
|
Регистры расчета
|
||||||
|
└── <ИмяРегистра>
|
||||||
|
├── Измерения
|
||||||
|
├── Ресурсы
|
||||||
|
├── Реквизиты
|
||||||
|
├── Перерасчеты
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль набора записей
|
||||||
|
├── Модуль менеджера
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Бизнес-процесс
|
||||||
|
|
||||||
|
```text
|
||||||
|
Бизнес-процессы
|
||||||
|
└── <ИмяБизнесПроцесса>
|
||||||
|
├── Реквизиты
|
||||||
|
├── Табличные части
|
||||||
|
├── Карта маршрута
|
||||||
|
├── Точки маршрута
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль объекта
|
||||||
|
├── Модуль менеджера
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Задача 1С
|
||||||
|
|
||||||
|
```text
|
||||||
|
Задачи
|
||||||
|
└── <ИмяЗадачи>
|
||||||
|
├── Реквизиты
|
||||||
|
├── Табличные части
|
||||||
|
├── Адресация
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
├── Макеты
|
||||||
|
├── Модуль объекта
|
||||||
|
├── Модуль менеджера
|
||||||
|
└── Права
|
||||||
|
```
|
||||||
|
|
||||||
|
### Внешний источник данных
|
||||||
|
|
||||||
|
```text
|
||||||
|
Внешние источники данных
|
||||||
|
└── <ИмяИсточника>
|
||||||
|
├── Таблицы
|
||||||
|
│ └── <ИмяТаблицы>
|
||||||
|
│ └── Поля
|
||||||
|
├── Кубы
|
||||||
|
├── Функции
|
||||||
|
├── Формы
|
||||||
|
├── Команды
|
||||||
|
└── Макеты
|
||||||
|
```
|
||||||
|
|
||||||
|
## Универсальные подчинённые узлы
|
||||||
|
|
||||||
|
Эти узлы могут встречаться у разных типов объектов. Загрузчик должен брать фактический состав из 1С, а не создавать все узлы всегда.
|
||||||
|
|
||||||
|
- `Реквизиты`
|
||||||
|
- `Табличные части`
|
||||||
|
- `Формы`
|
||||||
|
- `Команды`
|
||||||
|
- `Макеты`
|
||||||
|
- `Модуль объекта`
|
||||||
|
- `Модуль менеджера`
|
||||||
|
- `Модуль набора записей`
|
||||||
|
- `Права`
|
||||||
|
- `Предопределенные данные`
|
||||||
|
- `Измерения`
|
||||||
|
- `Ресурсы`
|
||||||
|
- `Графы`
|
||||||
|
- `Значения`
|
||||||
|
- `Перерасчеты`
|
||||||
|
- `Движения`
|
||||||
|
- `Адресация`
|
||||||
|
- `СКД`
|
||||||
|
- `URL-шаблоны`
|
||||||
|
- `Методы`
|
||||||
|
- `Контракты`
|
||||||
|
- `Обработчики`
|
||||||
|
|
||||||
|
## Правило для SFERA
|
||||||
|
|
||||||
|
Загрузчик метаданных должен сохранять:
|
||||||
|
|
||||||
|
- `metadata_type`: тип объекта 1С;
|
||||||
|
- `name`: имя объекта из конфигурации;
|
||||||
|
- `synonym`: синоним;
|
||||||
|
- `qualified_name`: полное имя вида `Документ.Имя`, `Справочник.Имя.Форма.ФормаЭлемента`;
|
||||||
|
- `parent`: родительский узел;
|
||||||
|
- `children`: подчинённые коллекции;
|
||||||
|
- `module_kind`: тип модуля, если узел является модулем;
|
||||||
|
- `rights`: права/ограничения доступа;
|
||||||
|
- `extension_origin`: основная конфигурация или расширение;
|
||||||
|
- `version_origin`: снимок/версия/задача;
|
||||||
|
- `sfera_overlays`: проверки, инциденты, знания, владельцы, runtime-события.
|
||||||
|
|
||||||
|
UI-дерево обязано строиться из этой структуры. Любые демонстрационные имена объектов должны быть заменены данными из SIR после подключения реального загрузчика.
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Codex Instructions for SFERA Docs
|
||||||
|
|
||||||
|
## Frontend Contract Rules
|
||||||
|
|
||||||
|
Перед любым изменением frontend:
|
||||||
|
|
||||||
|
1. Прочитать `docs/frontend/SFERA_FRONTEND_PRODUCT_CONTRACT.md`.
|
||||||
|
2. Прочитать `docs/frontend/SFERA_IDE_UI_CONTRACT.md`.
|
||||||
|
3. Если меняется дерево 1С - прочитать `docs/frontend/SFERA_METADATA_TREE_CONTRACT.md`.
|
||||||
|
4. Если меняются настройки проекта - прочитать `docs/frontend/SFERA_PROJECT_SETTINGS_CONTRACT.md`.
|
||||||
|
5. Если контракт устарел - сначала обновить контракт, затем код.
|
||||||
|
6. Все UI-изменения фиксировать в `docs/frontend/SFERA_FRONTEND_CHANGELOG.md`.
|
||||||
|
|
||||||
|
Frontend SFERA нельзя переводить в dashboard, CRM или файловый редактор. Принятая модель сохраняется:
|
||||||
|
|
||||||
|
- SFERA = metadata-first semantic configurator for 1C;
|
||||||
|
- основной экран = IDE последнего проекта;
|
||||||
|
- проект выбирается сверху;
|
||||||
|
- левая панель = дерево текущего проекта;
|
||||||
|
- основная конфигурация и расширения = configuration-like roots одного уровня;
|
||||||
|
- центр = рабочая область;
|
||||||
|
- правая панель = контекстные свойства;
|
||||||
|
- низ = открытые объекты, tools и status.
|
||||||
|
|
||||||
|
Для 1C-specific поведения использовать официальную документацию:
|
||||||
|
|
||||||
|
- ITS;
|
||||||
|
- v8.1c.ru;
|
||||||
|
- 1C DN;
|
||||||
|
- локальные knowledge packs.
|
||||||
|
|
||||||
|
ITS credentials передаются только через `.env.local`:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
SFERA_ITS_URL=<ITS_URL>
|
||||||
|
SFERA_ITS_USERNAME=<ITS_USERNAME>
|
||||||
|
SFERA_ITS_PASSWORD=<ITS_PASSWORD>
|
||||||
|
```
|
||||||
|
|
||||||
|
Запрещено:
|
||||||
|
|
||||||
|
- хранить реальные ITS credentials в репозитории;
|
||||||
|
- писать реальные логины или пароли в markdown;
|
||||||
|
- писать реальные логины или пароли в Dockerfile;
|
||||||
|
- выводить реальные логины или пароли в logs;
|
||||||
|
- коммитить `.env.local` и `.env.*.local`.
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
# Architecture Index
|
||||||
|
|
||||||
|
## Core
|
||||||
|
- SIR
|
||||||
|
- Rust Parser
|
||||||
|
- `rust/crates/bsl-parser`
|
||||||
|
- JSON CLI contract: `cargo run -p bsl-parser -- <module.bsl>`
|
||||||
|
- output sections: `procedures`, `calls`, `queries`, `writes`, `diagnostics`
|
||||||
|
- Semantic Kernel
|
||||||
|
- Projection Engine
|
||||||
|
- Incremental Indexer
|
||||||
|
- project-level delta rebuild for 1C `.bsl` and `.xml`
|
||||||
|
- preserves metadata object links and object-level impact consistency
|
||||||
|
- refreshes Neo4j projection after incremental updates for already-projected projects
|
||||||
|
- Impact Engine
|
||||||
|
- routine-level impact
|
||||||
|
- 1C object-level impact from metadata owner to attributes/tabular sections/tabular section columns/modules/routines/tables/writes/forms/commands/command handlers
|
||||||
|
- role access included in object impact
|
||||||
|
- in-memory and Neo4j API surfaces
|
||||||
|
|
||||||
|
## 1C Native
|
||||||
|
- Designer CLI adapter primary
|
||||||
|
- EDT optional
|
||||||
|
- EPF/CFE agent later
|
||||||
|
- XML metadata extraction
|
||||||
|
- Catalog / Document / Register / CommonModule
|
||||||
|
- ExchangePlan / ScheduledJob / BusinessProcess / Task / Role
|
||||||
|
- Form / Command / Attribute / TabularSection / Element
|
||||||
|
- Role rights as `GRANTS_ACCESS` edges
|
||||||
|
- metadata object `CONTAINS` BSL module links from 1C export paths
|
||||||
|
- Form commands linked to BSL handlers with `HANDLES`
|
||||||
|
- Object-scoped UI API for 1C forms, commands, elements, and handlers
|
||||||
|
- Scheduled jobs linked to routines with `RUNS`
|
||||||
|
- Integration topology from BSL and XML ExchangePlan metadata
|
||||||
|
- BSL integrations as `INTEGRATION_ENDPOINT` nodes and `USES_INTEGRATION` edges
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
- Semantic Object Store primary
|
||||||
|
- Git optional adapter
|
||||||
|
|
||||||
|
## Knowledge
|
||||||
|
- Global / Workspace / Project / Session scopes
|
||||||
|
- Knowledge packs
|
||||||
|
- BSP/vendor documentation pack import
|
||||||
|
- pack/vendor metadata enrichment for records
|
||||||
|
- Vendor configs
|
||||||
|
- BSP detection
|
||||||
|
- 1C schema knowledge coverage
|
||||||
|
- review findings for schema nodes without knowledge records
|
||||||
|
- Pattern mining
|
||||||
|
- repeated table read/write patterns
|
||||||
|
- repeated routine IO shapes
|
||||||
|
|
||||||
|
## Collaboration
|
||||||
|
- Users / workspaces / projects
|
||||||
|
- Tasks / active task context / change sessions
|
||||||
|
- Comments / discussions
|
||||||
|
- project comments API
|
||||||
|
- target-scoped discussion lookup
|
||||||
|
- Activity feed
|
||||||
|
- 1C object ownership
|
||||||
|
- project ownership API
|
||||||
|
- object-scoped owner lookup
|
||||||
|
- persisted ownership assignments
|
||||||
|
|
||||||
|
## Governance
|
||||||
|
- RBAC
|
||||||
|
- 1C role rights graph
|
||||||
|
- object -> roles access API
|
||||||
|
- role -> objects access API
|
||||||
|
- project report security summary
|
||||||
|
- review warnings for objects without role access
|
||||||
|
- Integration governance
|
||||||
|
- project report integration counters
|
||||||
|
- review findings for outbound external integration endpoints
|
||||||
|
- Schema governance
|
||||||
|
- project report counters for attributes, tabular sections, columns, and empty tabular sections
|
||||||
|
- review findings for tabular sections without columns
|
||||||
|
- review hints for tabular sections without common subject columns
|
||||||
|
- UI governance
|
||||||
|
- review findings for form commands with missing BSL handlers
|
||||||
|
- Ownership governance
|
||||||
|
- project report ownership counters
|
||||||
|
- review findings for 1C objects without an assigned owner
|
||||||
|
- Privacy modes
|
||||||
|
- Privacy classification
|
||||||
|
- project privacy marker API
|
||||||
|
- object-scoped privacy lookup
|
||||||
|
- review hints for sensitive 1C fields without classification
|
||||||
|
- project report privacy counters
|
||||||
|
- AI governance
|
||||||
|
- answer policy gate for knowledge context, privacy markers, token budget, and external model calls
|
||||||
|
- AI usage governance
|
||||||
|
- AI usage event API
|
||||||
|
- project/user/model/operation usage summaries
|
||||||
|
- token limit policy endpoint
|
||||||
|
- project report AI usage counters
|
||||||
|
- Token usage limits
|
||||||
|
|
||||||
|
## Operations
|
||||||
|
- Jobs / workers / queues
|
||||||
|
- Admin console
|
||||||
|
- Observability
|
||||||
|
- Marketplace/download center
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# Codex UI Guidelines для SFERA
|
||||||
|
|
||||||
|
## Роль Codex
|
||||||
|
|
||||||
|
Codex должен работать как senior frontend engineer + product designer.
|
||||||
|
|
||||||
|
Он обязан:
|
||||||
|
- соблюдать design system
|
||||||
|
- использовать русский язык интерфейса и команд по умолчанию
|
||||||
|
- предусматривать выбор английского языка интерфейса
|
||||||
|
- не генерировать случайные стили
|
||||||
|
- переиспользовать компоненты
|
||||||
|
- писать TypeScript
|
||||||
|
- не ломать архитектуру
|
||||||
|
- добавлять loading/error/empty states
|
||||||
|
- учитывать права доступа
|
||||||
|
- думать о масштабируемости IDE/authoring-среды для 1С
|
||||||
|
|
||||||
|
## Перед генерацией экрана Codex должен определить
|
||||||
|
|
||||||
|
1. Какая 1С-сущность или IDE-сущность?
|
||||||
|
2. Какие действия доступны пользователю?
|
||||||
|
3. Какие статусы есть?
|
||||||
|
4. Какие поля обязательные?
|
||||||
|
5. Нужен ли editor, designer, graph, table, inspector или diff?
|
||||||
|
6. Нужен ли AI Copilot?
|
||||||
|
7. Нужны ли права доступа?
|
||||||
|
8. Нужна ли история изменений?
|
||||||
|
9. Нужна ли интеграция с внешним источником?
|
||||||
|
10. Нужно ли preview/diff/apply для изменения 1С-кода или metadata?
|
||||||
|
|
||||||
|
## Запреты
|
||||||
|
|
||||||
|
Codex НЕ должен:
|
||||||
|
- использовать inline styles
|
||||||
|
- создавать хаотичные цвета
|
||||||
|
- использовать Bootstrap
|
||||||
|
- делать огромный компонент на 1000 строк
|
||||||
|
- хранить business logic в JSX
|
||||||
|
- игнорировать loading states
|
||||||
|
- игнорировать empty states
|
||||||
|
- генерировать mock API без явной пометки
|
||||||
|
- смешивать entity-компоненты и базовый UI
|
||||||
|
|
||||||
|
## Обязательные states
|
||||||
|
|
||||||
|
Каждый экран должен иметь:
|
||||||
|
|
||||||
|
- loading
|
||||||
|
- error
|
||||||
|
- empty
|
||||||
|
- success
|
||||||
|
- permission denied
|
||||||
|
- dirty form / unsaved changes
|
||||||
|
- semantic diff / preview
|
||||||
|
- guarded apply result
|
||||||
|
|
||||||
|
## UI quality checklist
|
||||||
|
|
||||||
|
Перед финалом Codex обязан проверить:
|
||||||
|
|
||||||
|
- интерфейс адаптивный
|
||||||
|
- все кнопки имеют понятный action
|
||||||
|
- статусы представлены Badge
|
||||||
|
- опасные действия требуют confirmation
|
||||||
|
- таблицы имеют фильтры
|
||||||
|
- формы валидируются через Zod
|
||||||
|
- редактор/дизайнер имеет problems panel и состояние несохранённых изменений
|
||||||
|
- дата/время форматируются единообразно
|
||||||
|
- AI действия показывают token/cost impact
|
||||||
|
- AI-подсказки учитывают текущий BSL-код, объект 1С, переменные, реквизиты, формы и связи
|
||||||
|
- есть audit trail для важных действий
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# SPRINT 1 — SIR Core
|
||||||
|
|
||||||
|
## Цель
|
||||||
|
|
||||||
|
Создать `packages/sir`.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `enums.py`
|
||||||
|
- `source_ref.py`
|
||||||
|
- `lineage.py`
|
||||||
|
- `nodes.py`
|
||||||
|
- `edges.py`
|
||||||
|
- `diagnostics.py`
|
||||||
|
- `references.py`
|
||||||
|
- `snapshot.py`
|
||||||
|
- `delta.py`
|
||||||
|
- `validation.py`
|
||||||
|
- `serialization.py`
|
||||||
|
- `hashing.py`
|
||||||
|
|
||||||
|
## DoD
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pytest packages/sir/tests
|
||||||
|
```
|
||||||
|
|
||||||
|
Должно проходить:
|
||||||
|
|
||||||
|
- snapshot validation ok;
|
||||||
|
- dangling edge detected;
|
||||||
|
- serialization roundtrip;
|
||||||
|
- snapshot hash deterministic;
|
||||||
|
- diagnostics/unresolved references serializable.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# SPRINT 2 — Rust BSL Parser MVP
|
||||||
|
|
||||||
|
## Цель
|
||||||
|
|
||||||
|
`rust/crates/bsl-parser` должен возвращать `ParsedSemanticUnit`:
|
||||||
|
|
||||||
|
- procedures;
|
||||||
|
- functions;
|
||||||
|
- calls;
|
||||||
|
- queries;
|
||||||
|
- query tables;
|
||||||
|
- writes;
|
||||||
|
- diagnostics.
|
||||||
|
|
||||||
|
## Важное
|
||||||
|
|
||||||
|
Поддержать RU/EN keywords.
|
||||||
|
|
||||||
|
## MVP ограничение
|
||||||
|
|
||||||
|
Можно начать с deterministic line-based parser. Позже заменить на полноценный lexer/parser.
|
||||||
|
|
||||||
|
## DoD
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd rust && cargo test
|
||||||
|
```
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# SPRINT 3 — Semantic Kernel
|
||||||
|
|
||||||
|
## Цель
|
||||||
|
|
||||||
|
`packages/semantic-kernel` конвертирует parsed result в SIR snapshot.
|
||||||
|
|
||||||
|
## Вход
|
||||||
|
|
||||||
|
`.bsl` файлы.
|
||||||
|
|
||||||
|
## Выход
|
||||||
|
|
||||||
|
`SirSnapshot` с nodes/edges:
|
||||||
|
|
||||||
|
- MODULE;
|
||||||
|
- PROCEDURE/FUNCTION;
|
||||||
|
- QUERY;
|
||||||
|
- TABLE/REGISTER;
|
||||||
|
- DECLARES;
|
||||||
|
- CALLS;
|
||||||
|
- OWNS_QUERY;
|
||||||
|
- READS_TABLE;
|
||||||
|
- WRITES.
|
||||||
|
|
||||||
|
## DoD
|
||||||
|
|
||||||
|
`index_project(path)` возвращает валидный snapshot.
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# SPRINT 4 — Neo4j Projection
|
||||||
|
|
||||||
|
## Цель
|
||||||
|
|
||||||
|
`SirSnapshot → Neo4j graph`.
|
||||||
|
|
||||||
|
## Queries
|
||||||
|
|
||||||
|
- find procedures;
|
||||||
|
- find callers;
|
||||||
|
- find callees;
|
||||||
|
- find query tables;
|
||||||
|
- find writes.
|
||||||
|
|
||||||
|
## Rule
|
||||||
|
|
||||||
|
Only `projection-engine` can mutate Neo4j.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# SPRINT 5 — Incremental Indexer
|
||||||
|
|
||||||
|
## Цель
|
||||||
|
|
||||||
|
Изменился один `.bsl` файл — пересобираем только fragment и применяем delta.
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
- source hash;
|
||||||
|
- change detector;
|
||||||
|
- SirDelta builder;
|
||||||
|
- snapshot transition;
|
||||||
|
- projection delta.
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
# Component Architecture
|
||||||
|
|
||||||
|
## Рекомендуемая структура
|
||||||
|
|
||||||
|
```txt
|
||||||
|
src/
|
||||||
|
app/
|
||||||
|
(auth)/
|
||||||
|
(workspace)/
|
||||||
|
dashboard/
|
||||||
|
projects/
|
||||||
|
objects/
|
||||||
|
graph/
|
||||||
|
editor/
|
||||||
|
designer/
|
||||||
|
review/
|
||||||
|
impact/
|
||||||
|
knowledge/
|
||||||
|
integrations/
|
||||||
|
jobs/
|
||||||
|
ai/
|
||||||
|
settings/
|
||||||
|
components/
|
||||||
|
ui/
|
||||||
|
layout/
|
||||||
|
data-table/
|
||||||
|
editor/
|
||||||
|
designer/
|
||||||
|
graph/
|
||||||
|
command/
|
||||||
|
ai/
|
||||||
|
entities/
|
||||||
|
one-c-projects/
|
||||||
|
one-c-objects/
|
||||||
|
bsl-modules/
|
||||||
|
forms/
|
||||||
|
reports/
|
||||||
|
roles/
|
||||||
|
features/
|
||||||
|
one-c-projects/
|
||||||
|
semantic-graph/
|
||||||
|
bsl-editor/
|
||||||
|
object-designer/
|
||||||
|
form-designer/
|
||||||
|
report-designer/
|
||||||
|
impact-analysis/
|
||||||
|
review/
|
||||||
|
ai-authoring/
|
||||||
|
ai-usage/
|
||||||
|
integrations/
|
||||||
|
scheduled-jobs/
|
||||||
|
lib/
|
||||||
|
api/
|
||||||
|
auth/
|
||||||
|
permissions/
|
||||||
|
validators/
|
||||||
|
formatters/
|
||||||
|
one-c/
|
||||||
|
store/
|
||||||
|
styles/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Правило разделения
|
||||||
|
|
||||||
|
### `components/ui`
|
||||||
|
|
||||||
|
Только базовые shadcn-like компоненты:
|
||||||
|
- Button
|
||||||
|
- Input
|
||||||
|
- Dialog
|
||||||
|
- Drawer
|
||||||
|
- Badge
|
||||||
|
- Card
|
||||||
|
- Tabs
|
||||||
|
|
||||||
|
### `components/editor`
|
||||||
|
|
||||||
|
IDE primitives:
|
||||||
|
- BslEditor
|
||||||
|
- ProblemsPanel
|
||||||
|
- ReferencesPanel
|
||||||
|
- OutlinePanel
|
||||||
|
- SemanticDiffView
|
||||||
|
- CompletionList
|
||||||
|
|
||||||
|
### `components/designer`
|
||||||
|
|
||||||
|
Object/form/report designer primitives:
|
||||||
|
- ObjectTree
|
||||||
|
- MetadataInspector
|
||||||
|
- FormCanvas
|
||||||
|
- FormElementPalette
|
||||||
|
- PropertiesInspector
|
||||||
|
- ReportDesigner
|
||||||
|
|
||||||
|
### `components/entities`
|
||||||
|
|
||||||
|
Переиспользуемые 1С entity-компоненты:
|
||||||
|
- OneCProjectCard
|
||||||
|
- OneCObjectBadge
|
||||||
|
- ObjectKindBadge
|
||||||
|
- RoleAccessBadge
|
||||||
|
- ReviewSeverityBadge
|
||||||
|
- SnapshotStatusBadge
|
||||||
|
|
||||||
|
### `features`
|
||||||
|
|
||||||
|
Полные feature-модули:
|
||||||
|
- список 1С-проектов
|
||||||
|
- дерево конфигурации
|
||||||
|
- карточка объекта 1С
|
||||||
|
- BSL editor workspace
|
||||||
|
- дизайнер формы
|
||||||
|
- дизайнер отчёта
|
||||||
|
- semantic graph
|
||||||
|
- impact analysis
|
||||||
|
- AI authoring panel
|
||||||
|
- AI usage dashboard
|
||||||
|
|
||||||
|
## Data Table стандарт
|
||||||
|
|
||||||
|
Каждая таблица должна иметь:
|
||||||
|
|
||||||
|
- search
|
||||||
|
- filters
|
||||||
|
- saved views
|
||||||
|
- column visibility
|
||||||
|
- sorting
|
||||||
|
- pagination / virtualization
|
||||||
|
- row actions
|
||||||
|
- bulk actions
|
||||||
|
- export
|
||||||
|
- audit-friendly row details
|
||||||
|
|
||||||
|
## IDE Page Standard
|
||||||
|
|
||||||
|
Каждая IDE-страница строится по шаблону:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
PageHeader
|
||||||
|
Toolbar
|
||||||
|
ObjectTree
|
||||||
|
PrimaryEditorOrDesigner
|
||||||
|
RightInspector
|
||||||
|
ProblemsPanel
|
||||||
|
SemanticDiffPreview
|
||||||
|
AIAssistantContext
|
||||||
|
```
|
||||||
|
|
||||||
|
## Naming conventions
|
||||||
|
|
||||||
|
```txt
|
||||||
|
OneCProjectList
|
||||||
|
OneCObjectTree
|
||||||
|
BslEditorWorkspace
|
||||||
|
BslCompletionPanel
|
||||||
|
FormDesignerCanvas
|
||||||
|
MetadataPropertiesInspector
|
||||||
|
SemanticDiffPreview
|
||||||
|
AiAuthoringPanel
|
||||||
|
```
|
||||||
|
|
||||||
|
Не использовать абстрактные имена вроде:
|
||||||
|
- MainTable
|
||||||
|
- CustomCard
|
||||||
|
- ModalWindow
|
||||||
|
- BigForm
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
# Design System SFERA
|
||||||
|
|
||||||
|
## UI концепция
|
||||||
|
|
||||||
|
**SFERA — Enterprise AI Operating System**
|
||||||
|
|
||||||
|
Интерфейс должен ощущаться как:
|
||||||
|
- Linear
|
||||||
|
- Stripe Dashboard
|
||||||
|
- Notion
|
||||||
|
- Attio
|
||||||
|
- ClickUp 3.0
|
||||||
|
- Plane
|
||||||
|
- VS Code / JetBrains IDE для authoring-сценариев 1С
|
||||||
|
|
||||||
|
SFERA не CRM. Основной UI — это современная IDE/операционная среда для 1С: semantic workspace, редактор кода, дерево объектов, дизайнер форм/отчётов, инспектор свойств, diff/preview/apply и AI-помощник.
|
||||||
|
|
||||||
|
Классический 1С Конфигуратор используется как reference workflow, а не как visual style. Мы берём рабочие паттерны 1С-разработчика: дерево конфигурации, вкладки объектов, модуль/форма/свойства/события, правый инспектор, нижние панели диагностики и поиск. Визуально это должно быть современно, плотно, спокойно и удобно для долгой работы.
|
||||||
|
|
||||||
|
## Визуальный стиль
|
||||||
|
|
||||||
|
- чистый enterprise minimalism
|
||||||
|
- dark/light режим
|
||||||
|
- спокойные нейтральные цвета
|
||||||
|
- акцентный цвет для действий
|
||||||
|
- cards with soft shadows
|
||||||
|
- rounded-2xl
|
||||||
|
- минимальный glassmorphism только для важных overlay
|
||||||
|
- плотная, но не перегруженная информационная сетка
|
||||||
|
|
||||||
|
## Layout principles
|
||||||
|
|
||||||
|
### Главная структура
|
||||||
|
|
||||||
|
```txt
|
||||||
|
AppShell
|
||||||
|
├── Sidebar
|
||||||
|
├── Topbar
|
||||||
|
├── CommandPalette
|
||||||
|
├── Workspace
|
||||||
|
│ ├── PageHeader
|
||||||
|
│ ├── Toolbar
|
||||||
|
│ ├── ContentGrid
|
||||||
|
│ └── RightInspector
|
||||||
|
├── EditorWorkspace
|
||||||
|
│ ├── ObjectTree
|
||||||
|
│ ├── WorkspaceModeBar
|
||||||
|
│ ├── CodeEditor
|
||||||
|
│ ├── FormDesigner
|
||||||
|
│ ├── PropertiesInspector
|
||||||
|
│ ├── EventsInspector
|
||||||
|
│ ├── VersionsPanel
|
||||||
|
│ ├── DocumentationPanel
|
||||||
|
│ ├── KnowledgePanel
|
||||||
|
│ ├── LearningPanel
|
||||||
|
│ ├── ProblemsPanel
|
||||||
|
│ └── SemanticDiff
|
||||||
|
└── AI Copilot Panel
|
||||||
|
```
|
||||||
|
|
||||||
|
## Основные зоны
|
||||||
|
|
||||||
|
### Sidebar
|
||||||
|
|
||||||
|
- Dashboard
|
||||||
|
- Проекты 1С
|
||||||
|
- Объекты 1С
|
||||||
|
- Редактор BSL
|
||||||
|
- Дизайнер объектов
|
||||||
|
- Дизайнер форм
|
||||||
|
- Отчёты
|
||||||
|
- Семантический граф
|
||||||
|
- Impact analysis
|
||||||
|
- Review
|
||||||
|
- Знания
|
||||||
|
- AI
|
||||||
|
- Интеграции
|
||||||
|
- Регламентные задания
|
||||||
|
- Настройки
|
||||||
|
|
||||||
|
### Topbar
|
||||||
|
|
||||||
|
- поиск
|
||||||
|
- command palette
|
||||||
|
- быстрые действия
|
||||||
|
- уведомления
|
||||||
|
- профиль
|
||||||
|
- переключение проекта/организации
|
||||||
|
|
||||||
|
### Right Inspector
|
||||||
|
|
||||||
|
Контекстная панель для:
|
||||||
|
- объекта 1С
|
||||||
|
- процедуры или функции
|
||||||
|
- формы, команды или элемента формы
|
||||||
|
- реквизита или табличной части
|
||||||
|
- отчёта
|
||||||
|
- AI анализа
|
||||||
|
- истории изменений
|
||||||
|
- связанных сущностей
|
||||||
|
|
||||||
|
## Компонентные правила
|
||||||
|
|
||||||
|
### Карточки
|
||||||
|
|
||||||
|
- `rounded-2xl`
|
||||||
|
- `border`
|
||||||
|
- `bg-card`
|
||||||
|
- `shadow-sm`
|
||||||
|
- padding минимум `p-4`
|
||||||
|
|
||||||
|
### Таблицы
|
||||||
|
|
||||||
|
- sticky header
|
||||||
|
- фильтры
|
||||||
|
- saved views
|
||||||
|
- быстрый поиск
|
||||||
|
- column visibility
|
||||||
|
- bulk actions
|
||||||
|
- inline status badge
|
||||||
|
- row details через drawer/inspector
|
||||||
|
|
||||||
|
### Формы
|
||||||
|
|
||||||
|
- разделять на logical sections
|
||||||
|
- использовать progressive disclosure
|
||||||
|
- показывать validation inline
|
||||||
|
- сохранять drafts
|
||||||
|
- audit trail для важных изменений
|
||||||
|
|
||||||
|
## Цветовые токены
|
||||||
|
|
||||||
|
```txt
|
||||||
|
background
|
||||||
|
foreground
|
||||||
|
card
|
||||||
|
card-foreground
|
||||||
|
muted
|
||||||
|
muted-foreground
|
||||||
|
border
|
||||||
|
input
|
||||||
|
primary
|
||||||
|
primary-foreground
|
||||||
|
secondary
|
||||||
|
destructive
|
||||||
|
warning
|
||||||
|
success
|
||||||
|
info
|
||||||
|
```
|
||||||
|
|
||||||
|
## Статусы
|
||||||
|
|
||||||
|
### Задача
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Новая
|
||||||
|
В работе
|
||||||
|
На проверке
|
||||||
|
Выполнена
|
||||||
|
Отменена
|
||||||
|
Просрочена
|
||||||
|
```
|
||||||
|
|
||||||
|
### Сделка
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Активна
|
||||||
|
Неактивна
|
||||||
|
На бординге
|
||||||
|
Ожидает документов
|
||||||
|
Приостановлена
|
||||||
|
Закрыта
|
||||||
|
```
|
||||||
|
|
||||||
|
### Терминал
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Подключен
|
||||||
|
Не подключен
|
||||||
|
Отключен банком
|
||||||
|
Ошибка настройки
|
||||||
|
```
|
||||||
|
|
||||||
|
## AI UX
|
||||||
|
|
||||||
|
AI должен быть не отдельной страницей, а частью workflow:
|
||||||
|
|
||||||
|
- AI Copilot справа
|
||||||
|
- подсказки в карточках
|
||||||
|
- inline completion в BSL editor
|
||||||
|
- context-aware suggestions по текущим переменным, реквизитам, табличным частям, форме и объекту 1С
|
||||||
|
- генерация кода, объектов, форм, команд и отчётов через preview/diff/apply
|
||||||
|
- объяснение текущего кода и структуры объекта
|
||||||
|
- генерация безопасных изменений 1С
|
||||||
|
- продолжение кода по текущему контексту
|
||||||
|
- объяснение изменений
|
||||||
|
- статистика токенов и лимитов
|
||||||
|
|
||||||
|
## Knowledge, Docs, Training UX
|
||||||
|
|
||||||
|
SFERA должна показывать знания рядом с местом работы, а не прятать их в отдельную wiki:
|
||||||
|
|
||||||
|
- документация объекта, формы, отчёта и бизнес-правила доступны из IDE-контекста;
|
||||||
|
- база знаний связывается с lineage объекта, процедурами, запросами и событиями формы;
|
||||||
|
- training/onboarding показывает рекомендации по текущему коду, стандартам команды и типовым ошибкам;
|
||||||
|
- AI отвечает только с учётом доступных знаний, прав и privacy policy;
|
||||||
|
- history/versions объясняют, почему объект менялся, какими задачами и решениями это было связано.
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# Frontend Stack для SFERA
|
||||||
|
|
||||||
|
## Core
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Next.js
|
||||||
|
React
|
||||||
|
TypeScript
|
||||||
|
Tailwind CSS
|
||||||
|
shadcn/ui
|
||||||
|
Radix UI
|
||||||
|
lucide-react
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data layer
|
||||||
|
|
||||||
|
```txt
|
||||||
|
TanStack Query
|
||||||
|
Zustand
|
||||||
|
Zod
|
||||||
|
React Hook Form
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tables / Grids
|
||||||
|
|
||||||
|
```txt
|
||||||
|
TanStack Table
|
||||||
|
TanStack Virtual
|
||||||
|
```
|
||||||
|
|
||||||
|
Использовать для:
|
||||||
|
- 1С-проектов
|
||||||
|
- объектов 1С
|
||||||
|
- процедур и функций
|
||||||
|
- форм и команд
|
||||||
|
- ролей и прав
|
||||||
|
- review findings
|
||||||
|
- журналов изменений
|
||||||
|
- AI usage статистики
|
||||||
|
- лимитов
|
||||||
|
- интеграций
|
||||||
|
|
||||||
|
## Charts
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Recharts
|
||||||
|
Apache ECharts
|
||||||
|
```
|
||||||
|
|
||||||
|
Для простых dashboard — Recharts.
|
||||||
|
Для тяжелой аналитики и сложных графиков — ECharts.
|
||||||
|
|
||||||
|
## Animations
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Framer Motion
|
||||||
|
```
|
||||||
|
|
||||||
|
Использовать аккуратно:
|
||||||
|
- открытие панелей
|
||||||
|
- command palette
|
||||||
|
- sidebar
|
||||||
|
- drawer
|
||||||
|
- карточки задач
|
||||||
|
- state transitions
|
||||||
|
|
||||||
|
## UI generation tools
|
||||||
|
|
||||||
|
```txt
|
||||||
|
v0 by Vercel
|
||||||
|
shadcn/ui
|
||||||
|
shadcn/studio
|
||||||
|
Cursor
|
||||||
|
Codex
|
||||||
|
```
|
||||||
|
|
||||||
|
## Почему не Ant Design / Bootstrap
|
||||||
|
|
||||||
|
Ant Design подходит для быстрых корпоративных систем, но SFERA должна выглядеть как современный AI enterprise workspace, а не как старая админка.
|
||||||
|
|
||||||
|
Bootstrap и старые admin templates не использовать как основу.
|
||||||
@@ -0,0 +1,391 @@
|
|||||||
|
# SFERA Frontend Changelog
|
||||||
|
|
||||||
|
## Правило
|
||||||
|
|
||||||
|
Каждое изменение frontend должно фиксироваться здесь.
|
||||||
|
|
||||||
|
Формат:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Дата:
|
||||||
|
Автор/Codex task:
|
||||||
|
Что изменено:
|
||||||
|
Какие файлы:
|
||||||
|
Затронутые экраны:
|
||||||
|
Изменен ли UI contract:
|
||||||
|
Нужны ли новые smoke tests:
|
||||||
|
```
|
||||||
|
|
||||||
|
## Записи
|
||||||
|
|
||||||
|
### 2026-05-11
|
||||||
|
|
||||||
|
Initial UI contract created.
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Корневой маршрут frontend переведен на IDE последнего проекта; существующий экран настройки проекта вынесен на `/project-settings`; Top Project Bar дополнен настройками проекта, созданием проекта, уведомлениями и профилем; smoke-тесты обновлены под IDE-first модель и новый route настроек проекта.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/app/page.tsx`, `frontend/sfera-web/src/app/project-settings/page.tsx`, `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/src/lib/i18n.ts`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: основной вход frontend, IDE workspace, project settings
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, HTML smoke покрывает redirect `/` -> IDE и доступность `/project-settings`
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Fallback metadata tree приведен к контрактной модели: проект содержит top-level `Основная конфигурация`, `Расширение: <Имя>`, `SFERA`, `Среды`; расширение использует тот же configuration-like каркас без fake-объектов.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, HTML smoke проверяет ключевые top-level узлы левой панели
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Server-side metadata tree приведен к той же top-level модели для lazy/large-project режима; пути раскрытия теперь идут через `main-configuration`, а lazy tree сохраняет раскрытие `Основная конфигурация`.
|
||||||
|
Какие файлы: `services/api-server/src/api_server/main.py`, `services/api-server/tests/test_api.py`, `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`
|
||||||
|
Затронутые экраны: IDE workspace, lazy metadata tree
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, API tests покрывают структуру, HTML smoke покрывает видимые top-level узлы
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Project Settings sidebar переименован из wizard в контрактный экран настроек, добавлен список разделов настроек, AI policy и ITS/documentation access с безопасными env placeholders без реальных credentials; default privacy для нового fallback проекта изменен на `METADATA_ONLY`.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/src/app/project-settings/page.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
|
||||||
|
Затронутые экраны: Project Settings, Top Project Bar, Import Center
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, HTML smoke проверяет Project Settings и ITS env placeholders
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Lazy metadata tree получил полный маппинг contract-first иконок на существующие 1C SVG assets, чтобы top-level проект, основная конфигурация, ветки metadata, группы макетов/событий/движений, бизнес-процессы, задачи и внешние источники не ссылались на отсутствующие файлы.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`
|
||||||
|
Затронутые экраны: IDE workspace, lazy metadata tree
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, существующий editor smoke покрывает lazy metadata tree shell
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Lazy metadata tree очищен от старого `dashboard` route variant; все переходы из дерева теперь строятся напрямую на `/editor`, включая SFERA overview как `mode=overview`.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`, `frontend/sfera-web/src/components/editor/ide-workspace.tsx`
|
||||||
|
Затронутые экраны: IDE workspace, lazy metadata tree
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, существующий editor smoke покрывает IDE route
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: `/project-settings` закреплен как экран Project Settings при любом статусе проекта; INDEXED-проект больше не подменяет настройки старым workbench, поэтому настройки проекта остаются доступны из Top Project Bar по контракту.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: Project Settings
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, project setup smoke обновлен под contract-first Project Settings route
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: IDE workspace получил contract-first управление панелями: левая навигация сворачивается и меняет ширину, правая Context Inspector и нижняя tool panel сворачиваются, добавлены горячие клавиши `Alt+1`, `Alt+2`, `Alt+3`, `Ctrl+Tab`, `Ctrl+Shift+Tab`, `Ctrl+W`.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, Left Navigation Panel, Main Workspace, Right Context Inspector, Bottom Tool Panel, Open Objects Bar
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, editor smoke расширен проверкой contract layout markers
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Runtime smoke расширен интерактивной проверкой contract controls: `Alt+1`, `Alt+2`, `Alt+3` скрывают соответствующие панели, rail/buttons возвращают их, `Ctrl+Tab` и `Ctrl+Shift+Tab` переключают открытые объекты; после переходов между editor modes нижняя tool panel сворачивается для focused editor workflows.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, панель открытых объектов, левая/правая/нижняя панели
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, runtime smoke обновлен
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Open Objects Bar получил fallback-набор IDE tabs (`Обзор`, `Модуль`, `Форма`, `TASK-123`) для пустого или минимального metadata tree, чтобы workspace сохранял contract-first модель переключаемых открытых объектов.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, Open Objects Bar
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, runtime smoke проверяет минимум два переключаемых объекта
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: IDE workspace убран жесткий `min-h-[760px]`, из-за которого нижняя tool panel и fixed status bar могли перекрывать рабочую область и перехватывать клики в metadata editor на невысоких viewport.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`
|
||||||
|
Затронутые экраны: IDE workspace, Main Workspace, Bottom Tool Panel, Status Bar
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, runtime smoke ловит перекрытие кликов
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Top Project Bar получил настоящий global search input; IDE workspace обрабатывает `Ctrl+K` для фокуса глобального поиска и `F5` для запуска проверки с открытием bottom tool panel и статусом запуска.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: Top Project Bar, IDE workspace, Bottom Tool Panel
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, runtime smoke расширен проверкой `Ctrl+K` и `F5`
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Fallback Left Navigation Panel получил поиск по дереву, фильтры `Все / 1C / SFERA / Среды`, отдельный scroll marker и сохранение раскрытия веток через `localStorage`.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, Left Navigation Panel
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, editor smoke и runtime smoke расширены проверкой поиска/фильтров fallback tree
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Open Objects Bar получил pin/close controls, `Ctrl+W` закрывает активный незакрепленный объект, состояние закрытых и закрепленных объектов сохраняется в `localStorage` и восстанавливается для проекта.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, Open Objects Bar
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, editor smoke и runtime smoke расширены проверкой pin/close/persist поведения
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Open Objects Bar поднят над рабочей областью (`z-index`) и сделан `shrink-0`, чтобы Monaco/editor canvas не перекрывал pin/close controls и не перехватывал клики.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`
|
||||||
|
Затронутые экраны: IDE workspace, Open Objects Bar
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, runtime smoke ловит перекрытие кликов
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Project Settings получил недостающие контрактные секции `Пользователи и доступ`, `Интеграции задач`, `Docker/runtime adapter`, `Audit`, `Backup/restore`; sidebar anchors обновлены под эти секции, без хранения credentials.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: Project Settings
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, существующие smoke расширены проверкой полного набора settings sections
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Status Bar приведен к полному набору контрактных индикаторов, добавлен `Current user`, стабильные `data-status-item` markers и горизонтальный overflow для узких viewport.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, Status Bar
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, editor smoke и runtime smoke расширены проверкой status markers
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Источники структуры 1С дополнены `REFERENCE_CONFIGURATION` end-to-end: backend import source registry/preflight, frontend selector/action button/source configurator и smoke checks.
|
||||||
|
Какие файлы: `services/api-server/src/api_server/main.py`, `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: Project Settings, Import Center
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, существующие smoke расширены проверкой reference configuration source
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Metadata tree дополнен контрактными configuration-like roots для context/reference источников: при `CONTEXT_ONLY` добавляется `Context-only configuration`, при `REFERENCE_CONFIGURATION` добавляется `Reference configuration` с тем же каркасом веток, что у основной конфигурации/расширений.
|
||||||
|
Какие файлы: `services/api-server/src/api_server/main.py`, `services/api-server/tests/test_api.py`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (lazy/server data)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, покрыто API tests для metadata tree response
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: В `LazyMetadataTree` добавлен настоящий virtual scroll для списка видимых узлов (viewport-based windowing с overscan), чтобы левая панель масштабировалась на больших деревьях без полной отрисовки всех root-level элементов.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (lazy mode)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, существующий `smoke:editor` проходит; typecheck зеленый
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Runtime smoke расширен проверкой контрактного scroll-контейнера левой панели (`data-virtual-scroll` для lazy tree или `data-fallback-tree-scroll` для fallback tree), чтобы регресс virtual scroll ловился автоматически.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: API test coverage дерева метаданных расширено для `CONTEXT_CONFIGURATION`: добавлен тест, подтверждающий появление `Context-only configuration` как configuration-like root с контрактным набором первых веток (`Сведения`, `Общие`, `Константы`).
|
||||||
|
Какие файлы: `services/api-server/tests/test_api.py`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, покрыто API tests
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: В `LazyMetadataTree` добавлены контрактные фильтры левой панели (`Все / 1C / SFERA / Среды`) для lazy/server режима, чтобы поведение фильтрации было единым с fallback tree.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (lazy mode)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, существующий runtime smoke проходит; typecheck зеленый
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Runtime smoke расширен проверкой lazy-tree фильтров: при наличии `data-lazy-tree-filter` тест переключает `SFERA`/`All` и подтверждает доступность узла `SFERA`, чтобы зафиксировать поведение новых фильтров.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (lazy mode)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Project Settings runtime smoke усилен проверкой отображения `.env.local` в секции `ITS/documentation access`, чтобы policy "credentials only via .env.local" оставалась закрепленной на UI-уровне.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: Project Settings (`ITS/documentation access`)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: HTML smoke (`smoke:editor`) усилен контрактными маркерами Top Project Bar на корневом IDE-экране: добавлены проверки `Компания`, `Среда`, `Задача`, `Ctrl+K`, `API доступен`, `Агент онлайн`.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
|
||||||
|
Затронутые экраны: основной IDE экран, Top Project Bar
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: HTML smoke для `/project-settings` расширен security-маркерами секции `ITS/documentation access`: добавлены проверки `.env.local` и placeholder `<set locally>` вместе с `SFERA_ITS_USERNAME`.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
|
||||||
|
Затронутые экраны: Project Settings (`ITS/documentation access`)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Добавлен защитный API-тест на metadata tree: для обычных источников (`XML_DUMP`) в корне проекта не должны появляться contract-only roots `CONTEXT_CONFIGURATION` и `REFERENCE_CONFIGURATION`.
|
||||||
|
Какие файлы: `services/api-server/tests/test_api.py`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, покрыто API tests
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Runtime smoke расширен проверкой горячей клавиши `Ctrl+W`: тест выбирает немодульный открытый объект (если доступен), закрывает его через `Ctrl+W` и проверяет, что tab удален без runtime ошибок; сценарий стабилизирован возвратом к module-tab при необходимости.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, Open Objects Bar, горячие клавиши
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: ITS security-policy smoke-покрытие расширено: в HTML smoke добавлены `SFERA_ITS_URL`/`SFERA_ITS_PASSWORD`, в runtime smoke `Project Settings` добавлены проверки `SFERA_ITS_URL`, `SFERA_ITS_PASSWORD` и presence примера ITS URL через `input[value*='its.1c.ru/db/v838doc']`.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: Project Settings (`ITS/documentation access`)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлены существующие `smoke:editor` и `smoke:project-setup`
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: HTML smoke расширен англоязычной проверкой корневого IDE-экрана (`lang=en`) для Top Project Bar: `Workspace`, `Env`, `Task`, `Ctrl+K`, `API online`, `Agent online`.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
|
||||||
|
Затронутые экраны: основной IDE экран, Top Project Bar (EN UI)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Добавлен API-тест порядка top-level узлов metadata tree: при `CONTEXT_ONLY` и `REFERENCE_CONFIGURATION` соответствующие configuration-like roots должны располагаться перед `SFERA` в корне проекта.
|
||||||
|
Какие файлы: `services/api-server/tests/test_api.py`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, покрыто API tests
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Runtime smoke расширен проверкой восстановления `Open Objects Bar` после перезагрузки: тест сохраняет состояние закрытых/закрепленных табов, делает `page.reload`, подтверждает сохранность `localStorage` и проверяет, что закрытый таб снова скрыт после применения состояния.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, Open Objects Bar
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-11
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: API tests для `CONTEXT_CONFIGURATION` и `REFERENCE_CONFIGURATION` расширены проверкой lazy-режима (`object_limit_per_branch=0`): условные configuration-like roots должны присутствовать не только в полном, но и в lazy metadata tree response.
|
||||||
|
Какие файлы: `services/api-server/tests/test_api.py`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, покрыто API tests
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: API-тест порядка корневых узлов расширен и на lazy metadata tree: для `CONTEXT_ONLY` и `REFERENCE_CONFIGURATION` условные configuration-like roots должны располагаться перед `SFERA` как в полном, так и в lazy-ответе (`object_limit_per_branch=0`).
|
||||||
|
Какие файлы: `services/api-server/tests/test_api.py`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, покрыто API tests
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Runtime smoke расширен проверкой состава `Bottom Tool Panel`: тест подтверждает видимость вкладок `Проблемы`, `Semantic diff`, `Вывод`, `История`, `Тесты`, `AI` после открытия нижней панели.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: IDE workspace, Bottom Tool Panel
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: HTML smoke расширен англоязычной проверкой `Project Settings` (`lang=en`): закреплены `Project Settings`, `Import Center`, `Task/session policy`, `Docker/runtime adapter`, `ITS/documentation access`, `Audit`, `Backup/restore` и ITS env placeholders.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
|
||||||
|
Затронутые экраны: Project Settings (EN UI)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Защитный API-тест для обычных источников (`XML_DUMP`) расширен и на lazy metadata tree: `CONTEXT_CONFIGURATION` и `REFERENCE_CONFIGURATION` не должны появляться в корне ни полного, ни lazy-ответа.
|
||||||
|
Какие файлы: `services/api-server/tests/test_api.py`
|
||||||
|
Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, покрыто API tests
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Runtime smoke `Project Settings` расширен англоязычным сценарием (`lang=en`): подтверждаются `Task/session policy`, `Docker/runtime adapter`, `ITS/documentation access`, `Audit`, `Backup/restore` и ITS env placeholders на реальном интерактивном экране.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: Project Settings (EN UI)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Runtime smoke IDE расширен англоязычным сценарием (`lang=en`) для Top Project Bar и status bar; дополнительно smoke фиксирован на desktop viewport `1680x1050`, чтобы контрактные desktop-элементы вроде `Task` проверялись в реальном видимом layout.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: основной IDE экран, Top Project Bar, Status Bar (EN UI)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий editor runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: EN runtime smoke `Project Settings` расширен проверкой `REFERENCE_CONFIGURATION` и кнопки `Reference config`, чтобы import/source contract был закреплен и в английском интерактивном сценарии.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: Project Settings (EN UI)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: EN runtime smoke IDE расширен проверкой `Bottom Tool Panel`: в английском сценарии подтверждаются вкладки `Problems`, `Semantic diff`, `Output`, `Change history`, `Tests`, `AI`.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: основной IDE экран, Bottom Tool Panel (EN UI)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий editor runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: Кнопки действий `Project Settings` получили стабильный маркер `data-import-action=<SOURCE>:<mode>`; runtime smoke переведен на этот маркер и EN-сценарий теперь интерактивно запускает `Source preflight`, а не зависит от русского текста кнопки.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: Project Settings, Import Center (RU/EN UI)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: HTML smoke для `Project Settings` (RU/EN) расширен проверкой стабильных action markers `data-import-action="REFERENCE_CONFIGURATION:import"` и `data-import-action="XML_DUMP:check"`, чтобы import actions ловились быстрым контуром без Playwright.
|
||||||
|
Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`
|
||||||
|
Затронутые экраны: Project Settings, Import Center (RU/EN UI)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлен существующий editor smoke
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: `Top Project Bar` получил стабильные `data-*` маркеры для logo, selectors, actions, status badges, language switcher и profile button; `Badge` обновлен с passthrough `HTMLAttributes`, чтобы `data-*` атрибуты доходили до DOM. HTML и runtime smoke IDE переведены на эти маркеры. Дополнительно runtime smoke после reload явно возвращается на module-tab перед проверкой Monaco.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/src/components/ui/badge.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs`
|
||||||
|
Затронутые экраны: основной IDE экран, Top Project Bar, Open Objects Bar
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлены существующие `smoke:editor` и `smoke:editor:runtime`
|
||||||
|
|
||||||
|
Дата: 2026-05-12
|
||||||
|
Автор/Codex task: Codex
|
||||||
|
Что изменено: `Project Settings` секции получили стабильный маркер `data-settings-section`; HTML и runtime smoke переведены на него для ключевых разделов `task-session-policy`, `docker-runtime-adapter`, `its-documentation-access` в RU/EN сценариях.
|
||||||
|
Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs`
|
||||||
|
Затронутые экраны: Project Settings (RU/EN UI)
|
||||||
|
Изменен ли UI contract: нет
|
||||||
|
Нужны ли новые smoke tests: нет, обновлены существующие `smoke:editor` и `smoke:project-setup`
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# SFERA Frontend Product Contract
|
||||||
|
|
||||||
|
SFERA - это серверная semantic IDE-платформа для 1С, а не dashboard, CRM или файловый редактор.
|
||||||
|
|
||||||
|
## Главная модель
|
||||||
|
|
||||||
|
- Проект выбирается в верхней панели.
|
||||||
|
- Пользователь долго работает внутри одного проекта.
|
||||||
|
- Основной экран - IDE workspace последнего проекта.
|
||||||
|
- Если проекта нет - пустой workspace с выбором или созданием проекта.
|
||||||
|
- Левая панель - навигация по текущему проекту.
|
||||||
|
- Центр - рабочая область.
|
||||||
|
- Правая панель - контекстные свойства.
|
||||||
|
- Нижняя зона - открытые объекты, служебные панели и status bar.
|
||||||
|
|
||||||
|
## Product Principles
|
||||||
|
|
||||||
|
SFERA должна быть metadata-first: в 1С дерево объектов конфигурации представляет прикладное решение как древовидную структуру логически связанных объектов.
|
||||||
|
|
||||||
|
Расширения являются configuration-like структурами: расширение похоже на обычную конфигурацию и тоже представляется деревом объектов.
|
||||||
|
|
||||||
|
Формы - visual-first: формы 1С предназначены для просмотра и редактирования данных и могут принадлежать объектам конфигурации или быть общими.
|
||||||
|
|
||||||
|
Окно объекта конфигурации в 1С предназначено для редактирования свойств, управления подчиненными объектами и настройки взаимодействия объектов. SFERA должна расширять эту модель, а не заменять ее dashboard-карточками.
|
||||||
|
|
||||||
|
## Official 1C Documentation
|
||||||
|
|
||||||
|
При проектировании 1C-specific поведения использовать официальные источники:
|
||||||
|
|
||||||
|
- ITS;
|
||||||
|
- v8.1c.ru;
|
||||||
|
- 1C DN;
|
||||||
|
- локальные knowledge packs.
|
||||||
|
|
||||||
|
ITS credentials нельзя хранить в документации или репозитории. Доступ передается только через `.env.local`.
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
# SFERA IDE UI Contract
|
||||||
|
|
||||||
|
## 1. Основной экран
|
||||||
|
|
||||||
|
После входа открывается:
|
||||||
|
|
||||||
|
- последний проект пользователя;
|
||||||
|
- либо пустой IDE shell, если проекта нет.
|
||||||
|
|
||||||
|
Проект выбирается только в верхней панели.
|
||||||
|
|
||||||
|
Запрещено:
|
||||||
|
|
||||||
|
- показывать список проектов в левой панели;
|
||||||
|
- делать dashboard главным экраном;
|
||||||
|
- показывать fake-данные без импортированного проекта.
|
||||||
|
|
||||||
|
## 2. Главный Layout
|
||||||
|
|
||||||
|
Экран состоит из:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Top Project Bar
|
||||||
|
Left Navigation Panel
|
||||||
|
Main Workspace
|
||||||
|
Right Context Inspector
|
||||||
|
Open Objects Bar
|
||||||
|
Bottom Tool Panel
|
||||||
|
Status Bar
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Top Project Bar
|
||||||
|
|
||||||
|
Содержит:
|
||||||
|
|
||||||
|
- SFERA logo;
|
||||||
|
- Workspace selector;
|
||||||
|
- Project selector;
|
||||||
|
- Project settings button;
|
||||||
|
- Create project button;
|
||||||
|
- Environment selector;
|
||||||
|
- Active task selector;
|
||||||
|
- Global search;
|
||||||
|
- Agent/API status;
|
||||||
|
- Notifications;
|
||||||
|
- Language;
|
||||||
|
- User profile.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SFERA | Workspace v | Project v | Настройки | + Проект | Env v | Task v | Search...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Левая Панель
|
||||||
|
|
||||||
|
Левая панель - навигация текущего проекта.
|
||||||
|
|
||||||
|
Она содержит:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Проект: ERP Demo
|
||||||
|
├── Основная конфигурация
|
||||||
|
├── Расширение: <Имя>
|
||||||
|
├── Расширение: <Имя>
|
||||||
|
├── SFERA
|
||||||
|
└── Среды
|
||||||
|
```
|
||||||
|
|
||||||
|
Левая панель должна:
|
||||||
|
|
||||||
|
- сворачиваться;
|
||||||
|
- менять ширину;
|
||||||
|
- поддерживать поиск;
|
||||||
|
- поддерживать фильтры;
|
||||||
|
- поддерживать lazy loading;
|
||||||
|
- поддерживать virtual scroll;
|
||||||
|
- сохранять состояние раскрытия узлов.
|
||||||
|
|
||||||
|
## 5. Центр
|
||||||
|
|
||||||
|
Центр - основная рабочая область.
|
||||||
|
|
||||||
|
Там открываются:
|
||||||
|
|
||||||
|
- Object Workspace;
|
||||||
|
- Code Workspace;
|
||||||
|
- Form Designer;
|
||||||
|
- Report Designer;
|
||||||
|
- СКД Designer;
|
||||||
|
- Layout Designer;
|
||||||
|
- Project Settings;
|
||||||
|
- Task Workspace;
|
||||||
|
- Review Workspace;
|
||||||
|
- Runtime Workspace;
|
||||||
|
- Knowledge Workspace.
|
||||||
|
|
||||||
|
## 6. Правая Панель
|
||||||
|
|
||||||
|
Правая панель - Context Inspector.
|
||||||
|
|
||||||
|
Она показывает свойства выбранного объекта, элемента формы, процедуры, задачи, отчета, регистра, расширения.
|
||||||
|
|
||||||
|
Она не является навигацией.
|
||||||
|
|
||||||
|
## 7. Open Objects Bar
|
||||||
|
|
||||||
|
Внизу отображается панель открытых объектов:
|
||||||
|
|
||||||
|
```text
|
||||||
|
[Документ.ЗаказКлиента] [ФормаДокумента] [Модуль объекта] [TASK-123]
|
||||||
|
```
|
||||||
|
|
||||||
|
Поддерживает:
|
||||||
|
|
||||||
|
- быстрое переключение;
|
||||||
|
- закрытие;
|
||||||
|
- закрепление;
|
||||||
|
- восстановление после перезагрузки.
|
||||||
|
|
||||||
|
## 8. Bottom Tool Panel
|
||||||
|
|
||||||
|
Сворачиваемая служебная панель:
|
||||||
|
|
||||||
|
- Проблемы;
|
||||||
|
- Semantic diff;
|
||||||
|
- Вывод;
|
||||||
|
- История;
|
||||||
|
- Тесты;
|
||||||
|
- AI.
|
||||||
|
|
||||||
|
## 9. Status Bar
|
||||||
|
|
||||||
|
- Snapshot;
|
||||||
|
- Agent;
|
||||||
|
- Parser;
|
||||||
|
- Diagnostics;
|
||||||
|
- Active Task;
|
||||||
|
- Privacy;
|
||||||
|
- AI tokens;
|
||||||
|
- Current user.
|
||||||
|
|
||||||
|
## 10. Горячие Клавиши
|
||||||
|
|
||||||
|
- `Alt+1` - левая панель;
|
||||||
|
- `Alt+2` - правая панель;
|
||||||
|
- `Alt+3` - нижняя панель;
|
||||||
|
- `Ctrl+Tab` - следующий открытый объект;
|
||||||
|
- `Ctrl+Shift+Tab` - предыдущий объект;
|
||||||
|
- `Ctrl+W` - закрыть текущий объект;
|
||||||
|
- `Ctrl+K` - глобальный поиск;
|
||||||
|
- `F5` - запустить проверку.
|
||||||
@@ -0,0 +1,301 @@
|
|||||||
|
# SFERA Metadata Tree Contract
|
||||||
|
|
||||||
|
## 1. Верхний Уровень
|
||||||
|
|
||||||
|
```text
|
||||||
|
Проект
|
||||||
|
├── Основная конфигурация
|
||||||
|
├── Расширение: <name>
|
||||||
|
├── Расширение: <name>
|
||||||
|
├── SFERA
|
||||||
|
└── Среды
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. ConfigurationLikeRoot
|
||||||
|
|
||||||
|
Один компонент используется для:
|
||||||
|
|
||||||
|
- основной конфигурации;
|
||||||
|
- расширений;
|
||||||
|
- context-only конфигураций;
|
||||||
|
- reference конфигураций.
|
||||||
|
|
||||||
|
Типы:
|
||||||
|
|
||||||
|
- `MAIN_CONFIGURATION`;
|
||||||
|
- `EXTENSION`;
|
||||||
|
- `CONTEXT_CONFIGURATION`;
|
||||||
|
- `REFERENCE_CONFIGURATION`.
|
||||||
|
|
||||||
|
## 3. Структура ConfigurationLikeRoot
|
||||||
|
|
||||||
|
- Сведения;
|
||||||
|
- Общие;
|
||||||
|
- Константы;
|
||||||
|
- Справочники;
|
||||||
|
- Документы;
|
||||||
|
- Журналы документов;
|
||||||
|
- Перечисления;
|
||||||
|
- Отчеты;
|
||||||
|
- Обработки;
|
||||||
|
- Планы видов характеристик;
|
||||||
|
- Планы счетов;
|
||||||
|
- Планы видов расчета;
|
||||||
|
- Регистры сведений;
|
||||||
|
- Регистры накопления;
|
||||||
|
- Регистры бухгалтерии;
|
||||||
|
- Регистры расчета;
|
||||||
|
- Бизнес-процессы;
|
||||||
|
- Задачи 1С;
|
||||||
|
- Внешние источники данных.
|
||||||
|
|
||||||
|
## 4. Узел "Общие"
|
||||||
|
|
||||||
|
- Подсистемы;
|
||||||
|
- Общие модули;
|
||||||
|
- Параметры сеанса;
|
||||||
|
- Роли;
|
||||||
|
- Общие реквизиты;
|
||||||
|
- Планы обмена;
|
||||||
|
- Критерии отбора;
|
||||||
|
- Подписки на события;
|
||||||
|
- Регламентные задания;
|
||||||
|
- Боты;
|
||||||
|
- Функциональные опции;
|
||||||
|
- Параметры функциональных опций;
|
||||||
|
- Определяемые типы;
|
||||||
|
- Хранилища настроек;
|
||||||
|
- Общие команды;
|
||||||
|
- Группы команд;
|
||||||
|
- Общие формы;
|
||||||
|
- Общие макеты;
|
||||||
|
- Общие картинки;
|
||||||
|
- XDTO-пакеты;
|
||||||
|
- Web-сервисы;
|
||||||
|
- HTTP-сервисы;
|
||||||
|
- WS-ссылки;
|
||||||
|
- WebSocket-клиенты;
|
||||||
|
- Сервисы интеграции;
|
||||||
|
- Цвета палитры;
|
||||||
|
- Элементы стиля;
|
||||||
|
- Стили;
|
||||||
|
- Языки.
|
||||||
|
|
||||||
|
## 5. Object Tree Templates
|
||||||
|
|
||||||
|
### Справочник
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- Реквизиты;
|
||||||
|
- Табличные части;
|
||||||
|
- Формы;
|
||||||
|
- Команды;
|
||||||
|
- Макеты;
|
||||||
|
- Модуль объекта;
|
||||||
|
- Модуль менеджера;
|
||||||
|
- Права;
|
||||||
|
- Данные;
|
||||||
|
- Где используется;
|
||||||
|
- Кто читает;
|
||||||
|
- Кто записывает;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### Документ
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- Реквизиты;
|
||||||
|
- Табличные части;
|
||||||
|
- Формы;
|
||||||
|
- Команды;
|
||||||
|
- Макеты;
|
||||||
|
- Движения;
|
||||||
|
- Модуль объекта;
|
||||||
|
- Модуль менеджера;
|
||||||
|
- Права;
|
||||||
|
- Данные;
|
||||||
|
- Где используется;
|
||||||
|
- Кто создает;
|
||||||
|
- Кто проводит;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### Регистр Сведений
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- Измерения;
|
||||||
|
- Ресурсы;
|
||||||
|
- Реквизиты;
|
||||||
|
- Формы;
|
||||||
|
- Команды;
|
||||||
|
- Макеты;
|
||||||
|
- Модуль набора записей;
|
||||||
|
- Модуль менеджера;
|
||||||
|
- Права;
|
||||||
|
- Данные;
|
||||||
|
- Кто читает;
|
||||||
|
- Кто записывает;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### Регистр Накопления
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- Измерения;
|
||||||
|
- Ресурсы;
|
||||||
|
- Реквизиты;
|
||||||
|
- Формы;
|
||||||
|
- Команды;
|
||||||
|
- Макеты;
|
||||||
|
- Модуль набора записей;
|
||||||
|
- Модуль менеджера;
|
||||||
|
- Права;
|
||||||
|
- Данные;
|
||||||
|
- Кто читает;
|
||||||
|
- Кто записывает;
|
||||||
|
- Документы-регистраторы;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### Отчет
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- СКД;
|
||||||
|
- Формы;
|
||||||
|
- Команды;
|
||||||
|
- Макеты;
|
||||||
|
- Модуль объекта;
|
||||||
|
- Права;
|
||||||
|
- Данные;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### Обработка
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- Формы;
|
||||||
|
- Команды;
|
||||||
|
- Макеты;
|
||||||
|
- Модуль объекта;
|
||||||
|
- Права;
|
||||||
|
- Данные;
|
||||||
|
- Интеграции;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### Общий Модуль
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- Процедуры;
|
||||||
|
- Функции;
|
||||||
|
- Экспортные методы;
|
||||||
|
- Запросы;
|
||||||
|
- Записи;
|
||||||
|
- Вызовы;
|
||||||
|
- Кто вызывает;
|
||||||
|
- Транзакции;
|
||||||
|
- Runtime;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### Форма
|
||||||
|
|
||||||
|
- Дизайнер формы;
|
||||||
|
- Свойства;
|
||||||
|
- Реквизиты формы;
|
||||||
|
- Элементы;
|
||||||
|
- Команды;
|
||||||
|
- События;
|
||||||
|
- Модуль формы;
|
||||||
|
- Связи с объектом;
|
||||||
|
- Данные;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### Роль
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- Права на объекты;
|
||||||
|
- Права на реквизиты;
|
||||||
|
- Права на табличные части;
|
||||||
|
- RLS;
|
||||||
|
- Унаследованные права;
|
||||||
|
- Отличия от default rights;
|
||||||
|
- Пользователи с ролью;
|
||||||
|
- Проверки безопасности;
|
||||||
|
- Версии;
|
||||||
|
- Данные.
|
||||||
|
|
||||||
|
### HTTP-Сервис
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- URL-шаблоны;
|
||||||
|
- Методы;
|
||||||
|
- Обработчики;
|
||||||
|
- Контракты JSON;
|
||||||
|
- Безопасность;
|
||||||
|
- Runtime;
|
||||||
|
- Тестовые запросы;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### План Обмена
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- Узлы;
|
||||||
|
- Состав обмена;
|
||||||
|
- Авторегистрация;
|
||||||
|
- Правила регистрации;
|
||||||
|
- Формы;
|
||||||
|
- Команды;
|
||||||
|
- Модуль объекта;
|
||||||
|
- Модуль менеджера;
|
||||||
|
- Runtime;
|
||||||
|
- Данные;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
### Регламентное Задание
|
||||||
|
|
||||||
|
- Обзор;
|
||||||
|
- Свойства;
|
||||||
|
- Расписание;
|
||||||
|
- Обработчик;
|
||||||
|
- Параметры;
|
||||||
|
- Runtime;
|
||||||
|
- Связанные интеграции;
|
||||||
|
- Версии;
|
||||||
|
- Проверки.
|
||||||
|
|
||||||
|
## 6. Узел "Данные"
|
||||||
|
|
||||||
|
Узел "Данные" добавляется к объектам, где это применимо.
|
||||||
|
|
||||||
|
Режимы:
|
||||||
|
|
||||||
|
- `METADATA_ONLY`;
|
||||||
|
- `SANITIZED_SAMPLE`;
|
||||||
|
- `TEST_DATA`;
|
||||||
|
- `FULL_DATA`.
|
||||||
|
|
||||||
|
По умолчанию:
|
||||||
|
|
||||||
|
- `METADATA_ONLY`.
|
||||||
|
|
||||||
|
Правила:
|
||||||
|
|
||||||
|
- `FULL_DATA` только по RBAC;
|
||||||
|
- `FULL_DATA` всегда audit logged;
|
||||||
|
- AI не получает данные без explicit approval;
|
||||||
|
- данные привязаны к environment;
|
||||||
|
- данные маскируются по умолчанию.
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
# SFERA Project Settings Contract
|
||||||
|
|
||||||
|
## 1. Назначение
|
||||||
|
|
||||||
|
Настройки проекта - один из главных экранов SFERA.
|
||||||
|
|
||||||
|
Открывается из Top Project Bar через кнопку рядом с Project selector.
|
||||||
|
|
||||||
|
## 2. Разделы Настроек
|
||||||
|
|
||||||
|
```text
|
||||||
|
Основные сведения
|
||||||
|
Источники структуры 1С
|
||||||
|
Импорт конфигурации
|
||||||
|
Среды
|
||||||
|
Агенты
|
||||||
|
Расширения
|
||||||
|
Knowledge sources
|
||||||
|
Privacy
|
||||||
|
AI policy
|
||||||
|
Task/session policy
|
||||||
|
Пользователи и доступ
|
||||||
|
Интеграции задач
|
||||||
|
Docker/runtime adapter
|
||||||
|
ITS/documentation access
|
||||||
|
Audit
|
||||||
|
Backup/restore
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Основные Сведения
|
||||||
|
|
||||||
|
Поля:
|
||||||
|
|
||||||
|
- Название проекта;
|
||||||
|
- Код проекта;
|
||||||
|
- Описание;
|
||||||
|
- Workspace;
|
||||||
|
- Владелец;
|
||||||
|
- Тип проекта;
|
||||||
|
- Язык интерфейса;
|
||||||
|
- Язык кода 1С по умолчанию: русский / английский;
|
||||||
|
- Версия платформы;
|
||||||
|
- Режим совместимости.
|
||||||
|
|
||||||
|
## 4. Источники Структуры 1С
|
||||||
|
|
||||||
|
Поддерживаемые источники:
|
||||||
|
|
||||||
|
- `.cf` файл;
|
||||||
|
- `.cfe` файл;
|
||||||
|
- XML dump;
|
||||||
|
- Live infobase через Designer CLI;
|
||||||
|
- EPF agent snapshot;
|
||||||
|
- CFE agent snapshot;
|
||||||
|
- EDT project;
|
||||||
|
- Архив выгрузки;
|
||||||
|
- BSL/XML file tree;
|
||||||
|
- Context-only configuration;
|
||||||
|
- Reference configuration.
|
||||||
|
|
||||||
|
Для каждого источника:
|
||||||
|
|
||||||
|
- тип;
|
||||||
|
- статус;
|
||||||
|
- последний импорт;
|
||||||
|
- последняя ошибка;
|
||||||
|
- версия платформы;
|
||||||
|
- режим совместимости;
|
||||||
|
- количество объектов;
|
||||||
|
- количество модулей;
|
||||||
|
- количество форм;
|
||||||
|
- количество расширений.
|
||||||
|
|
||||||
|
## 5. Среды
|
||||||
|
|
||||||
|
- Dev;
|
||||||
|
- Test;
|
||||||
|
- Stage;
|
||||||
|
- Prod.
|
||||||
|
|
||||||
|
Для среды:
|
||||||
|
|
||||||
|
- тип;
|
||||||
|
- подключение;
|
||||||
|
- агент;
|
||||||
|
- источник данных;
|
||||||
|
- privacy mode;
|
||||||
|
- разрешение data preview;
|
||||||
|
- версия платформы;
|
||||||
|
- активные расширения.
|
||||||
|
|
||||||
|
## 6. Агенты
|
||||||
|
|
||||||
|
- EPF agent;
|
||||||
|
- CFE agent;
|
||||||
|
- runtime agent;
|
||||||
|
- diagnostic agent.
|
||||||
|
|
||||||
|
Поля:
|
||||||
|
|
||||||
|
- agent id;
|
||||||
|
- version;
|
||||||
|
- environment;
|
||||||
|
- last heartbeat;
|
||||||
|
- status;
|
||||||
|
- compatibility;
|
||||||
|
- download/update.
|
||||||
|
|
||||||
|
## 7. Расширения
|
||||||
|
|
||||||
|
Таблица:
|
||||||
|
|
||||||
|
- имя;
|
||||||
|
- версия;
|
||||||
|
- назначение;
|
||||||
|
- активно;
|
||||||
|
- безопасный режим;
|
||||||
|
- защита от опасных действий;
|
||||||
|
- область действия;
|
||||||
|
- источник;
|
||||||
|
- последний import;
|
||||||
|
- статус применимости.
|
||||||
|
|
||||||
|
Действия:
|
||||||
|
|
||||||
|
- загрузить `.cfe`;
|
||||||
|
- получить из live base;
|
||||||
|
- обновить snapshot;
|
||||||
|
- проверить применимость;
|
||||||
|
- сравнить с основной конфигурацией;
|
||||||
|
- построить effective configuration.
|
||||||
|
|
||||||
|
## 8. ITS/Documentation Access
|
||||||
|
|
||||||
|
Документация 1С используется для проверки 1С-specific поведения.
|
||||||
|
|
||||||
|
Источники:
|
||||||
|
|
||||||
|
- ITS;
|
||||||
|
- v8.1c.ru;
|
||||||
|
- 1C DN;
|
||||||
|
- локальные knowledge packs.
|
||||||
|
|
||||||
|
ITS credentials нельзя хранить в репозитории.
|
||||||
|
|
||||||
|
Использовать только переменные окружения:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
SFERA_ITS_URL=<ITS_URL>
|
||||||
|
SFERA_ITS_USERNAME=<ITS_USERNAME>
|
||||||
|
SFERA_ITS_PASSWORD=<ITS_PASSWORD>
|
||||||
|
```
|
||||||
|
|
||||||
|
Локальный файл:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.env.local
|
||||||
|
```
|
||||||
|
|
||||||
|
Пример для локальной настройки:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
SFERA_ITS_URL=https://its.1c.ru/db/v838doc#browse:13:-1:7
|
||||||
|
SFERA_ITS_USERNAME=<set locally>
|
||||||
|
SFERA_ITS_PASSWORD=<set locally>
|
||||||
|
```
|
||||||
|
|
||||||
|
Запрещено:
|
||||||
|
|
||||||
|
- коммитить логин или пароль;
|
||||||
|
- писать логин или пароль в markdown;
|
||||||
|
- писать логин или пароль в Dockerfile;
|
||||||
|
- выводить логин или пароль в logs.
|
||||||
|
|
||||||
|
## 9. Privacy
|
||||||
|
|
||||||
|
- `METADATA_ONLY`;
|
||||||
|
- `SANITIZED_SAMPLE`;
|
||||||
|
- `TEST_DATA`;
|
||||||
|
- `FULL_DATA`.
|
||||||
|
|
||||||
|
По умолчанию:
|
||||||
|
|
||||||
|
- `METADATA_ONLY`.
|
||||||
|
|
||||||
|
## 10. Task/Session Policy
|
||||||
|
|
||||||
|
- `STRICT`;
|
||||||
|
- `SOFT`;
|
||||||
|
- `LOCAL_DEV`.
|
||||||
|
|
||||||
|
Enterprise default:
|
||||||
|
|
||||||
|
- `STRICT`.
|
||||||
@@ -0,0 +1,282 @@
|
|||||||
|
# SFERA Stand Runbook
|
||||||
|
|
||||||
|
## Network API
|
||||||
|
|
||||||
|
- API: `http://192.168.200.60:8000`
|
||||||
|
- Swagger: `http://192.168.200.60:8000/docs`
|
||||||
|
- Health: `GET /health`
|
||||||
|
- Summary: `GET /admin/summary`
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
This OS runs inside a VM. Do not install or use a local Docker Engine here.
|
||||||
|
|
||||||
|
Use the shared Docker host for Docker/integration stands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker -H ssh://test-docker ps
|
||||||
|
```
|
||||||
|
|
||||||
|
Shared host:
|
||||||
|
|
||||||
|
- SSH alias: `test-docker` / `docker-test`
|
||||||
|
- Host: `docker-test.cin.su`
|
||||||
|
- User: `test`
|
||||||
|
|
||||||
|
Integrated SFERA testing must be deployed on `docker-test`, including both backend/server
|
||||||
|
services and the frontend service. Do not fall back to local Docker Engine for project testing.
|
||||||
|
|
||||||
|
## Neo4j
|
||||||
|
|
||||||
|
Neo4j runs on `docker-test` as container `sfera-neo4j`.
|
||||||
|
|
||||||
|
- Browser: `http://docker-test.cin.su:17474`
|
||||||
|
- Bolt: `bolt://docker-test.cin.su:17687`
|
||||||
|
- User: `neo4j`
|
||||||
|
- Password: `password`
|
||||||
|
|
||||||
|
API uses:
|
||||||
|
|
||||||
|
```text
|
||||||
|
NEO4J_URI=bolt://docker-test.cin.su:17687
|
||||||
|
NEO4J_USER=neo4j
|
||||||
|
NEO4J_PASSWORD=password
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rust BSL Parser
|
||||||
|
|
||||||
|
Build the parser locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd rust
|
||||||
|
cargo build -p bsl-parser
|
||||||
|
```
|
||||||
|
|
||||||
|
API indexing consumes the Rust JSON contract automatically when the built parser is found at
|
||||||
|
`rust\target\debug\bsl-parser.exe`. To force a specific parser binary, set:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SFERA_BSL_PARSER=rust\target\debug\bsl-parser.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
If no parser binary is configured or auto-discovered, `semantic-kernel` uses the built-in Python parser fallback.
|
||||||
|
|
||||||
|
## Runtime Adapter / 1C Access
|
||||||
|
|
||||||
|
`sfera-runtime-adapter` is a separate container/service. It must stay separate from `sfera-api`.
|
||||||
|
|
||||||
|
Modes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
RUNTIME_ADAPTER_MODE=mock
|
||||||
|
RUNTIME_ADAPTER_MODE=local_1c
|
||||||
|
RUNTIME_ADAPTER_MODE=remote_worker
|
||||||
|
```
|
||||||
|
|
||||||
|
`mock` is the default Docker mode and does not require a 1C platform inside Linux containers. `local_1c` can normalize EDT/XML/file-tree sources without executing Designer. For `.cf`, `.cfe`, archive, and live infobase sources it first returns a safe `designer_dump_planned` response unless execution is explicitly enabled on a trusted worker.
|
||||||
|
|
||||||
|
Platform discovery:
|
||||||
|
|
||||||
|
- Set `ONEC_DESIGNER_PATH` when the worker has a known Designer CLI path.
|
||||||
|
- If it is empty, runtime-adapter tries common install roots such as `C:\Program Files\1cv8\*\bin\1cv8.exe`.
|
||||||
|
- Set `ONEC_DISABLE_AUTO_DISCOVERY=true` to turn discovery off in tests.
|
||||||
|
- Check `GET /runtime/platform` for `platform_found`, `designer_path`, `discovered_paths`, capabilities, and diagnostics.
|
||||||
|
|
||||||
|
Credentials rule:
|
||||||
|
|
||||||
|
- Do not store live 1C credentials in repository files, compose files, docs, fixtures, or logs.
|
||||||
|
- Use `credentials_ref` such as `runtime://prompt/live-upo` or a real vault reference.
|
||||||
|
- Runtime dump plans redact password-like keys in connection strings before returning diagnostics.
|
||||||
|
|
||||||
|
Useful local checks, without storing secrets:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-Path "C:\EDT\projects\iFCM-UPO"
|
||||||
|
Invoke-WebRequest -UseBasicParsing -Uri "http://192.168.200.95/upo/ru_RU/" -TimeoutSec 10
|
||||||
|
Get-ChildItem "C:\Program Files\1cv8","C:\Program Files (x86)\1cv8" -Recurse -Filter 1cv8.exe -ErrorAction SilentlyContinue
|
||||||
|
```
|
||||||
|
|
||||||
|
## Smoke Flow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
POST /projects/demo/index
|
||||||
|
POST /projects/{project_id}/incremental/file
|
||||||
|
POST /projects/demo/graph/neo4j/project
|
||||||
|
GET /projects/demo/graph/neo4j/callees/Проведение
|
||||||
|
GET /projects/demo/graph/neo4j/writes/Проведение
|
||||||
|
GET /projects/{project_id}/objects/impact/{object_name}
|
||||||
|
GET /projects/{project_id}/objects/attributes/{object_name}
|
||||||
|
GET /projects/{project_id}/objects/schema/{object_name}
|
||||||
|
GET /projects/{project_id}/objects/tabular-sections/{object_name}
|
||||||
|
GET /projects/{project_id}/objects/tabular-sections/{object_name}/columns
|
||||||
|
GET /projects/{project_id}/objects/ui/{object_name}
|
||||||
|
GET /projects/{project_id}/graph/neo4j/objects/attributes/{object_name}
|
||||||
|
GET /projects/{project_id}/graph/neo4j/objects/schema/{object_name}
|
||||||
|
GET /projects/{project_id}/graph/neo4j/objects/tabular-sections/{object_name}
|
||||||
|
GET /projects/{project_id}/graph/neo4j/objects/tabular-sections/{object_name}/columns
|
||||||
|
GET /projects/{project_id}/graph/neo4j/objects/impact/{object_name}
|
||||||
|
GET /projects/{project_id}/graph/neo4j/objects/ui/{object_name}
|
||||||
|
GET /projects/{project_id}/access/objects/{object_name}/roles
|
||||||
|
GET /projects/{project_id}/access/roles/{role_name}/objects
|
||||||
|
GET /projects/{project_id}/jobs/scheduled
|
||||||
|
GET /projects/{project_id}/integrations
|
||||||
|
GET /projects/{project_id}/graph/neo4j/integrations
|
||||||
|
GET /projects/{project_id}/graph/neo4j/integrations/{integration_name}/modules
|
||||||
|
GET /projects/{project_id}/graph/neo4j/access/objects/{object_name}/roles
|
||||||
|
GET /projects/{project_id}/graph/neo4j/access/roles/{role_name}/objects
|
||||||
|
POST /knowledge/packs
|
||||||
|
GET /knowledge/packs
|
||||||
|
GET /projects/{project_id}/knowledge/schema-coverage
|
||||||
|
GET /projects/{project_id}/patterns
|
||||||
|
POST /projects/{project_id}/comments
|
||||||
|
GET /projects/{project_id}/comments
|
||||||
|
GET /projects/{project_id}/comments/{target_id}
|
||||||
|
POST /projects/{project_id}/ownership
|
||||||
|
GET /projects/{project_id}/ownership
|
||||||
|
GET /projects/{project_id}/objects/ownership/{object_name}
|
||||||
|
POST /projects/{project_id}/privacy/markers
|
||||||
|
GET /projects/{project_id}/privacy/markers
|
||||||
|
GET /projects/{project_id}/objects/privacy/{object_name}
|
||||||
|
POST /ai/usage
|
||||||
|
GET /ai/usage
|
||||||
|
GET /ai/usage/summary
|
||||||
|
GET /ai/policy
|
||||||
|
POST /projects/{project_id}/ai/answer-policy
|
||||||
|
GET /projects/{project_id}/review
|
||||||
|
GET /projects/{project_id}/report
|
||||||
|
GET /graph/neo4j/status
|
||||||
|
```
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
Frontend app:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Z:\codex\SFERA\frontend\sfera-web
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the mapped `Z:` drive. It points to `\\nas\MST` and avoids Windows tooling issues with UNC current directories:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
cd /d Z:\codex\SFERA\frontend\sfera-web
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Always run frontend `npm` commands from the mapped `Z:` drive. Do not use `\\nas\MST\...` as the current directory: Windows `cmd.exe` does not support UNC current directories and falls back to `C:\Windows`, which makes npm scripts fail with missing `package.json`.
|
||||||
|
|
||||||
|
Default URL:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://192.168.200.60:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
Editor direct links:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://192.168.200.60:3000/editor?project=demo&mode=module
|
||||||
|
http://192.168.200.60:3000/editor?project=demo&mode=form
|
||||||
|
http://192.168.200.60:3000/editor?project=demo&mode=events
|
||||||
|
http://192.168.200.60:3000/editor?project=demo&mode=learning
|
||||||
|
```
|
||||||
|
|
||||||
|
Lightweight frontend smoke check against the running stand:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
cd /d Z:\codex\SFERA\frontend\sfera-web
|
||||||
|
npm run smoke:editor
|
||||||
|
```
|
||||||
|
|
||||||
|
Browser runtime smoke check against the running stand:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
cd /d Z:\codex\SFERA\frontend\sfera-web
|
||||||
|
npm run smoke:editor:runtime
|
||||||
|
```
|
||||||
|
|
||||||
|
Project Setup / Import Center runtime smoke check against the running stand:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
cd /d Z:\codex\SFERA\frontend\sfera-web
|
||||||
|
npm run smoke:project-setup
|
||||||
|
```
|
||||||
|
|
||||||
|
Full editor smoke check:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
cd /d Z:\codex\SFERA\frontend\sfera-web
|
||||||
|
npm run smoke:editor:all
|
||||||
|
```
|
||||||
|
|
||||||
|
Override the checked frontend URL when needed:
|
||||||
|
|
||||||
|
```bat
|
||||||
|
set SFERA_WEB_URL=http://docker-test.cin.su:3000
|
||||||
|
npm run smoke:editor:all
|
||||||
|
```
|
||||||
|
|
||||||
|
`smoke:editor` checks server-rendered HTML for the overview and editor modes and retries briefly while a freshly started stand settles. `smoke:editor:runtime` launches the installed Chrome/Edge through `playwright-core`, catches browser runtime errors, verifies Monaco in module mode, opens the Versions tab, clicks a version row, checks full version payload details, and exercises metadata draft preview/apply through the API. `smoke:project-setup` prepares the `default` project through the web API proxy, verifies the new Project Setup / IDE Shell route, and saves a metadata draft to workspace history. Set `SFERA_BROWSER_PATH` if Chrome/Edge is installed in a non-standard location.
|
||||||
|
|
||||||
|
Docker health smoke can include the Project Setup browser smoke:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\smoke-test-docker.ps1 `
|
||||||
|
-ApiUrl http://docker-test.cin.su:8000 `
|
||||||
|
-WebUrl http://docker-test.cin.su:3000 `
|
||||||
|
-Neo4jUrl http://docker-test.cin.su:7474 `
|
||||||
|
-QdrantUrl http://docker-test.cin.su:6333 `
|
||||||
|
-ObjectStorageUrl http://docker-test.cin.su:9000 `
|
||||||
|
-IncludeProjectSetupSmoke
|
||||||
|
```
|
||||||
|
|
||||||
|
The frontend resolves the API endpoint in this order:
|
||||||
|
|
||||||
|
1. `SFERA_API_URL`
|
||||||
|
2. `NEXT_PUBLIC_SFERA_API_URL`
|
||||||
|
3. the current panel host with API port `8000`
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://192.168.200.60:3000 -> http://192.168.200.60:8000
|
||||||
|
http://docker-test.cin.su:3000 -> http://docker-test.cin.su:8000
|
||||||
|
http://127.0.0.1:3001 -> http://localhost:8000
|
||||||
|
```
|
||||||
|
|
||||||
|
If the API moves to another address or port, set:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SFERA_API_URL=http://api-host:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
If only the derived API port changes, set:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SFERA_API_PORT=8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not use `127.0.0.1:8000` as the panel default, because browsers are normally opened from another computer in the LAN. Full Docker stands should run on `docker-test`; local mode is only for the current API + Next.js development loop without a local Docker Engine.
|
||||||
|
|
||||||
|
Browser-side editor actions call the API directly, so API CORS must allow the panel origin. By default the API allows localhost, LAN `192.168.*.*` origins, and `docker-test.cin.su`. Override with `SFERA_CORS_ORIGIN_REGEX` only when the stand moves to a different trusted host pattern.
|
||||||
|
|
||||||
|
Expected demo projection:
|
||||||
|
|
||||||
|
```text
|
||||||
|
nodes: 5
|
||||||
|
edges: 6
|
||||||
|
```
|
||||||
|
|
||||||
|
After a project has been projected once to Neo4j, `POST /projects/{project_id}/incremental/file` automatically applies the SIR delta to that project's Neo4j graph. Check `neo4j_projected` / `neo4j_error` in the response.
|
||||||
|
|
||||||
|
Object impact includes 1C role access when XML contains role rights, for example `Role -> Right object="Документ.ЗаказПокупателя"`.
|
||||||
|
|
||||||
|
Knowledge packs are stored in `knowledge_packs`; importing a BSP/vendor pack also persists enriched `knowledge` records with `pack:{pack_id}` and `vendor:{vendor}` tags for search and coverage.
|
||||||
|
|
||||||
|
Pattern mining is available via `GET /projects/{project_id}/patterns?min_support=2` and reports repeated table reads/writes and repeated routine read/write shapes.
|
||||||
|
|
||||||
|
Ownership is stored in `collaboration_ownership` and is scoped by project + target lineage. Project review reports `Missing 1C object owner` for root 1C objects without an assigned owner; project report includes ownership and unowned-object counters.
|
||||||
|
|
||||||
|
Privacy markers are stored in `privacy_markers` and are scoped by project + target lineage. Review reports `Unclassified sensitive 1C field` for likely sensitive 1C attributes such as ИНН, паспорт, телефон, email, адрес when no privacy classification exists.
|
||||||
|
|
||||||
|
AI usage records are stored in `ai_usage`. Use `GET /ai/usage/summary?project_id=...` for dashboard counters and `GET /ai/policy?user_id=...` before AI actions to show token limits and remaining allowance.
|
||||||
|
|
||||||
|
AI answer policy is available via `POST /projects/{project_id}/ai/answer-policy`. It does not generate an answer; it returns `allowed`, blocking reasons, warnings, matching knowledge records, privacy markers, and remaining token budget.
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
# SFERA Completion Plan
|
||||||
|
|
||||||
|
Дата аудита: 2026-05-10.
|
||||||
|
|
||||||
|
Этот план фиксирует путь к завершению SFERA как продукта. Он не подменяет
|
||||||
|
`IMPLEMENTATION_ORDER.md`, а добавляет проверяемые критерии готовности и текущий статус.
|
||||||
|
|
||||||
|
## Текущее состояние
|
||||||
|
|
||||||
|
SFERA уже содержит рабочий backend/API, Rust BSL parser, SIR, semantic kernel,
|
||||||
|
projection/incremental контур, runtime/governance/knowledge/collaboration пакеты и Next.js IDE.
|
||||||
|
|
||||||
|
Текущая проверенная база:
|
||||||
|
|
||||||
|
- Python/API tests: `161 passed`.
|
||||||
|
- Rust tests: `14 passed`.
|
||||||
|
- Frontend `typecheck`: passed.
|
||||||
|
- Frontend production `next build`: passed.
|
||||||
|
- Editor smoke: passed.
|
||||||
|
- Editor runtime smoke: passed.
|
||||||
|
|
||||||
|
## Definition Of Done
|
||||||
|
|
||||||
|
Проект считается завершённым для production-ready milestone, когда выполнены все пункты:
|
||||||
|
|
||||||
|
1. Все фазы из `IMPLEMENTATION_ORDER.md` имеют deterministic implementation без placeholder/stub.
|
||||||
|
2. Все parser bugs покрыты golden fixtures.
|
||||||
|
3. SIR snapshot validates для BSL/XML metadata projects.
|
||||||
|
4. Projection and incremental update pass against in-memory and Neo4j-compatible contracts.
|
||||||
|
5. API exposes project, semantic, governance, knowledge, collaboration and IDE workflows.
|
||||||
|
6. Frontend builds production bundle and passes editor smoke/runtime checks.
|
||||||
|
7. Stand runbook is executable on local/NAS and shared Docker host.
|
||||||
|
8. A single verification command can reproduce core/backend/Rust/frontend checks.
|
||||||
|
|
||||||
|
## Phase Plan
|
||||||
|
|
||||||
|
### Phase 1 — Semantic Core
|
||||||
|
|
||||||
|
Status: mostly complete.
|
||||||
|
|
||||||
|
Completed:
|
||||||
|
|
||||||
|
- `packages/sir`.
|
||||||
|
- `rust/crates/bsl-parser`.
|
||||||
|
- Rust `query-parser` foundation.
|
||||||
|
- Rust `semantic-engine` foundation.
|
||||||
|
- `packages/semantic-kernel`.
|
||||||
|
- `packages/projection-engine`.
|
||||||
|
- `packages/incremental-indexer`.
|
||||||
|
- Golden fixtures for mixed RU/EN syntax, calls, queries, writes, object writes and recordset writes.
|
||||||
|
- Same-module routine resolution priority for duplicate routine names.
|
||||||
|
- SIR diagnostics for malformed BSL routine/query boundaries.
|
||||||
|
- Incremental diagnostic refresh for changed BSL fragments.
|
||||||
|
- Routine `Экспорт` / `Export` flags preserved in SIR node attributes.
|
||||||
|
- BSL control-flow fixture for calls/writes inside loops and try/except blocks.
|
||||||
|
- Form event handler links from XML metadata to BSL routines.
|
||||||
|
|
||||||
|
Remaining:
|
||||||
|
|
||||||
|
- Keep parser and XML fixtures expanding as new 1C export patterns are encountered.
|
||||||
|
|
||||||
|
### Phase 2 — Object Runtime
|
||||||
|
|
||||||
|
Status: implemented with tests, needs broader fixtures.
|
||||||
|
|
||||||
|
Completed:
|
||||||
|
|
||||||
|
- XML metadata fixtures preserve register dimensions/resources as SIR attributes.
|
||||||
|
- Semantic versioning classifies object rename/move/update changes.
|
||||||
|
- Object impact includes form event handlers and their register writes.
|
||||||
|
- XML fixtures cover child-element forms, commands and role rights.
|
||||||
|
- Query intelligence reports register read/write dependencies.
|
||||||
|
- Transaction topology groups routines by written register target.
|
||||||
|
- Object impact can include scheduled-job integration endpoints from the owning module.
|
||||||
|
|
||||||
|
Remaining:
|
||||||
|
|
||||||
|
- Add more impact/review fixtures for object-level dependency edge cases as new patterns are found.
|
||||||
|
|
||||||
|
### Phase 3 — Runtime Intelligence
|
||||||
|
|
||||||
|
Status: implemented with tests, needs integration depth.
|
||||||
|
|
||||||
|
Remaining:
|
||||||
|
|
||||||
|
- Expand transaction/query intelligence with register movement patterns.
|
||||||
|
- Connect UI semantics to editor panels and review findings.
|
||||||
|
- Add scheduled job and integration cross-links to impact reports.
|
||||||
|
|
||||||
|
### Phase 4 — Knowledge System
|
||||||
|
|
||||||
|
Status: implemented with tests.
|
||||||
|
|
||||||
|
Remaining:
|
||||||
|
|
||||||
|
- Add import fixtures for larger BSP/vendor packs.
|
||||||
|
- Add coverage reports by metadata subtree.
|
||||||
|
|
||||||
|
### Phase 5 — Collaboration
|
||||||
|
|
||||||
|
Status: implemented with tests.
|
||||||
|
|
||||||
|
Remaining:
|
||||||
|
|
||||||
|
- Enforce task/session binding for mutations outside Phase 1 placeholders.
|
||||||
|
- Add UI flow coverage for comments/ownership/activity.
|
||||||
|
|
||||||
|
### Phase 6 — Governance/Operations
|
||||||
|
|
||||||
|
Status: implemented with tests.
|
||||||
|
|
||||||
|
Remaining:
|
||||||
|
|
||||||
|
- Verify full stand runbook on `test-docker`.
|
||||||
|
- Add backup/restore and migration smoke checks.
|
||||||
|
|
||||||
|
### Phase 7 — 1C IDE / Authoring
|
||||||
|
|
||||||
|
Status: working Next.js IDE exists and passes smoke; advanced authoring remains product work.
|
||||||
|
|
||||||
|
Completed:
|
||||||
|
|
||||||
|
- Backend and typed frontend API client for symbol search, go to definition and find references.
|
||||||
|
|
||||||
|
Remaining:
|
||||||
|
|
||||||
|
- Wire editor actions for go to definition, find references and symbol search into IDE panels.
|
||||||
|
- Complete semantic autocomplete from SIR + metadata context.
|
||||||
|
- Complete guarded apply with preview, semantic diff, impact, review, RBAC/privacy and version record.
|
||||||
|
- Complete object/form/report designer flows.
|
||||||
|
- Add browser smoke for key authoring flows.
|
||||||
|
|
||||||
|
### AI Layer
|
||||||
|
|
||||||
|
Status: intentionally gated until semantic truth is stronger.
|
||||||
|
|
||||||
|
Remaining:
|
||||||
|
|
||||||
|
- Add answer/generation policy enforcement to every AI-facing endpoint.
|
||||||
|
- Add prompt/context builders over SIR, metadata, knowledge, privacy and task/session.
|
||||||
|
- Add preview-only AI code generation and guarded apply workflow.
|
||||||
|
|
||||||
|
## Execution Order From Here
|
||||||
|
|
||||||
|
1. Keep all current green checks green with `scripts/check_all.ps1`.
|
||||||
|
2. Finish Phase 1 hardening fixtures and diagnostics.
|
||||||
|
3. Expand Phase 2/3 fixtures around metadata, impact, query and runtime topology.
|
||||||
|
4. Finish guarded apply and object-level authoring API.
|
||||||
|
5. Finish IDE authoring UI and smoke coverage.
|
||||||
|
6. Add AI pair-programmer only after guarded apply is deterministic.
|
||||||
|
7. Verify full stand on local/NAS and shared Docker host.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\check_all.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected checks:
|
||||||
|
|
||||||
|
- `cargo test && cargo build -p bsl-parser`
|
||||||
|
- `uv run pytest`
|
||||||
|
- `npm run typecheck`
|
||||||
|
- `next build`
|
||||||
|
- optional frontend smoke checks when API/frontend stand is running.
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
# Реальный порядок реализации
|
||||||
|
|
||||||
|
## Phase 1 — Semantic Core
|
||||||
|
|
||||||
|
1. `packages/sir`
|
||||||
|
2. `rust/crates/bsl-parser`
|
||||||
|
- deterministic BSL parser;
|
||||||
|
- JSON CLI contract for Python semantic-kernel integration.
|
||||||
|
3. `packages/semantic-kernel`
|
||||||
|
- current Python parser remains compatible;
|
||||||
|
- consumes Rust parser JSON as canonical BSL parse source when the CLI is configured or auto-discovered;
|
||||||
|
- metadata object to BSL module links via `CONTAINS`.
|
||||||
|
4. `packages/projection-engine`
|
||||||
|
5. `packages/incremental-indexer`
|
||||||
|
|
||||||
|
## Phase 2 — Object Runtime
|
||||||
|
|
||||||
|
1. `packages/one-c-normalizer`
|
||||||
|
- BSL source normalization;
|
||||||
|
- XML metadata extraction for core 1C objects.
|
||||||
|
2. `packages/semantic-versioning`
|
||||||
|
3. `packages/semantic-search`
|
||||||
|
4. `packages/impact-engine`
|
||||||
|
5. `packages/review-engine`
|
||||||
|
|
||||||
|
## Phase 3 — Runtime Intelligence
|
||||||
|
|
||||||
|
1. `runtime-overlays`
|
||||||
|
2. `transaction-topology`
|
||||||
|
3. `query-intelligence`
|
||||||
|
4. `ui-semantics`
|
||||||
|
5. `integration-topology`
|
||||||
|
6. `job-topology`
|
||||||
|
|
||||||
|
## Phase 4 — Knowledge System
|
||||||
|
|
||||||
|
1. global/workspace/project knowledge; ✅
|
||||||
|
2. BSP/vendor docs; ✅
|
||||||
|
3. pattern mining; ✅
|
||||||
|
4. knowledge coverage; ✅
|
||||||
|
5. AI answer policy. ✅
|
||||||
|
|
||||||
|
## Phase 5 — Collaboration
|
||||||
|
|
||||||
|
1. users/workspaces/projects; ✅
|
||||||
|
2. tasks/sessions; ✅
|
||||||
|
3. comments/discussions; ✅
|
||||||
|
4. activity feed; ✅
|
||||||
|
5. ownership. ✅
|
||||||
|
|
||||||
|
## Phase 6 — Governance/Operations
|
||||||
|
|
||||||
|
RBAC ✅, privacy ✅, AI usage ✅, jobs ✅, observability ✅, reports ✅, marketplace ✅, licensing ✅, admin ✅.
|
||||||
|
|
||||||
|
## Phase 7 — 1C IDE / Authoring
|
||||||
|
|
||||||
|
Reference workflow: берём лучшие рабочие паттерны 1С Конфигуратора, но реализуем их как современную AI IDE. Обязательны дерево конфигурации, вкладки открытых объектов, режимы модуль/форма/свойства/события, инспектор, нижние панели проблем/output/diff и быстрый поиск. Дополнительно SFERA должна объединять версии, документацию, знания, обучение, audit и guarded apply.
|
||||||
|
|
||||||
|
1. BSL editor foundation:
|
||||||
|
- syntax highlighting;
|
||||||
|
- diagnostics;
|
||||||
|
- outline;
|
||||||
|
- go to definition;
|
||||||
|
- find references;
|
||||||
|
- symbol search.
|
||||||
|
2. Semantic autocomplete:
|
||||||
|
- current procedure/function context;
|
||||||
|
- local variables and parameters;
|
||||||
|
- object attributes;
|
||||||
|
- tabular sections and columns;
|
||||||
|
- form elements and commands;
|
||||||
|
- known 1C platform APIs;
|
||||||
|
- mixed Russian/English 1C syntax.
|
||||||
|
3. AI pair programmer:
|
||||||
|
- code continuation;
|
||||||
|
- procedure/function generation;
|
||||||
|
- query generation;
|
||||||
|
- register movement generation;
|
||||||
|
- command/form handler generation;
|
||||||
|
- explanation of proposed code.
|
||||||
|
4. 1C object designer:
|
||||||
|
- create/update document/catalog/register/common module metadata;
|
||||||
|
- create/update attributes and tabular sections;
|
||||||
|
- create/update commands, forms, form elements and reports.
|
||||||
|
5. Semantic diff and guarded apply:
|
||||||
|
- preview every manual or AI change;
|
||||||
|
- impact analysis before apply;
|
||||||
|
- review findings before apply;
|
||||||
|
- privacy/RBAC checks;
|
||||||
|
- object-level version record;
|
||||||
|
- rollback point.
|
||||||
|
6. IDE-grade UX:
|
||||||
|
- editor workspace;
|
||||||
|
- object tree;
|
||||||
|
- mode bar: module/form/properties/events/versions/docs/knowledge/training;
|
||||||
|
- properties inspector;
|
||||||
|
- form/report designer;
|
||||||
|
- terminal/command palette;
|
||||||
|
- AI assistant panel;
|
||||||
|
- problems/references/output panels.
|
||||||
|
|
||||||
|
7. Documentation/knowledge/training inside IDE:
|
||||||
|
- docs linked to objects, forms, reports, events and routines;
|
||||||
|
- project/vendor/BSP knowledge available next to the code;
|
||||||
|
- team patterns, decisions and examples surfaced by current context;
|
||||||
|
- learning hints for the selected object and available variables;
|
||||||
|
- search across code, metadata, docs, versions and discussions.
|
||||||
|
|
||||||
|
## Frontend/UI Gate
|
||||||
|
|
||||||
|
Перед началом UI-этапа перечитать и применить актуальные требования:
|
||||||
|
|
||||||
|
- `docs/design-system.md`
|
||||||
|
- `docs/codex-ui-guidelines.md`
|
||||||
|
- `docs/ui-ux-roadmap.md`
|
||||||
|
- `docs/component-architecture.md`
|
||||||
|
- `docs/frontend-stack.md`
|
||||||
|
- `prompts/system-frontend-architect.md`
|
||||||
|
- `prompts/ui-generation-prompt.md`
|
||||||
|
|
||||||
|
Ключевой принцип: SFERA UI должен ощущаться как современная Enterprise AI IDE / Operating System для 1С, а не legacy CRM. Каждый экран обязан иметь AppShell-compatible layout, loading/error/empty/permission states, адаптивность, права доступа, audit trail для важных действий, таблицы с фильтрами/saved views/bulk actions и AI token/cost impact для AI-действий. Для authoring-экранов обязательны editor/object tree/properties inspector/problems/diff/preview/apply states.
|
||||||
|
|
||||||
|
Язык UI/команд: русский по умолчанию, но каждый пользовательский экран должен иметь выбор английского интерфейса. Команды в интерфейсе также проектируются с русским вариантом по умолчанию и английским вариантом как доступным режимом. 1С-код может смешивать русские и английские ключевые слова в одном тексте; parser/review/UI не должны считать это ошибкой.
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# UI/UX Roadmap SFERA
|
||||||
|
|
||||||
|
SFERA UI — это современная IDE/операционная среда для 1С, а не CRM.
|
||||||
|
|
||||||
|
Для authoring-экранов 1С Конфигуратор является источником сильных workflow-паттернов: дерево конфигурации, вкладки открытых объектов, режимы модуль/форма/свойства/события, правый инспектор и нижние панели. SFERA не повторяет legacy-внешний вид, а переносит эти паттерны в современную AI IDE.
|
||||||
|
|
||||||
|
## Этап 1 — Foundation
|
||||||
|
|
||||||
|
- AppShell
|
||||||
|
- Sidebar
|
||||||
|
- Topbar
|
||||||
|
- theme tokens
|
||||||
|
- auth layout
|
||||||
|
- workspace layout
|
||||||
|
- command palette
|
||||||
|
- базовый 1С dashboard
|
||||||
|
- permissions scaffold
|
||||||
|
- audit trail scaffold
|
||||||
|
|
||||||
|
## Этап 2 — 1С Semantic Workspace
|
||||||
|
|
||||||
|
- дерево проектов 1С
|
||||||
|
- дерево объектов конфигурации
|
||||||
|
- SIR snapshots
|
||||||
|
- semantic graph view
|
||||||
|
- object details inspector
|
||||||
|
- impact analysis
|
||||||
|
- review findings
|
||||||
|
- knowledge coverage
|
||||||
|
- роли и права 1С
|
||||||
|
- privacy markers
|
||||||
|
|
||||||
|
## Этап 3 — IDE Workspace
|
||||||
|
|
||||||
|
- BSL code editor
|
||||||
|
- рабочие режимы: модуль, форма, свойства, события, версии, документация, знания, обучение
|
||||||
|
- подсветка синтаксиса
|
||||||
|
- diagnostics/problems panel
|
||||||
|
- outline
|
||||||
|
- go to definition
|
||||||
|
- find references
|
||||||
|
- rename/refactor preview
|
||||||
|
- semantic search
|
||||||
|
- command palette для IDE-действий
|
||||||
|
|
||||||
|
## Этап 4 — AI Pair Programmer
|
||||||
|
|
||||||
|
- inline code completion
|
||||||
|
- продолжение BSL-кода по текущему контексту
|
||||||
|
- подсказки по доступным переменным, параметрам, реквизитам, табличным частям и формам
|
||||||
|
- генерация процедур, функций, запросов и движений регистров
|
||||||
|
- генерация обработчиков команд и форм
|
||||||
|
- объяснение предложенного кода
|
||||||
|
- token/cost impact перед AI-действием
|
||||||
|
- AI decision audit
|
||||||
|
- объяснение текущих переменных, доступных реквизитов, событий формы и связанных объектов перед генерацией
|
||||||
|
|
||||||
|
## Этап 5 — Object/Form/Report Designer
|
||||||
|
|
||||||
|
- создание и изменение документов, справочников, регистров и общих модулей
|
||||||
|
- создание реквизитов и табличных частей
|
||||||
|
- создание команд
|
||||||
|
- visual form designer
|
||||||
|
- form elements inspector
|
||||||
|
- command handler binding
|
||||||
|
- report designer
|
||||||
|
- metadata diff
|
||||||
|
|
||||||
|
## Этап 5.5 — Documentation, Knowledge, Training
|
||||||
|
|
||||||
|
- документация объекта и формы рядом с редактором
|
||||||
|
- связь знаний с lineage, процедурами, запросами, событиями и задачами
|
||||||
|
- командные паттерны и стандарты кодирования 1С
|
||||||
|
- обучение разработчика на текущем объекте: что можно безопасно написать, какие переменные доступны, какие риски есть
|
||||||
|
- поиск по документации, базе знаний, версиям, обсуждениям и изменениям
|
||||||
|
|
||||||
|
## Этап 6 — Guarded Apply
|
||||||
|
|
||||||
|
- preview всех изменений
|
||||||
|
- semantic diff
|
||||||
|
- impact analysis до применения
|
||||||
|
- review до применения
|
||||||
|
- RBAC/privacy checks
|
||||||
|
- object-level version record
|
||||||
|
- task/session binding
|
||||||
|
- rollback point
|
||||||
|
|
||||||
|
## Этап 7 — Runtime And Operations
|
||||||
|
|
||||||
|
- регламентные задания
|
||||||
|
- интеграции
|
||||||
|
- runtime overlays
|
||||||
|
- operations jobs
|
||||||
|
- observability
|
||||||
|
- marketplace/download center
|
||||||
|
- license/admin panels
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# VSCode / Cursor Extensions
|
||||||
|
|
||||||
|
## Обязательно
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Tailwind CSS IntelliSense
|
||||||
|
ESLint
|
||||||
|
Prettier
|
||||||
|
Pretty TypeScript Errors
|
||||||
|
Error Lens
|
||||||
|
GitLens
|
||||||
|
```
|
||||||
|
|
||||||
|
## Для UI
|
||||||
|
|
||||||
|
```txt
|
||||||
|
shadcn/studio
|
||||||
|
v0 integration / paste workflow
|
||||||
|
Figma for VS Code
|
||||||
|
Iconify IntelliSense
|
||||||
|
```
|
||||||
|
|
||||||
|
## Для качества кода
|
||||||
|
|
||||||
|
```txt
|
||||||
|
SonarLint
|
||||||
|
Import Cost
|
||||||
|
TypeScript Importer
|
||||||
|
Path Intellisense
|
||||||
|
```
|
||||||
|
|
||||||
|
## Для AI workflow
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Cursor
|
||||||
|
GitHub Copilot
|
||||||
|
Continue
|
||||||
|
Codeium / Windsurf, если используется отдельно
|
||||||
|
```
|
||||||
|
|
||||||
|
## Рекомендация
|
||||||
|
|
||||||
|
Основной UI генерировать через:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
v0 → вставка в проект → Codex refactor → Cursor review
|
||||||
|
```
|
||||||
|
|
||||||
|
Codex не должен генерировать финальный UI без design system rules.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
Процедура Проведение()
|
||||||
|
ПроверитьОстатки();
|
||||||
|
Движения.ОстаткиТоваров.Записать();
|
||||||
|
КонецПроцедуры
|
||||||
|
|
||||||
|
Процедура ПроверитьОстатки()
|
||||||
|
Запрос = Новый Запрос;
|
||||||
|
Запрос.Текст =
|
||||||
|
"ВЫБРАТЬ
|
||||||
|
Остатки.Номенклатура
|
||||||
|
ИЗ
|
||||||
|
РегистрНакопления.ОстаткиТоваров КАК Остатки";
|
||||||
|
КонецПроцедуры
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# SFERA Web
|
||||||
|
|
||||||
|
Next.js frontend for the SFERA 1C semantic workspace.
|
||||||
|
|
||||||
|
## Run On This NAS Workspace
|
||||||
|
|
||||||
|
Use the mapped `R:` drive. It points to `\\nas\MST` and avoids Windows tooling issues with UNC current directories.
|
||||||
|
|
||||||
|
```bat
|
||||||
|
cd /d R:\codex\SFERA\frontend\sfera-web
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not run `npm` from the UNC path `\\nas\MST\...`. Windows starts `cmd.exe` in `C:\Windows` for UNC current directories, so package scripts cannot find `package.json`.
|
||||||
|
|
||||||
|
The app resolves the API endpoint in this order:
|
||||||
|
|
||||||
|
1. `SFERA_API_URL`
|
||||||
|
2. `NEXT_PUBLIC_SFERA_API_URL`
|
||||||
|
3. the current panel host with API port `8000`
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- `http://192.168.200.60:3000` -> `http://192.168.200.60:8000`
|
||||||
|
- `http://docker-test.cin.su:3000` -> `http://docker-test.cin.su:8000`
|
||||||
|
- `http://127.0.0.1:3001` -> `http://localhost:8000`
|
||||||
|
|
||||||
|
If the stand moves to another API port, set:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SFERA_API_URL=http://api-host:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also override only the derived port:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SFERA_API_PORT=8080
|
||||||
|
```
|
||||||
|
|
||||||
|
## Checks
|
||||||
|
|
||||||
|
```bat
|
||||||
|
cd /d R:\codex\SFERA\frontend\sfera-web
|
||||||
|
node_modules\.bin\tsc.cmd -p tsconfig.json --noEmit
|
||||||
|
node_modules\.bin\next.cmd build
|
||||||
|
npm run smoke:editor
|
||||||
|
npm run smoke:editor:runtime
|
||||||
|
npm run smoke:project-setup
|
||||||
|
```
|
||||||
|
|
||||||
|
`npm run smoke:editor` checks the running stand URL. By default it uses `http://192.168.200.60:3000` and verifies that the overview stays a dashboard while editor modes open directly:
|
||||||
|
|
||||||
|
- `mode=module`
|
||||||
|
- `mode=form`
|
||||||
|
- `mode=events`
|
||||||
|
- `mode=learning`
|
||||||
|
|
||||||
|
Use `SFERA_WEB_URL` to point the smoke check at another host or port. The HTML smoke retries each page briefly while a freshly started stand settles.
|
||||||
|
|
||||||
|
`npm run smoke:editor:runtime` opens the running editor in an installed Chrome/Edge through `playwright-core`. It catches browser runtime failures such as Monaco `Runtime TypeError`, verifies that Monaco renders in `mode=module`, opens `mode=versions`, clicks a version row, checks full version payload details, and exercises metadata draft preview/apply through the API.
|
||||||
|
|
||||||
|
`npm run smoke:project-setup` checks the new Project Setup / Import Center flow. It prepares the `default` project through the web API proxy, verifies that the indexed Project IDE Shell opens, and exercises metadata draft preview/save to workspace history.
|
||||||
|
|
||||||
|
By default the runtime smoke uses the installed Chrome/Edge paths on this Windows stand. Override when needed:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SFERA_BROWSER_PATH=C:\Path\To\chrome.exe
|
||||||
|
SFERA_WEB_URL=http://docker-test.cin.su:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `npm run smoke:editor:all` to run both the HTML smoke and browser runtime smoke. Browser-side editor actions require API CORS for the panel origin; the API allows LAN panel origins, localhost, and `docker-test.cin.su` by default. The Project Setup smoke uses the Next.js `/api/sfera/...` proxy and therefore also verifies frontend-to-backend routing.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
/// <reference path="./.next/types/routes.d.ts" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
|
reactStrictMode: true
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "sfera-web",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev --hostname 0.0.0.0 --port 3000",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start --hostname 0.0.0.0 --port 3000",
|
||||||
|
"lint": "next lint",
|
||||||
|
"smoke:editor": "node scripts/smoke-editor-modes.mjs",
|
||||||
|
"smoke:editor:all": "npm run smoke:editor && npm run smoke:editor:runtime",
|
||||||
|
"smoke:editor:runtime": "node scripts/smoke-editor-runtime.mjs",
|
||||||
|
"smoke:project-setup": "node scripts/smoke-project-setup.mjs",
|
||||||
|
"typecheck": "tsc --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@monaco-editor/react": "^4.7.0",
|
||||||
|
"@tanstack/react-table": "^8.21.3",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"lucide-react": "^0.468.0",
|
||||||
|
"monaco-editor": "^0.55.1",
|
||||||
|
"next": "^15.0.4",
|
||||||
|
"react": "^19.0.0",
|
||||||
|
"react-dom": "^19.0.0",
|
||||||
|
"tailwind-merge": "^2.5.5",
|
||||||
|
"zod": "^3.24.1",
|
||||||
|
"zustand": "^5.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^22.10.2",
|
||||||
|
"@types/react": "^19.0.1",
|
||||||
|
"@types/react-dom": "^19.0.2",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"eslint": "^9.16.0",
|
||||||
|
"eslint-config-next": "^15.0.4",
|
||||||
|
"playwright-core": "^1.59.1",
|
||||||
|
"postcss": "^8.4.49",
|
||||||
|
"tailwindcss": "^3.4.16",
|
||||||
|
"typescript": "^5.7.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Copyright © 2026 Andrew Ponomarev
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the “Software”), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use,
|
||||||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
1C-like metadata icons
|
||||||
|
======================
|
||||||
|
|
||||||
|
Source: MetadataViewer1C by Andrew Ponomarev
|
||||||
|
Repository: https://github.com/asweetand-a11y/MetadataViewer1C
|
||||||
|
License: MIT, see LICENSE.MetadataViewer1C.md
|
||||||
|
|
||||||
|
These SVGs are used as a visually similar open-source icon set for SFERA's 1C metadata tree.
|
||||||
|
They are not extracted from the 1C:Enterprise Configurator executable or distribution.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M20.95 31.95 35.4 17.5l-2.15-2.15-12.3 12.3L15 21.7l-2.15 2.15ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 440 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M24.5 21.7h3v-4.2h4.2v-3h-4.2v-4.2h-3v4.2h-4.2v3h4.2Zm-4.2 7.8h11.4v-3H20.3ZM13 40q-1.2 0-2.1-.9-.9-.9-.9-2.1V5q0-1.2.9-2.1.9-.9 2.1-.9h17.4L42 13.6V37q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h26V14.9L28.9 5H13v32Zm-6 9q-1.2 0-2.1-.9Q4 44.2 4 43V12.05h3V43h24.9v3Zm6-9V5v32Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 506 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M32 22q.85 0 1.425-.575Q34 20.85 34 20q0-.85-.575-1.425Q32.85 18 32 18q-.85 0-1.425.575Q30 19.15 30 20q0 .85.575 1.425Q31.15 22 32 22Zm-16-5h10v-3H16ZM9 42q-1.7-5.7-3.35-11.375Q4 24.95 4 19q0-4.6 3.2-7.8T15 8h10q1.45-1.9 3.525-2.95Q30.6 4 33 4q1.25 0 2.125.875T36 7q0 .3-.075.6t-.175.55q-.2.55-.375 1.125T35.1 10.45L39.65 15H44v13.95l-5.65 1.85L35 42H24v-4h-4v4Zm2.25-3H17v-4h10v4h5.75l3.15-10.5 5.1-1.75V18h-2.6L32 11.6q.05-1.25.325-2.425Q32.6 8 32.9 6.8q-1.9.5-3.6 1.475-1.7.975-2.6 2.725H15q-3.3 0-5.65 2.35Q7 15.7 7 19q0 5.15 1.45 10.075Q9.9 34 11.25 39ZM24 22.9Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 811 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M8 25.5v-3h32v3Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 260 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M31 44v-4.75L15.5 31.5H6v-11h8.75l6.25-7V4h11v11h-8.3L17 22.5v6.45l14 6.95V33h11v11Zm-7-32h5V7h-5ZM9 28.5h5v-5H9ZM34 41h5v-5h-5ZM26.5 9.5ZM11.5 26Zm25 12.5Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 400 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M15.7 36.6h2.5v-4.4h4.4v-2.5h-4.4v-4.4h-2.5v4.4h-4.4v2.5h4.4Zm10.75-1.75H36.5V32.4H26.45Zm0-5.35H36.5V27H26.45Zm1.85-8.15 3.05-3.05 3.05 3.05 1.8-1.8-3.05-3.05 3.05-3.05-1.8-1.8-3.05 3.05-3.05-3.05-1.8 1.8 3.05 3.05-3.05 3.05Zm-16.25-3.6h9.8v-2.5h-9.8ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 629 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M6 42V6h36v36Zm3-25h30V9H9Zm11 11h8v-8h-8Zm0 11h8v-8h-8ZM9 28h8v-8H9Zm22 0h8v-8h-8ZM9 39h8v-8H9Zm22 0h8v-8h-8Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 354 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M14.5 40V13H4V8h26v5H19.5v27Zm18 0V23H26v-5h18v5h-6.5v17Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 301 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="m24 41.5-18-14 2.5-1.85L24 37.7l15.5-12.05L42 27.5Zm0-7.6-18-14 18-14 18 14Zm0-15.05Zm0 11.25 13.1-10.2L24 9.7 10.9 19.9Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 365 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M15 33.7q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm0-8.2q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm0-8.2q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm6.6 16.4h12.2v-3H21.6Zm0-8.2h12.2v-3H21.6Zm0-8.2h12.2v-3H21.6ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 811 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M15.35 16.6q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm8.65 0q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45Zm8.65 0q.6 0 1.05-.45.45-.45.45-1.05 0-.6-.45-1.05-.45-.45-1.05-.45-.6 0-1.05.45-.45.45-.45 1.05 0 .6.45 1.05.45.45 1.05.45ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 753 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M19.15 32.5 32.5 24l-13.35-8.5ZM24 44q-4.1 0-7.75-1.575-3.65-1.575-6.375-4.3-2.725-2.725-4.3-6.375Q4 28.1 4 24q0-4.15 1.575-7.8 1.575-3.65 4.3-6.35 2.725-2.7 6.375-4.275Q19.9 4 24 4q4.15 0 7.8 1.575 3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24q0 4.1-1.575 7.75-1.575 3.65-4.275 6.375t-6.35 4.3Q28.15 44 24 44Zm0-3q7.1 0 12.05-4.975Q41 31.05 41 24q0-7.1-4.95-12.05Q31.1 7 24 7q-7.05 0-12.025 4.95Q7 16.9 7 24q0 7.05 4.975 12.025Q16.95 41 24 41Zm0-17Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 704 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M13.4 35.5q-3.1 0-5.25-2.15T6 28.1q0-3.1 2.15-5.25t5.25-2.15q3.1 0 5.25 2.15t2.15 5.25q0 3.1-2.15 5.25T13.4 35.5Zm0-3q1.85 0 3.125-1.275T17.8 28.1q0-1.85-1.275-3.125T13.4 23.7q-1.85 0-3.125 1.275T9 28.1q0 1.85 1.275 3.125T13.4 32.5Zm8.45-16.7q1.9 0 3.15-1.25t1.25-3.15q0-1.9-1.25-3.15T21.85 7q-1.9 0-3.15 1.25t-1.25 3.15q0 1.9 1.25 3.15t3.15 1.25Zm0 3q-3.1 0-5.25-2.15t-2.15-5.25q0-3.1 2.15-5.25T21.85 4q3.1 0 5.25 2.15t2.15 5.25q0 3.1-2.15 5.25t-5.25 2.15ZM34.6 39q1.9 0 3.15-1.25T39 34.6q0-1.9-1.25-3.15T34.6 30.2q-1.9 0-3.15 1.25T30.2 34.6q0 1.9 1.25 3.15T34.6 39Zm0 3q-3.1 0-5.25-2.15T27.2 34.6q0-3.1 2.15-5.25t5.25-2.15q3.1 0 5.25 2.15T42 34.6q0 3.1-2.15 5.25T34.6 42ZM21.85 11.4ZM13.4 28.1Zm21.2 6.5Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 950 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M13.85 34.05H27.6v-3H13.85Zm0-8.55h20.3v-3h-20.3Zm0-8.55h20.3v-3h-20.3ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 448 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M6 6h16.5v16.5H6Zm3 2.95v9.4ZM25.5 6H42v16.5H25.5Zm4.15 2.95v9.4ZM6 25.5h16.5V42H6Zm3 4.05V39Zm23.25-4.05h3v6.75H42v3h-6.75V42h-3v-6.75H25.5v-3h6.75ZM28.5 9v10.5H39V9ZM9 9v10.5h10.5V9Zm0 19.5V39h10.5V28.5Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 449 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="m14 42-2.15-2.15 4.3-4.3q-5.4.35-9.775-3.525T2 22q0-5.85 4.075-9.925Q10.15 8 16 8h6v3h-6q-4.55 0-7.775 3.225Q5 17.45 5 22q0 4.7 3.275 7.7t8.025 2.9l-4.45-4.45L14 26l8 8Zm12-2V26h18v14Zm0-18V8h18v14Zm3-3h12v-8H29Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 456 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M7 36q-1.2 0-2.1-.9Q4 34.2 4 33V15q0-1.15.9-2.075Q5.8 12 7 12h34q1.2 0 2.1.925.9.925.9 2.075v18q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h34V15h-6.5v9h-3v-9h-6v9h-3v-9h-6v9h-3v-9H7v18Zm6.5-9h3Zm9 0h3Zm9 0h3ZM24 24Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 445 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M15 16H2V0h8.621L15 4.379V16z" id="outline"/><path class="icon-vs-fg" d="M13 14H4V2h5v4h4v8zm-3-9V2.207L12.793 5H10z" id="iconFg"/><path class="icon-vs-bg" d="M3 1v14h11V4.793L10.207 1H3zm10 13H4V2h5v4h4v8zm-3-9V2.207L12.793 5H10z" id="iconBg"/></svg>
|
||||||
|
After Width: | Height: | Size: 552 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M28.05 31V20h3.75l3.25 3.25V31Zm-3 3h13V22l-5-5h-8Zm-18 6q-1.2 0-2.1-.925-.9-.925-.9-2.075V11q0-1.15.9-2.075Q5.85 8 7.05 8h14l3 3h17q1.15 0 2.075.925.925.925.925 2.075v23q0 1.15-.925 2.075Q42.2 40 41.05 40Zm0-29v26h34V14H22.8l-3-3H7.05Zm0 0v26Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 488 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" viewBox="0 -960 960 960">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M120-80v-60h100v-30h-60v-60h60v-30H120v-60h160v90l-30 30 30 30v90H120Zm0-280v-150h100v-30H120v-60h160v150H180v30h100v60H120Zm60-280v-180h-60v-60h120v240h-60Zm189 431v-60h471v60H369Zm0-243v-60h471v60H369Zm0-243v-60h471v60H369Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 494 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M24 42v-3.55l10.8-10.8 3.55 3.55L27.55 42ZM6 31.5v-3h15v3Zm34.5-2.45-3.55-3.55 1.45-1.45q.4-.4 1.05-.4t1.05.4l1.45 1.45q.4.4.4 1.05t-.4 1.05ZM6 23.25v-3h23.5v3ZM6 15v-3h23.5v3Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 420 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M11 44q-1.2 0-2.1-.9Q8 42.2 8 41V7q0-1.2.9-2.1Q9.8 4 11 4h17l12 12v7.8h-3V18H26V7H11v34h15v3Zm0-3V7v34Zm26.8-11.15 1.4 1.4-8.2 8.2V42h2.55l8.2-8.2 1.4 1.4-8.8 8.8H29v-5.35Zm5.35 5.35-5.35-5.35 3.05-3.05q.45-.45 1.05-.45.6 0 1.05.45l3.25 3.25q.45.45.45 1.05 0 .6-.45 1.05Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 515 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M28.5 40v-3h6q1.05 0 1.775-.725Q37 35.55 37 34.5v-5q0-1.85 1.125-3.3 1.125-1.45 2.875-2v-.4q-1.75-.5-2.875-1.975T37 18.5v-5q0-1.05-.725-1.775Q35.55 11 34.5 11h-6V8h6q2.3 0 3.9 1.6t1.6 3.9v5q0 1.05.725 1.775Q41.45 21 42.5 21H44v6h-1.5q-1.05 0-1.775.725Q40 28.45 40 29.5v5q0 2.3-1.6 3.9T34.5 40Zm-15 0q-2.3 0-3.9-1.6T8 34.5v-5q0-1.05-.725-1.775Q6.55 27 5.5 27H4v-6h1.5q1.05 0 1.775-.725Q8 19.55 8 18.5v-5q0-2.3 1.6-3.9T13.5 8h6v3h-6q-1.05 0-1.775.725Q11 12.45 11 13.5v5q0 1.85-1.125 3.325T7 23.8v.4q1.75.55 2.875 2T11 29.5v5q0 1.05.725 1.775Q12.45 37 13.5 37h6v3Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 805 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M19.95 42 22 27.9h-7.3q-.55 0-.8-.5t0-.95L26.15 6h2.05l-2.05 14.05h7.2q.55 0 .825.5.275.5.025.95L22 42Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 347 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M8.35 40v-3h6.5l-.75-.6q-3.2-2.55-4.65-5.55-1.45-3-1.45-6.7 0-5.3 3.125-9.525Q14.25 10.4 19.35 8.8v3.1q-3.75 1.45-6.05 4.825T11 24.15q0 3.15 1.175 5.475 1.175 2.325 3.175 4.025l1.5 1.05v-6.2h3V40Zm20.35-.75V36.1q3.8-1.45 6.05-4.825T37 23.85q0-2.4-1.175-4.875T32.75 14.6l-1.45-1.3v6.2h-3V8h11.5v3h-6.55l.75.7q3 2.8 4.5 6t1.5 6.15q0 5.3-3.1 9.55-3.1 4.25-8.2 5.85Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 606 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="m24.5 28.85 11.4-11.4-2.1-2.05-9.25 9.3-4.85-4.85-2.1 2.1ZM13 38q-1.2 0-2.1-.9-.9-.9-.9-2.1V7q0-1.2.9-2.1.9-.9 2.1-.9h28q1.2 0 2.1.9.9.9.9 2.1v28q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h28V7H13v28Zm-6 9q-1.2 0-2.1-.9Q4 42.2 4 41V10h3v31h31v3Zm6-37v28V7Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 486 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M24 22q-8.05 0-13.025-2.45T6 14q0-3.15 4.975-5.575Q15.95 6 24 6t13.025 2.425Q42 10.85 42 14q0 3.1-4.975 5.55Q32.05 22 24 22Zm0 10q-7.3 0-12.65-2.2Q6 27.6 6 24.5v-5q0 1.95 1.875 3.375t4.65 2.35q2.775.925 5.9 1.35Q21.55 27 24 27q2.5 0 5.6-.425 3.1-.425 5.875-1.325 2.775-.9 4.65-2.325Q42 21.5 42 19.5v5q0 3.1-5.35 5.3Q31.3 32 24 32Zm0 10q-7.3 0-12.65-2.2Q6 37.6 6 34.5v-5q0 1.95 1.875 3.375t4.65 2.35q2.775.925 5.9 1.35Q21.55 37 24 37q2.5 0 5.6-.425 3.1-.425 5.875-1.325 2.775-.9 4.65-2.325Q42 31.5 42 29.5v5q0 3.1-5.35 5.3Q31.3 42 24 42Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 780 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M22 40q-.85 0-1.425-.575Q20 38.85 20 38V26L8.05 10.75q-.7-.85-.2-1.8Q8.35 8 9.4 8h29.2q1.05 0 1.55.95t-.2 1.8L28 26v12q0 .85-.575 1.425Q26.85 40 26 40Zm2-13.8L36 11H12Zm0 0Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 417 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M7.05 40q-1.2 0-2.1-.925-.9-.925-.9-2.075V11q0-1.15.9-2.075Q5.85 8 7.05 8h14l3 3h17q1.15 0 2.075.925.925.925.925 2.075v23q0 1.15-.925 2.075Q42.2 40 41.05 40Zm0-29v26h34V14H22.8l-3-3H7.05Zm0 0v26Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 439 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M8 38v-3h19.3v3Zm0-8.3v-3h32v3Zm0-8.35v-3h32v3ZM8 13v-3h32v3Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 305 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M24 44q-4.2 0-7.85-1.575Q12.5 40.85 9.8 38.15q-2.7-2.7-4.25-6.375Q4 28.1 4 23.9t1.55-7.825Q7.1 12.45 9.8 9.75t6.35-4.225Q19.8 4 24 4q4.2 0 7.85 1.525Q35.5 7.05 38.2 9.75q2.7 2.7 4.25 6.325Q44 19.7 44 23.9t-1.55 7.875Q40.9 35.45 38.2 38.15t-6.35 4.275Q28.2 44 24 44Zm0-2.9q1.75-1.8 2.925-4.125Q28.1 34.65 28.85 31.45H19.2q.7 3 1.875 5.4Q22.25 39.25 24 41.1Zm-4.25-.6q-1.25-1.9-2.15-4.1-.9-2.2-1.5-4.95H8.6Q10.5 35 13 37.025q2.5 2.025 6.75 3.475Zm8.55-.05q3.6-1.15 6.475-3.45 2.875-2.3 4.625-5.55h-7.45q-.65 2.7-1.525 4.9-.875 2.2-2.125 4.1Zm-20.7-12h7.95q-.15-1.35-.175-2.425-.025-1.075-.025-2.125 0-1.25.05-2.225.05-.975.2-2.175h-8q-.35 1.2-.475 2.15T7 23.9q0 1.3.125 2.325.125 1.025.475 2.225Zm11.05 0H29.4q.2-1.55.25-2.525.05-.975.05-2.025 0-1-.05-1.925T29.4 19.5H18.65q-.2 1.55-.25 2.475-.05.925-.05 1.925 0 1.05.05 2.025.05.975.25 2.525Zm13.75 0h8q.35-1.2.475-2.225Q41 25.2 41 23.9q0-1.3-.125-2.25T40.4 19.5h-7.95q.15 1.75.2 2.675.05.925.05 1.725 0 1.1-.075 2.075-.075.975-.225 2.475Zm-.5-11.95h7.5q-1.65-3.45-4.525-5.75Q32 8.45 28.25 7.5q1.25 1.85 2.125 4t1.525 5Zm-12.7 0h9.7q-.55-2.65-1.85-5.125T24 7q-1.6 1.35-2.7 3.55-1.1 2.2-2.1 5.95Zm-10.6 0h7.55q.55-2.7 1.4-4.825.85-2.125 2.15-4.125-3.75.95-6.55 3.2T8.6 16.5Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M4 39.5v-31h40v31Zm3-21.65h6.25V11.5H7Zm9.25 0h6.25V11.5h-6.25Zm9.25 0h6.25V11.5H25.5Zm9.25 0H41V11.5h-6.25Zm0 9.35H41v-6.35h-6.25Zm-9.25 0h6.25v-6.35H25.5Zm-9.25 0h6.25v-6.35h-6.25Zm-3-6.35H7v6.35h6.25Zm21.5 15.65H41v-6.3h-6.25Zm-9.25 0h6.25v-6.3H25.5Zm-9.25 0h6.25v-6.3h-6.25ZM7 36.5h6.25v-6.3H7Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 542 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M12.55 40q-4.4 0-7.475-3.075Q2 33.85 2 29.45q0-3.9 2.5-6.85 2.5-2.95 6.35-3.55 1-4.85 4.7-7.925T24.1 8.05q5.6 0 9.45 4.075Q37.4 16.2 37.4 21.9v1.2q3.6-.1 6.1 2.325Q46 27.85 46 31.55q0 3.45-2.5 5.95T37.55 40Zm0-3h25q2.25 0 3.85-1.6t1.6-3.85q0-2.25-1.6-3.85t-3.85-1.6H34.4v-4.2q0-4.55-3.05-7.7-3.05-3.15-7.45-3.15t-7.475 3.15q-3.075 3.15-3.075 7.7h-.95q-3.1 0-5.25 2.175T5 29.45q0 3.15 2.2 5.35Q9.4 37 12.55 37ZM33 15V4h11v11Zm5-5h5V5h-5Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 680 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M34 36q-4.95 0-8.475-3.525Q22 28.95 22 24q0-4.95 3.525-8.475Q29.05 12 34 12q4.95 0 8.475 3.525Q46 19.05 46 24q0 4.95-3.525 8.475Q38.95 36 34 36Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 389 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 472 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M8 40V18h7v22Zm12.5 0V8h7v32ZM33 40V26h7v14Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 288 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="m22.4 39.65-11-6.45q-.7-.4-1.075-1.1-.375-.7-.375-1.5V17.75q0-.8.375-1.5t1.075-1.1L22.45 8.6q.7-.4 1.55-.4.85 0 1.55.4l11.05 6.55q.7.4 1.075 1.1.375.7.375 1.5V30.6q0 .8-.4 1.5t-1.1 1.1L25.4 39.65q-.7.4-1.5.4t-1.5-.4Zm.1-3.45V25L13 19.55V30.5Zm3 0 9.55-5.7V19.55L25.5 25ZM2 11.45V7.6q0-2.35 1.625-3.975T7.6 2h3.85v3H7.6q-1.1 0-1.85.75T5 7.6v3.85ZM7.6 46q-2.35 0-3.975-1.625T2 40.4v-3.85h3v3.85q0 1.1.75 1.85T7.6 43h3.85v3Zm28.95-.2v-3h3.85q1.1 0 1.85-.75T43 40.2v-3.85h3v3.85q0 2.35-1.625 3.975T40.4 45.8ZM43 11.45V7.6q0-1.1-.75-1.85T40.4 5h-3.85V2h3.85q2.35 0 3.975 1.625T46 7.6v3.85ZM24 22.3l9.5-5.5-9.5-5.45-9.5 5.45Zm0 1.25Zm0-1.25Zm1.5 2.7Zm-3 0Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 894 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M14 27.4q-1.4 0-2.4-1t-1-2.4q0-1.4 1-2.4t2.4-1q1.4 0 2.4 1t1 2.4q0 1.4-1 2.4t-2.4 1Zm0 8.6q-5 0-8.5-3.5T2 24q0-5 3.5-8.5T14 12q3.6 0 6.3 1.7 2.7 1.7 4.25 5.15h17.8L48 24.5l-8.35 7.65-4.4-3.2-4.4 3.2-3.75-3h-2.55q-1.25 3-3.925 4.925Q17.95 36 14 36Zm0-3q2.9 0 5.35-1.925 2.45-1.925 3.15-4.925h5.7l2.7 2.25 4.4-3.15 4.1 3.1 4.25-3.95-2.55-2.55H22.5q-.6-2.8-3-4.825Q17.1 15 14 15q-3.75 0-6.375 2.625T5 24q0 3.75 2.625 6.375T14 33Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 670 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M24 38q5.85 0 9.925-4.075Q38 29.85 38 24q0-5.85-4.075-9.925Q29.85 10 24 10v14l-9.55 10q1.85 1.95 4.35 2.975Q21.3 38 24 38Zm0 6q-4.1 0-7.75-1.575-3.65-1.575-6.375-4.3-2.725-2.725-4.3-6.375Q4 28.1 4 24q0-4.15 1.575-7.8 1.575-3.65 4.3-6.35 2.725-2.7 6.375-4.275Q19.9 4 24 4q4.15 0 7.8 1.575 3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24q0 4.1-1.575 7.75-1.575 3.65-4.275 6.375t-6.35 4.3Q28.15 44 24 44Zm0-3q7.1 0 12.05-4.975Q41 31.05 41 24q0-7.1-4.95-12.05Q31.1 7 24 7q-7.05 0-12.025 4.95Q7 16.9 7 24q0 7.05 4.975 12.025Q16.95 41 24 41Zm0-17Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 793 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M120-280v-60h560v60H120Zm80-170v-60h560v60H200Zm80-170v-60h560v60H280Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 339 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M24 29.25 18.75 24 24 18.75 29.25 24Zm-4.25-14.7L15.6 10.4 24 2l8.4 8.4-4.15 4.15L24 10.3ZM10.4 32.4 2 24l8.4-8.4 4.15 4.15L10.3 24l4.25 4.25Zm27.2 0-4.15-4.15L37.7 24l-4.25-4.25 4.15-4.15L46 24ZM24 46l-8.4-8.4 4.15-4.15L24 37.7l4.25-4.25 4.15 4.15Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 493 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M603-160h56v-83l102-24q21-5 43.5-11.5T827-299q0-8-8-14.5T792-326q-38-11-58-34t-18-49q2-21 19.5-37.5T785-474q28-10 41.5-22.5T840-526q0-20-17-30.5t-37-3.5q-6 2-12.5 3t-12.5 1q-26 0-43.5-20T700-625q0-26 13.5-47.5T727-720q0-17-14.5-28.5T677-760q-29 0-40.5 12.5T625-700q0 17 1.5 33t1.5 33q0 45-16 66t-50 21q-11 0-23-3t-23-3q-6 0-9.5 2.5T503-543q0 10 12 20t23 19q26 23 38 44t12 42q0 27-19.5 46T521-353q-11 0-21-2t-21-3q-28-2-43 5t-15 21q0 14 13 23t38 13l131 21v115Zm-450 40-73-33 200-440 73 33-200 440Zm370 40v-128l-57-8q-55-8-89.5-39.5T342-329q0-48 39.5-80.5T476-439q5 0 8.5.5t7.5 1.5q-8-8-15-14.5T464-465q-20-22-29-40.5t-9-37.5q0-38 21.5-62.5T504-630q7 0 19 .5t26 2.5q2-20 0-41t-2-41q0-63 34-97t97-34q56 0 93.5 32t36.5 78q0 23-8 45t-18 43q5-1 10.5-1.5t10.5-.5q48 0 82.5 34.5T920-525q0 43-30.5 77.5T818-402q7 2 13 4t12 5q29 14 47 39.5t18 55.5q0 38-33.5 66.5T779-188l-40 10v98H523ZM138-537q-29-29-43.5-65.5T80-679q0-84 58-142.5T280-880q40 0 76.5 15t65.5 44l-56 56q-17-17-39.5-26t-46.5-9q-50 0-85 35t-35 85q0 24 9 46.5t26 39.5l-57 57Zm493 128Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M8 46V35h5v-5.5H8v-11h5V13H8V2h13v11h-5v5.5h5v4h8v-4h13v11H29v-4h-8v4h-5V35h5v11Zm3-3h7v-5h-7Zm0-16.5h7v-5h-7Zm21 0h7v-5h-7ZM11 10h7V5h-7Zm3.5-2.5Zm0 16.5Zm21 0Zm-21 16.5Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 415 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M7 37h9.35V11H7v26Zm12.35 0h9.3V11h-9.3v26Zm12.3 0H41V11h-9.35v26ZM7 40q-1.2 0-2.1-.9Q4 38.2 4 37V11q0-1.2.9-2.1Q5.8 8 7 8h34q1.2 0 2.1.9.9.9.9 2.1v26q0 1.2-.9 2.1-.9.9-2.1.9Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 419 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M11.1 37.3 4 30.2l2.1-2.1 5 4.95 8.95-8.95 2.1 2.15Zm0-16L4 14.2l2.1-2.1 5 4.95 8.95-8.95 2.1 2.15ZM26 33.5v-3h18v3Zm0-16v-3h18v3Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 374 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M13 33h13v-3H13Zm19 0h3V15h-3Zm-19-7.5h13v-3H13Zm0-7.5h13v-3H13ZM6.6 42q-1.2 0-2.1-.9-.9-.9-.9-2.1V9q0-1.2.9-2.1.9-.9 2.1-.9h34.8q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h34.8V9H6.6v30Zm0 0V9v30Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 452 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M24 44q-4.2 0-7.85-1.575Q12.5 40.85 9.8 38.15q-2.7-2.7-4.25-6.375Q4 28.1 4 23.9t1.55-7.825Q7.1 12.45 9.8 9.75t6.35-4.225Q19.8 4 24 4q1.15 0 2.275.125T28.5 4.5v10.4q-.7-2.25-1.85-4.275Q25.5 8.6 24 7q-1.6 1.35-2.7 3.55-1.1 2.2-2.1 5.95h9.3v3h-9.85q-.2 1.55-.25 2.475-.05.925-.05 1.925 0 1.05.05 2.025.05.975.25 2.525H29.4q.2-1.55.25-2.525.05-.975.05-2.025 0-1-.05-1.925T29.4 19.5h3.05q.15 1.75.2 2.675.05.925.05 1.725 0 1.1-.075 2.075-.075.975-.225 2.475h8q.35-1.2.475-2.225Q41 25.2 41 23.9q0-1.3-.125-2.25T40.4 19.5h3.15q.25 1.05.35 2.15.1 1.1.1 2.25 0 4.2-1.55 7.875T38.2 38.15q-2.7 2.7-6.35 4.275Q28.2 44 24 44ZM7.6 28.45h7.95q-.15-1.35-.175-2.425-.025-1.075-.025-2.125 0-1.25.05-2.225.05-.975.2-2.175h-8q-.35 1.2-.475 2.15T7 23.9q0 1.3.125 2.325.125 1.025.475 2.225ZM19.75 40.5q-1.25-1.9-2.15-4.1-.9-2.2-1.5-4.95H8.6Q10.5 35 13 37.025q2.5 2.025 6.75 3.475ZM8.6 16.5h7.55q.55-2.7 1.4-4.825.85-2.125 2.15-4.125-3.75.95-6.55 3.2T8.6 16.5ZM24 41.1q1.75-1.8 2.925-4.125Q28.1 34.65 28.85 31.45H19.2q.7 3 1.875 5.4Q22.25 39.25 24 41.1Zm4.3-.65q3.6-1.15 6.475-3.45 2.875-2.3 4.625-5.55h-7.45q-.65 2.7-1.525 4.9-.875 2.2-2.125 4.1ZM33 15V4h11v11Zm5-5h5V5h-5Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M12.55 40q-4.4 0-7.475-3.075Q2 33.85 2 29.45q0-3.9 2.5-6.85 2.5-2.95 6.35-3.55 1-4.85 4.7-7.925T24.1 8.05q5.6 0 9.45 4.075Q37.4 16.2 37.4 21.9v1.2q3.6-.1 6.1 2.325Q46 27.85 46 31.55q0 3.45-2.5 5.95T37.55 40Zm0-3h25q2.25 0 3.85-1.6t1.6-3.85q0-2.25-1.6-3.85t-3.85-1.6H34.4v-4.2q0-4.55-3.05-7.7-3.05-3.15-7.45-3.15t-7.475 3.15q-3.075 3.15-3.075 7.7h-.95q-3.1 0-5.25 2.175T5 29.45q0 3.15 2.2 5.35Q9.4 37 12.55 37ZM24 24Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 661 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
|
||||||
|
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
|
||||||
|
<path class="icon-vs-fg" d="M24 44q-3.3 0-6.525-1.2-3.225-1.2-5.775-3.15-2.55-1.95-4.125-4.4Q6 32.8 6 30.25v-5l6.75 5.05-2.9 2.9q1.55 2.9 5.3 5.175T22.5 40.9V21.5H16v-3h6.5v-3.7q-1.9-.7-2.95-2.1-1.05-1.4-1.05-3.2 0-2.3 1.625-3.9T24 4q2.3 0 3.9 1.6t1.6 3.9q0 1.8-1.05 3.2-1.05 1.4-2.95 2.1v3.7H32v3h-6.5v19.4q3.6-.25 7.35-2.525 3.75-2.275 5.3-5.175l-2.9-2.9L42 25.25v5q0 2.55-1.575 5t-4.125 4.4q-2.55 1.95-5.775 3.15Q27.3 44 24 44Zm0-32q1.05 0 1.775-.75.725-.75.725-1.75 0-1.05-.725-1.775Q25.05 7 24 7q-1 0-1.75.725T21.5 9.5q0 1 .75 1.75T24 12Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 759 B |
@@ -0,0 +1,165 @@
|
|||||||
|
const baseUrl = process.env.SFERA_WEB_URL ?? "http://192.168.200.60:3000";
|
||||||
|
const projectId = process.env.SFERA_PROJECT_ID ?? "demo";
|
||||||
|
const routine = encodeURIComponent(process.env.SFERA_ROUTINE ?? "Проведение");
|
||||||
|
const attempts = Number(process.env.SFERA_SMOKE_ATTEMPTS ?? "5");
|
||||||
|
|
||||||
|
const checks = [
|
||||||
|
{
|
||||||
|
name: "root opens IDE workspace",
|
||||||
|
url: `${baseUrl}/?lang=ru&project=${projectId}`,
|
||||||
|
mustInclude: [
|
||||||
|
"SFERA",
|
||||||
|
"data-top-project-bar",
|
||||||
|
"data-top-bar-logo",
|
||||||
|
"data-top-bar-selector=\"workspace\"",
|
||||||
|
"data-top-bar-selector=\"project\"",
|
||||||
|
"data-top-bar-selector=\"environment\"",
|
||||||
|
"data-top-bar-selector=\"active-task\"",
|
||||||
|
"data-top-bar-action=\"project-settings\"",
|
||||||
|
"data-top-bar-action=\"create-project\"",
|
||||||
|
"data-top-bar-badge=\"api-status\"",
|
||||||
|
"data-top-bar-badge=\"agent-status\"",
|
||||||
|
"data-top-bar-language",
|
||||||
|
"data-top-bar-button=\"profile\"",
|
||||||
|
"Ctrl+K",
|
||||||
|
"data-status-bar",
|
||||||
|
"data-status-item=\"current-user\""
|
||||||
|
],
|
||||||
|
mustNotInclude: ["Открыть в редакторе"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "root opens IDE workspace (en)",
|
||||||
|
url: `${baseUrl}/?lang=en&project=${projectId}`,
|
||||||
|
mustInclude: [
|
||||||
|
"SFERA",
|
||||||
|
"data-top-project-bar",
|
||||||
|
"data-top-bar-logo",
|
||||||
|
"data-top-bar-selector=\"workspace\"",
|
||||||
|
"data-top-bar-selector=\"project\"",
|
||||||
|
"data-top-bar-selector=\"environment\"",
|
||||||
|
"data-top-bar-selector=\"active-task\"",
|
||||||
|
"data-top-bar-action=\"project-settings\"",
|
||||||
|
"data-top-bar-action=\"create-project\"",
|
||||||
|
"data-top-bar-badge=\"api-status\"",
|
||||||
|
"data-top-bar-badge=\"agent-status\"",
|
||||||
|
"data-top-bar-language",
|
||||||
|
"data-top-bar-button=\"profile\"",
|
||||||
|
"Ctrl+K",
|
||||||
|
"data-status-bar",
|
||||||
|
"data-status-item=\"current-user\""
|
||||||
|
],
|
||||||
|
mustNotInclude: ["Open in editor"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project settings route",
|
||||||
|
url: `${baseUrl}/project-settings`,
|
||||||
|
mustInclude: [
|
||||||
|
"Project Settings",
|
||||||
|
"Import Center",
|
||||||
|
"REFERENCE_CONFIGURATION",
|
||||||
|
"Reference config",
|
||||||
|
"data-import-action=\"REFERENCE_CONFIGURATION:import\"",
|
||||||
|
"data-import-action=\"XML_DUMP:check\"",
|
||||||
|
"data-settings-section=\"docker-runtime-adapter\"",
|
||||||
|
"data-settings-section=\"its-documentation-access\"",
|
||||||
|
"Пользователи и доступ",
|
||||||
|
"Интеграции задач",
|
||||||
|
"Docker/runtime adapter",
|
||||||
|
"ITS/documentation access",
|
||||||
|
"Audit",
|
||||||
|
"Backup/restore",
|
||||||
|
"SFERA_ITS_URL",
|
||||||
|
"SFERA_ITS_USERNAME",
|
||||||
|
"SFERA_ITS_PASSWORD",
|
||||||
|
"https://its.1c.ru/db/v838doc#browse:13:-1:7",
|
||||||
|
".env.local",
|
||||||
|
"<set locally>"
|
||||||
|
],
|
||||||
|
mustNotInclude: ["Открыть в редакторе"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project settings route (en)",
|
||||||
|
url: `${baseUrl}/project-settings?lang=en`,
|
||||||
|
mustInclude: [
|
||||||
|
"Project Settings",
|
||||||
|
"Import Center",
|
||||||
|
"REFERENCE_CONFIGURATION",
|
||||||
|
"Reference config",
|
||||||
|
"data-import-action=\"REFERENCE_CONFIGURATION:import\"",
|
||||||
|
"data-import-action=\"XML_DUMP:check\"",
|
||||||
|
"data-settings-section=\"task-session-policy\"",
|
||||||
|
"data-settings-section=\"docker-runtime-adapter\"",
|
||||||
|
"data-settings-section=\"its-documentation-access\"",
|
||||||
|
"Task/session policy",
|
||||||
|
"Docker/runtime adapter",
|
||||||
|
"ITS/documentation access",
|
||||||
|
"Audit",
|
||||||
|
"Backup/restore",
|
||||||
|
"SFERA_ITS_URL",
|
||||||
|
"SFERA_ITS_USERNAME",
|
||||||
|
"SFERA_ITS_PASSWORD",
|
||||||
|
".env.local",
|
||||||
|
"<set locally>"
|
||||||
|
],
|
||||||
|
mustNotInclude: ["Open in editor"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "module mode",
|
||||||
|
url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=module&routine=${routine}`,
|
||||||
|
mustInclude: ["data-ide-workspace", "data-left-navigation-panel", "data-right-context-inspector", "data-open-objects-bar", "data-open-document-pin", "data-open-document-close", "data-fallback-tree-search", "data-fallback-tree-filters", "Alt+1 Alt+2 Alt+3", "Редактор BSL", "Код модуля не загружен", "Выберите реальный модуль", "Основная конфигурация", "Расширение: <Имя>", "SFERA", "Среды"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "form mode",
|
||||||
|
url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=form&routine=${routine}`,
|
||||||
|
mustInclude: ["Дизайнер формы", "Провести и закрыть", "Товары"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "events mode",
|
||||||
|
url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=events&routine=${routine}`,
|
||||||
|
mustInclude: ["Инспектор событий", "ПриСозданииНаСервере", "ПередЗаписью"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "learning mode",
|
||||||
|
url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=learning&routine=${routine}`,
|
||||||
|
mustInclude: ["Обучение", "переменные доступны", "стандарты команды"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const check of checks) {
|
||||||
|
let lastError;
|
||||||
|
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
||||||
|
try {
|
||||||
|
await runCheck(check);
|
||||||
|
console.log(`ok ${check.name}`);
|
||||||
|
lastError = undefined;
|
||||||
|
break;
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error;
|
||||||
|
if (attempt < attempts) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastError) {
|
||||||
|
throw lastError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runCheck(check) {
|
||||||
|
const response = await fetch(check.url, { headers: { Accept: "text/html" } });
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`${check.name}: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = await response.text();
|
||||||
|
for (const expected of check.mustInclude ?? []) {
|
||||||
|
if (!html.includes(expected)) {
|
||||||
|
throw new Error(`${check.name}: missing "${expected}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const forbidden of check.mustNotInclude ?? []) {
|
||||||
|
if (html.includes(forbidden)) {
|
||||||
|
throw new Error(`${check.name}: unexpected "${forbidden}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
import { chromium } from "playwright-core";
|
||||||
|
import { existsSync } from "node:fs";
|
||||||
|
|
||||||
|
const baseUrl = process.env.SFERA_WEB_URL ?? "http://192.168.200.60:3000";
|
||||||
|
const projectId = process.env.SFERA_PROJECT_ID ?? "demo";
|
||||||
|
const uniqueSuffix = Date.now().toString(36);
|
||||||
|
const browserPath =
|
||||||
|
process.env.SFERA_BROWSER_PATH ??
|
||||||
|
[
|
||||||
|
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
||||||
|
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
|
||||||
|
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe"
|
||||||
|
].find((path) => existsSync(path));
|
||||||
|
|
||||||
|
if (!browserPath) {
|
||||||
|
throw new Error("No installed Chrome or Edge browser found. Set SFERA_BROWSER_PATH.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const runtimeErrors = [];
|
||||||
|
const browser = await chromium.launch({
|
||||||
|
executablePath: browserPath,
|
||||||
|
headless: true
|
||||||
|
});
|
||||||
|
|
||||||
|
function assertNoFatalRuntimeErrors(stage) {
|
||||||
|
const fatalErrors = runtimeErrors.filter((message) => {
|
||||||
|
return (
|
||||||
|
message.includes("Runtime TypeError") ||
|
||||||
|
message.includes("Cannot read properties") ||
|
||||||
|
message.includes("Unhandled Runtime Error")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (fatalErrors.length > 0) {
|
||||||
|
throw new Error(`${stage} failed:\n${fatalErrors.join("\n")}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function collapseBottomPanelIfOpen(page) {
|
||||||
|
if ((await page.locator("[data-bottom-tool-panel]").count()) > 0) {
|
||||||
|
await page.keyboard.press("Alt+3");
|
||||||
|
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.setViewportSize({ width: 1680, height: 1050 });
|
||||||
|
page.on("pageerror", (error) => {
|
||||||
|
runtimeErrors.push(`pageerror: ${error.message}`);
|
||||||
|
});
|
||||||
|
page.on("console", (message) => {
|
||||||
|
if (message.type() === "error") {
|
||||||
|
runtimeErrors.push(`console: ${message.text()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await page.goto(`${baseUrl}/editor?lang=ru&project=${encodeURIComponent(projectId)}&mode=module`, {
|
||||||
|
waitUntil: "load",
|
||||||
|
timeout: 60000
|
||||||
|
});
|
||||||
|
if (!response?.ok()) {
|
||||||
|
throw new Error(`editor runtime smoke: ${response?.status()} ${response?.statusText()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.getByRole("heading", { name: "Редактор BSL" }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByRole("heading", { name: "Семантический diff" }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
for (const marker of ["snapshot", "agent", "parser", "diagnostics", "active-task", "privacy", "ai-tokens", "current-user"]) {
|
||||||
|
await page.locator(`[data-status-item="${marker}"]`).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
await page.locator("[data-global-search-input]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.keyboard.press("Control+K");
|
||||||
|
const globalSearchFocused = await page.locator("[data-global-search-input]").evaluate((input) => document.activeElement === input);
|
||||||
|
if (!globalSearchFocused) {
|
||||||
|
throw new Error("Ctrl+K did not focus global search");
|
||||||
|
}
|
||||||
|
await page.evaluate(() => {
|
||||||
|
window.dispatchEvent(new KeyboardEvent("keydown", { key: "F5", bubbles: true, cancelable: true }));
|
||||||
|
});
|
||||||
|
await page.locator("[data-run-check-status]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("[data-left-navigation-panel]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
const hasVirtualScrollContainer =
|
||||||
|
(await page.locator("[data-virtual-scroll]").count()) > 0 ||
|
||||||
|
(await page.locator("[data-fallback-tree-scroll]").count()) > 0;
|
||||||
|
if (!hasVirtualScrollContainer) {
|
||||||
|
throw new Error("Left navigation panel has no virtual/fallback scroll container marker");
|
||||||
|
}
|
||||||
|
await page.locator("[data-right-context-inspector]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
for (const tabName of ["Проблемы", "Semantic diff", "Вывод", "История", "Тесты", "AI"]) {
|
||||||
|
await page.locator("[data-bottom-tool-panel]").getByText(tabName).first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
await page.locator("[data-fallback-tree-search-input]").fill("SFERA");
|
||||||
|
await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("[data-fallback-tree-search-input]").fill("");
|
||||||
|
await page.locator("[data-fallback-tree-filter='sfera']").click();
|
||||||
|
await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("[data-fallback-tree-filter='all']").click();
|
||||||
|
const lazyFilterCount = await page.locator("[data-lazy-tree-filter]").count();
|
||||||
|
if (lazyFilterCount > 0) {
|
||||||
|
await page.locator("[data-lazy-tree-filter='sfera']").click();
|
||||||
|
await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("[data-lazy-tree-filter='all']").click();
|
||||||
|
}
|
||||||
|
await page.keyboard.press("Alt+1");
|
||||||
|
await page.locator("[data-left-navigation-panel]").waitFor({ state: "detached", timeout: 15000 });
|
||||||
|
await page.locator("[data-panel-rail]").first().click();
|
||||||
|
await page.locator("[data-left-navigation-panel]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.keyboard.press("Alt+2");
|
||||||
|
await page.locator("[data-right-context-inspector]").waitFor({ state: "detached", timeout: 15000 });
|
||||||
|
await page.locator("[data-panel-rail]").last().click();
|
||||||
|
await page.locator("[data-right-context-inspector]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.keyboard.press("Alt+3");
|
||||||
|
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 });
|
||||||
|
await page.getByRole("button", { name: "Нижняя панель" }).click();
|
||||||
|
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.keyboard.press("Alt+3");
|
||||||
|
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 });
|
||||||
|
const activeDocumentBeforeNext = await page.locator('[data-open-document][aria-pressed="true"]').first().getAttribute("data-open-document");
|
||||||
|
const openDocumentCount = await page.locator("[data-open-document]").count();
|
||||||
|
if (openDocumentCount < 2) {
|
||||||
|
throw new Error("Open Objects Bar has fewer than two switchable objects");
|
||||||
|
}
|
||||||
|
await page.evaluate(() => {
|
||||||
|
window.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab", ctrlKey: true, bubbles: true, cancelable: true }));
|
||||||
|
});
|
||||||
|
const activeDocumentAfterNext = await page.locator('[data-open-document][aria-pressed="true"]').first().getAttribute("data-open-document");
|
||||||
|
if (!activeDocumentAfterNext || activeDocumentAfterNext === activeDocumentBeforeNext) {
|
||||||
|
throw new Error("Ctrl+Tab did not switch the active open object");
|
||||||
|
}
|
||||||
|
await page.evaluate(() => {
|
||||||
|
window.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab", ctrlKey: true, shiftKey: true, bubbles: true, cancelable: true }));
|
||||||
|
});
|
||||||
|
await page.locator(`[data-open-document="${activeDocumentBeforeNext}"][aria-pressed="true"]`).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator(`[data-open-document-pin="${activeDocumentAfterNext}"]`).click();
|
||||||
|
const pinnedCloseButton = page.locator(`[data-open-document-close="${activeDocumentAfterNext}"]`);
|
||||||
|
if (!(await pinnedCloseButton.isDisabled())) {
|
||||||
|
throw new Error("Pinned open object close button is not disabled");
|
||||||
|
}
|
||||||
|
await page.locator(`[data-open-document-pin="${activeDocumentAfterNext}"]`).click();
|
||||||
|
await pinnedCloseButton.click();
|
||||||
|
await page.locator(`[data-open-document="${activeDocumentAfterNext}"]`).waitFor({ state: "detached", timeout: 15000 });
|
||||||
|
const ctrlWCandidate = await page.evaluate(() => {
|
||||||
|
const buttons = Array.from(document.querySelectorAll<HTMLElement>("[data-open-document]"));
|
||||||
|
const candidate = buttons.find((button) => button.getAttribute("data-open-document-mode") !== "module");
|
||||||
|
return candidate?.getAttribute("data-open-document") ?? null;
|
||||||
|
});
|
||||||
|
if (ctrlWCandidate) {
|
||||||
|
const targetTab = page.locator(`[data-open-document="${ctrlWCandidate}"]`);
|
||||||
|
await targetTab.click();
|
||||||
|
await page.evaluate(() => {
|
||||||
|
window.dispatchEvent(new KeyboardEvent("keydown", { key: "w", ctrlKey: true, bubbles: true, cancelable: true }));
|
||||||
|
});
|
||||||
|
await targetTab.waitFor({ state: "detached", timeout: 15000 });
|
||||||
|
const moduleTabs = page.locator('[data-open-document-mode="module"]');
|
||||||
|
const moduleTabCount = await moduleTabs.count();
|
||||||
|
if (moduleTabCount > 0) {
|
||||||
|
await moduleTabs.first().click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const openObjectsState = await page.evaluate((storageKey) => window.localStorage.getItem(storageKey), `sfera.open-objects.${projectId}`);
|
||||||
|
if (!openObjectsState?.includes(activeDocumentAfterNext)) {
|
||||||
|
throw new Error("Open Objects Bar state was not persisted");
|
||||||
|
}
|
||||||
|
await page.reload({ waitUntil: "load", timeout: 60000 });
|
||||||
|
await page.getByRole("heading", { name: "Редактор BSL" }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
const restoredState = await page.evaluate((storageKey) => window.localStorage.getItem(storageKey), `sfera.open-objects.${projectId}`);
|
||||||
|
if (restoredState !== openObjectsState) {
|
||||||
|
throw new Error("Open Objects Bar state was not restored after reload");
|
||||||
|
}
|
||||||
|
await page.locator(`[data-open-document="${activeDocumentAfterNext}"]`).waitFor({ state: "detached", timeout: 15000 });
|
||||||
|
const restoredModuleTabs = page.locator('[data-open-document-mode="module"]');
|
||||||
|
if ((await restoredModuleTabs.count()) > 0) {
|
||||||
|
await restoredModuleTabs.first().click();
|
||||||
|
}
|
||||||
|
await page.locator(".monaco-editor").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("#symbol-search-input").fill("Проверить");
|
||||||
|
await page.locator("#symbol-search-input").press("Enter");
|
||||||
|
await page.locator("[data-symbol-result]").first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator('button[data-editor-action="find-usages"]').click();
|
||||||
|
await page.locator("[data-symbol-references]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
const applyButton = page.locator('button[data-editor-action="apply-to-sfera"]');
|
||||||
|
await applyButton.waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
if (await applyButton.isEnabled()) {
|
||||||
|
await applyButton.click();
|
||||||
|
await page.getByText("Записано в SFERA").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
assertNoFatalRuntimeErrors("editor module runtime smoke");
|
||||||
|
|
||||||
|
const versionsResponse = await page.goto(`${baseUrl}/editor?lang=ru&project=${encodeURIComponent(projectId)}&mode=versions`, {
|
||||||
|
waitUntil: "load",
|
||||||
|
timeout: 60000
|
||||||
|
});
|
||||||
|
if (!versionsResponse?.ok()) {
|
||||||
|
throw new Error(`editor versions runtime smoke: ${versionsResponse?.status()} ${versionsResponse?.statusText()}`);
|
||||||
|
}
|
||||||
|
await page.getByRole("heading", { name: "Версии" }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await collapseBottomPanelIfOpen(page);
|
||||||
|
await page.getByText("Линия версий").first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
const versionButtons = page.locator("button[data-version-id]");
|
||||||
|
const versionButtonCount = await versionButtons.count();
|
||||||
|
if (versionButtonCount > 0) {
|
||||||
|
await versionButtons.first().click();
|
||||||
|
await page.getByText("Полные данные").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
assertNoFatalRuntimeErrors("editor versions runtime smoke");
|
||||||
|
|
||||||
|
const rollbackButtons = page.locator('button[data-editor-action="rollback-plan"]');
|
||||||
|
const rollbackButtonCount = await rollbackButtons.count();
|
||||||
|
if (rollbackButtonCount > 0) {
|
||||||
|
await rollbackButtons.first().click();
|
||||||
|
await page.locator("[data-rollback-preview]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
const applyRollbackButton = page.locator('button[data-editor-action="apply-rollback"]');
|
||||||
|
await applyRollbackButton.waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
if (await applyRollbackButton.isEnabled()) {
|
||||||
|
await applyRollbackButton.click();
|
||||||
|
await page.locator("[data-rollback-apply-message]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertNoFatalRuntimeErrors("editor rollback runtime smoke");
|
||||||
|
|
||||||
|
const metadataResponse = await page.goto(`${baseUrl}/editor?lang=ru&project=${encodeURIComponent(projectId)}&mode=properties`, {
|
||||||
|
waitUntil: "load",
|
||||||
|
timeout: 60000
|
||||||
|
});
|
||||||
|
if (!metadataResponse?.ok()) {
|
||||||
|
throw new Error(`editor metadata runtime smoke: ${metadataResponse?.status()} ${metadataResponse?.statusText()}`);
|
||||||
|
}
|
||||||
|
await page.getByRole("heading", { name: "Свойства" }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await collapseBottomPanelIfOpen(page);
|
||||||
|
await page.getByLabel("Имя объекта").fill(`АвтоОбъект${uniqueSuffix}`);
|
||||||
|
await page.getByLabel("Синоним").fill(`Авто объект ${uniqueSuffix}`);
|
||||||
|
const addAttributeButton = page.locator('button[data-editor-action="add-metadata-attribute"]');
|
||||||
|
await addAttributeButton.waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await addAttributeButton.click();
|
||||||
|
await page.getByRole("textbox", { name: "Имя реквизита" }).nth(1).fill("Комментарий");
|
||||||
|
await page.getByRole("textbox", { name: "Тип" }).nth(1).fill("Строка250");
|
||||||
|
const addFormButton = page.locator('button[data-editor-action="add-metadata-form"]');
|
||||||
|
await addFormButton.waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await addFormButton.click();
|
||||||
|
await page.getByRole("textbox", { name: "Имя формы" }).last().fill(`ФормаВыбора${uniqueSuffix}`);
|
||||||
|
const addCommandButton = page.locator('button[data-editor-action="add-metadata-command"]');
|
||||||
|
await addCommandButton.waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await addCommandButton.click();
|
||||||
|
await page.getByRole("textbox", { name: "Имя команды" }).last().fill(`Отправить${uniqueSuffix}`);
|
||||||
|
await page.getByRole("textbox", { name: "Обработчик" }).last().fill(`Отправить${uniqueSuffix}Команда`);
|
||||||
|
const metadataButton = page.locator('button[data-editor-action="apply-metadata-object"]');
|
||||||
|
await metadataButton.waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
if (await metadataButton.isEnabled()) {
|
||||||
|
await metadataButton.click();
|
||||||
|
const draftMessage = page.locator("[data-metadata-draft-message]");
|
||||||
|
await draftMessage.waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
try {
|
||||||
|
await page.locator("[data-metadata-draft-preview]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`metadata draft preview did not appear: ${await draftMessage.textContent()}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertNoFatalRuntimeErrors("editor metadata runtime smoke");
|
||||||
|
|
||||||
|
const englishResponse = await page.goto(`${baseUrl}/editor?lang=en&project=${encodeURIComponent(projectId)}&mode=module`, {
|
||||||
|
waitUntil: "load",
|
||||||
|
timeout: 60000
|
||||||
|
});
|
||||||
|
if (!englishResponse?.ok()) {
|
||||||
|
throw new Error(`editor english runtime smoke: ${englishResponse?.status()} ${englishResponse?.statusText()}`);
|
||||||
|
}
|
||||||
|
await page.getByRole("heading", { name: "BSL Editor" }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("[data-top-project-bar]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
for (const selector of ["workspace", "project", "environment", "active-task"]) {
|
||||||
|
await page.locator(`[data-top-bar-selector="${selector}"]`).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
for (const action of ["project-settings", "create-project"]) {
|
||||||
|
await page.locator(`[data-top-bar-action="${action}"]`).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
for (const badge of ["api-status", "agent-status"]) {
|
||||||
|
await page.locator(`[data-top-bar-badge="${badge}"]`).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
await page.locator("[data-top-bar-language]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator('[data-top-bar-button="profile"]').waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
for (const tabName of ["Problems", "Semantic diff", "Output", "Change history", "Tests", "AI"]) {
|
||||||
|
await page.locator("[data-bottom-tool-panel]").getByText(tabName).first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
for (const statusMarker of ["snapshot", "agent", "parser", "diagnostics", "active-task", "privacy", "ai-tokens", "current-user"]) {
|
||||||
|
await page.locator(`[data-status-item="${statusMarker}"]`).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
assertNoFatalRuntimeErrors("editor english runtime smoke");
|
||||||
|
|
||||||
|
console.log("ok editor runtime");
|
||||||
|
} finally {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
import { chromium } from "playwright-core";
|
||||||
|
import { existsSync } from "node:fs";
|
||||||
|
|
||||||
|
const baseUrl = process.env.SFERA_WEB_URL ?? "http://localhost:3000";
|
||||||
|
const projectId = process.env.SFERA_PROJECT_ID ?? "default";
|
||||||
|
const browserPath =
|
||||||
|
process.env.SFERA_BROWSER_PATH ??
|
||||||
|
[
|
||||||
|
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
||||||
|
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
|
||||||
|
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe"
|
||||||
|
].find((path) => existsSync(path));
|
||||||
|
|
||||||
|
if (!browserPath) {
|
||||||
|
throw new Error("No installed Chrome or Edge browser found. Set SFERA_BROWSER_PATH.");
|
||||||
|
}
|
||||||
|
|
||||||
|
await prepareIndexedProject();
|
||||||
|
|
||||||
|
const runtimeErrors = [];
|
||||||
|
const browser = await chromium.launch({
|
||||||
|
executablePath: browserPath,
|
||||||
|
headless: true
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const page = await browser.newPage();
|
||||||
|
page.on("pageerror", (error) => {
|
||||||
|
runtimeErrors.push(`pageerror: ${error.message}`);
|
||||||
|
});
|
||||||
|
page.on("console", (message) => {
|
||||||
|
if (message.type() === "error") {
|
||||||
|
runtimeErrors.push(`console: ${message.text()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await page.goto(`${baseUrl}/project-settings`, { waitUntil: "load", timeout: 60000 });
|
||||||
|
if (!response?.ok()) {
|
||||||
|
throw new Error(`project setup smoke: ${response?.status()} ${response?.statusText()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.locator("[data-project-import-center]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByRole("heading", { name: "Project Settings" }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
for (const section of ["Пользователи и доступ", "Интеграции задач", "Docker/runtime adapter", "Audit", "Backup/restore"]) {
|
||||||
|
await page.getByText(section).first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
for (const sectionMarker of ["docker-runtime-adapter", "its-documentation-access"]) {
|
||||||
|
await page.locator(`[data-settings-section="${sectionMarker}"]`).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
await page.getByText("ITS/documentation access").first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("SFERA_ITS_URL").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("SFERA_ITS_USERNAME").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("SFERA_ITS_PASSWORD").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("input[value*='its.1c.ru/db/v838doc']").first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText(".env.local").first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("input[value='<set locally>']").first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("select").filter({ hasText: "REFERENCE_CONFIGURATION" }).first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByRole("button", { name: /Reference config/ }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
const hasMetadataOnlyPrivacy = await page.locator("select").evaluateAll((selects) => {
|
||||||
|
return selects.some((select) => select.value === "METADATA_ONLY" || [...select.options].some((option) => option.value === "METADATA_ONLY"));
|
||||||
|
});
|
||||||
|
if (!hasMetadataOnlyPrivacy) {
|
||||||
|
throw new Error("project setup smoke: missing METADATA_ONLY privacy mode");
|
||||||
|
}
|
||||||
|
await page.getByText("Project Setup / Import Center").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("Режим работы с конфигурацией 1С").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator('[data-import-mode="FULL_REPLACE"]').waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator('[data-run-import-mode="SYNC_PREVIEW"]').click();
|
||||||
|
const importMode = await page.evaluate(() => window.localStorage.getItem("sfera.import.mode"));
|
||||||
|
if (importMode !== "SYNC_PREVIEW") {
|
||||||
|
throw new Error(`project setup smoke: import mode was not persisted, got ${importMode}`);
|
||||||
|
}
|
||||||
|
await page.locator('[data-run-import-mode="FULL_REPLACE"]').click();
|
||||||
|
await page.locator("[data-import-validation-panel]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("Не заполнен путь к источнику").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator('input[placeholder*="/mnt/share/project"]').fill("/tmp/nonexistent-smoke-import");
|
||||||
|
await page.locator('[data-run-import-mode="FULL_REPLACE"]').click();
|
||||||
|
await page.getByText("Подтвердите полное обновление").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByRole("button", { name: "Отмена" }).click();
|
||||||
|
await page.locator('[data-run-import-mode="SYNC_PREVIEW"]').click();
|
||||||
|
await page.locator('[data-import-action="XML_DUMP:check"]').click();
|
||||||
|
await page.locator("[data-import-check-panel]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("Source preflight").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
|
||||||
|
const englishResponse = await page.goto(`${baseUrl}/project-settings?lang=en`, { waitUntil: "load", timeout: 60000 });
|
||||||
|
if (!englishResponse?.ok()) {
|
||||||
|
throw new Error(`project setup smoke (en): ${englishResponse?.status()} ${englishResponse?.statusText()}`);
|
||||||
|
}
|
||||||
|
await page.getByRole("heading", { name: "Project Settings" }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
for (const section of ["Task/session policy", "Docker/runtime adapter", "ITS/documentation access", "Audit", "Backup/restore"]) {
|
||||||
|
await page.getByText(section).first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
for (const sectionMarker of ["task-session-policy", "docker-runtime-adapter", "its-documentation-access"]) {
|
||||||
|
await page.locator(`[data-settings-section="${sectionMarker}"]`).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
}
|
||||||
|
await page.locator("select").filter({ hasText: "REFERENCE_CONFIGURATION" }).first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByRole("button", { name: /Reference config/ }).waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("SFERA_ITS_URL").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("SFERA_ITS_USERNAME").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("SFERA_ITS_PASSWORD").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText(".env.local").first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator("input[value='<set locally>']").first().waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.locator('[data-import-action="XML_DUMP:check"]').click();
|
||||||
|
await page.locator("[data-import-check-panel]").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
await page.getByText("Source preflight").waitFor({ state: "visible", timeout: 15000 });
|
||||||
|
|
||||||
|
assertNoFatalRuntimeErrors();
|
||||||
|
console.log("ok project setup runtime");
|
||||||
|
} finally {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function prepareIndexedProject() {
|
||||||
|
await postJson(`/api/sfera/projects/${encodeURIComponent(projectId)}/settings`, {
|
||||||
|
name: "SFERA Smoke Project",
|
||||||
|
structure_source: "XML_DUMP",
|
||||||
|
platform_version: "8.3.24",
|
||||||
|
compatibility_mode: "8.3.20"
|
||||||
|
});
|
||||||
|
await postJson(`/api/sfera/projects/${encodeURIComponent(projectId)}/imports/XML_DUMP`, {
|
||||||
|
source: "XML_DUMP",
|
||||||
|
metadata: {
|
||||||
|
platform_version: "8.3.24",
|
||||||
|
compatibility_mode: "8.3.20"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function postJson(path, body) {
|
||||||
|
const response = await fetch(`${baseUrl}${path}`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { Accept: "application/json", "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`${path}: ${response.status} ${await response.text()}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertNoFatalRuntimeErrors() {
|
||||||
|
const fatalErrors = runtimeErrors.filter((message) => {
|
||||||
|
return (
|
||||||
|
message.includes("Runtime TypeError") ||
|
||||||
|
message.includes("Cannot read properties") ||
|
||||||
|
message.includes("Unhandled Runtime Error")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (fatalErrors.length > 0) {
|
||||||
|
throw new Error(`project setup runtime smoke failed:\n${fatalErrors.join("\n")}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { resolveApiUrl } from "@/lib/api";
|
||||||
|
|
||||||
|
type RouteContext = {
|
||||||
|
params: Promise<{ path: string[] }>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function GET(request: Request, context: RouteContext) {
|
||||||
|
return proxy(request, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function POST(request: Request, context: RouteContext) {
|
||||||
|
return proxy(request, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function PUT(request: Request, context: RouteContext) {
|
||||||
|
return proxy(request, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function PATCH(request: Request, context: RouteContext) {
|
||||||
|
return proxy(request, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function DELETE(request: Request, context: RouteContext) {
|
||||||
|
return proxy(request, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function OPTIONS(request: Request, context: RouteContext) {
|
||||||
|
return proxy(request, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function HEAD(request: Request, context: RouteContext) {
|
||||||
|
return proxy(request, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function proxy(request: Request, context: RouteContext) {
|
||||||
|
const { path } = await context.params;
|
||||||
|
const apiUrl = resolveApiUrl(request.headers.get("host"));
|
||||||
|
const sourceUrl = new URL(request.url);
|
||||||
|
const target = `${apiUrl}/${path.join("/")}${sourceUrl.search}`;
|
||||||
|
const method = request.method;
|
||||||
|
const hasBody = method !== "GET" && method !== "HEAD" && request.body !== null;
|
||||||
|
const body = hasBody ? await request.arrayBuffer() : undefined;
|
||||||
|
const contentType = request.headers.get("Content-Type");
|
||||||
|
const accept = request.headers.get("Accept") ?? "application/json";
|
||||||
|
const publicHost = request.headers.get("x-forwarded-host") ?? request.headers.get("host");
|
||||||
|
const publicProto = request.headers.get("x-forwarded-proto") ?? "http";
|
||||||
|
const publicOrigin = publicHost ? `${publicProto}://${publicHost}` : sourceUrl.origin;
|
||||||
|
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
Accept: accept,
|
||||||
|
"X-Sfera-Public-Origin": publicOrigin
|
||||||
|
};
|
||||||
|
if (hasBody) {
|
||||||
|
headers["Content-Type"] = contentType ?? "application/json";
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(target, {
|
||||||
|
method,
|
||||||
|
cache: "no-store",
|
||||||
|
headers,
|
||||||
|
body
|
||||||
|
});
|
||||||
|
const responseHeaders: Record<string, string> = {
|
||||||
|
"Content-Type": response.headers.get("Content-Type") ?? "application/json"
|
||||||
|
};
|
||||||
|
const contentDisposition = response.headers.get("Content-Disposition");
|
||||||
|
if (contentDisposition) {
|
||||||
|
responseHeaders["Content-Disposition"] = contentDisposition;
|
||||||
|
}
|
||||||
|
const cacheControl = response.headers.get("Cache-Control");
|
||||||
|
if (cacheControl) {
|
||||||
|
responseHeaders["Cache-Control"] = cacheControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(response.body, {
|
||||||
|
status: response.status,
|
||||||
|
headers: responseHeaders
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import { AlertTriangle } from "lucide-react";
|
||||||
|
import { headers } from "next/headers";
|
||||||
|
|
||||||
|
import { IdeWorkspace } from "@/components/editor/ide-workspace";
|
||||||
|
import { AppShell } from "@/components/layout/app-shell";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
|
import {
|
||||||
|
getApiHealth,
|
||||||
|
getProjects,
|
||||||
|
getProjectWorkspaceData,
|
||||||
|
resolveApiUrl,
|
||||||
|
type ProjectSummary
|
||||||
|
} from "@/lib/api";
|
||||||
|
import { messages, normalizeLanguage, type UiLanguage } from "@/lib/i18n";
|
||||||
|
|
||||||
|
export default async function EditorPage({
|
||||||
|
searchParams
|
||||||
|
}: Readonly<{
|
||||||
|
searchParams?: Promise<{ lang?: string; mode?: string; project?: string; routine?: string }>;
|
||||||
|
}>) {
|
||||||
|
const params = await searchParams;
|
||||||
|
const language = normalizeLanguage(params?.lang);
|
||||||
|
const requestHeaders = await headers();
|
||||||
|
const apiUrl = resolveApiUrl(requestHeaders.get("host"));
|
||||||
|
const bootstrap = await loadEditorBootstrap(apiUrl, language, params?.project);
|
||||||
|
const projectData =
|
||||||
|
bootstrap.status === "ok" && bootstrap.projectId ? await getProjectWorkspaceData(bootstrap.projectId, apiUrl, params?.routine, params?.mode) : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppShell
|
||||||
|
apiStatus={bootstrap.status}
|
||||||
|
language={language}
|
||||||
|
projectId={bootstrap.status === "ok" ? bootstrap.projectId : undefined}
|
||||||
|
projectOptions={bootstrap.status === "ok" ? bootstrap.projects : []}
|
||||||
|
>
|
||||||
|
<main className="pb-8">
|
||||||
|
{bootstrap.status === "error" ? (
|
||||||
|
<ErrorState language={language} message={bootstrap.error} />
|
||||||
|
) : projectData ? (
|
||||||
|
<IdeWorkspace
|
||||||
|
key={projectData.projectId}
|
||||||
|
data={projectData}
|
||||||
|
initialMode={params?.mode}
|
||||||
|
language={language}
|
||||||
|
routineName={params?.routine}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<ErrorState language={language} message={messages[language].noProjectDataDescription} />
|
||||||
|
)}
|
||||||
|
</main>
|
||||||
|
</AppShell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadEditorBootstrap(apiUrl: string, language: UiLanguage, projectId?: string): Promise<
|
||||||
|
| { status: "ok"; projectId: string | undefined; projects: ProjectSummary[] }
|
||||||
|
| { status: "error"; error: string }
|
||||||
|
> {
|
||||||
|
try {
|
||||||
|
const [projectsResponse] = await Promise.all([getProjects(apiUrl), getApiHealth(apiUrl)]);
|
||||||
|
const projects = uniqueProjects(projectsResponse);
|
||||||
|
return { status: "ok", projectId: projectId || pickDefaultProject(projectsResponse), projects };
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
status: "error",
|
||||||
|
error: error instanceof Error ? error.message : messages[language].unknownApiError
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ErrorState({
|
||||||
|
message,
|
||||||
|
language
|
||||||
|
}: Readonly<{
|
||||||
|
message: string;
|
||||||
|
language: UiLanguage;
|
||||||
|
}>) {
|
||||||
|
const t = messages[language];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx-auto flex min-h-[70vh] max-w-xl items-center justify-center">
|
||||||
|
<Card className="w-full">
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<AlertTriangle className="mt-1 h-5 w-5 text-destructive" aria-hidden="true" />
|
||||||
|
<div>
|
||||||
|
<h1 className="text-base font-semibold">{t.apiUnavailable}</h1>
|
||||||
|
<p className="mt-2 text-sm leading-6 text-muted-foreground">{message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickDefaultProject(projects: ProjectSummary[]) {
|
||||||
|
return (
|
||||||
|
projects.find((project) => project.project_id === "ifcm-upo")?.project_id ??
|
||||||
|
projects.find((project) => project.project_id !== "demo")?.project_id ??
|
||||||
|
projects.at(-1)?.project_id ??
|
||||||
|
projects.find((project) => project.project_id === "demo")?.project_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function uniqueProjects(projects: ProjectSummary[]) {
|
||||||
|
const byId = new Map<string, ProjectSummary>();
|
||||||
|
for (const project of projects) {
|
||||||
|
const projectId = project.project_id.trim();
|
||||||
|
if (projectId) {
|
||||||
|
byId.set(projectId, { ...project, project_id: projectId, name: project.name || projectId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Array.from(byId.values()).sort((left, right) => (left.name || left.project_id).localeCompare(right.name || right.project_id, "ru"));
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background: 210 20% 98%;
|
||||||
|
--foreground: 222 47% 11%;
|
||||||
|
--card: 0 0% 100%;
|
||||||
|
--card-foreground: 222 47% 11%;
|
||||||
|
--muted: 210 17% 94%;
|
||||||
|
--muted-foreground: 215 16% 47%;
|
||||||
|
--border: 214 20% 88%;
|
||||||
|
--input: 214 20% 88%;
|
||||||
|
--primary: 198 93% 32%;
|
||||||
|
--primary-foreground: 0 0% 100%;
|
||||||
|
--secondary: 168 42% 39%;
|
||||||
|
--secondary-foreground: 0 0% 100%;
|
||||||
|
--destructive: 0 72% 45%;
|
||||||
|
--warning: 38 92% 48%;
|
||||||
|
--success: 142 54% 36%;
|
||||||
|
--info: 214 84% 56%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
--background: 220 24% 10%;
|
||||||
|
--foreground: 210 20% 96%;
|
||||||
|
--card: 220 20% 14%;
|
||||||
|
--card-foreground: 210 20% 96%;
|
||||||
|
--muted: 220 16% 20%;
|
||||||
|
--muted-foreground: 215 15% 66%;
|
||||||
|
--border: 220 16% 24%;
|
||||||
|
--input: 220 16% 24%;
|
||||||
|
--primary: 194 80% 46%;
|
||||||
|
--primary-foreground: 0 0% 100%;
|
||||||
|
--secondary: 164 52% 43%;
|
||||||
|
--secondary-foreground: 0 0% 100%;
|
||||||
|
--destructive: 0 72% 51%;
|
||||||
|
--warning: 38 92% 52%;
|
||||||
|
--success: 142 54% 42%;
|
||||||
|
--info: 214 84% 62%;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
background: hsl(var(--background));
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
background: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
font-family:
|
||||||
|
Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background: hsl(var(--primary) / 0.18);
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export async function GET() {
|
||||||
|
return Response.json({ status: "ok", service: "sfera-web" });
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import type React from "react";
|
||||||
|
import "./globals.css";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "SFERA",
|
||||||
|
description: "Semantic 1C operating workspace"
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||||
|
return (
|
||||||
|
<html lang="ru">
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
|
export default async function HomePage({
|
||||||
|
searchParams
|
||||||
|
}: Readonly<{
|
||||||
|
searchParams?: Promise<{ lang?: string; mode?: string; project?: string; routine?: string }>;
|
||||||
|
}>) {
|
||||||
|
const params = await searchParams;
|
||||||
|
const nextParams = new URLSearchParams();
|
||||||
|
if (params?.lang === "en") {
|
||||||
|
nextParams.set("lang", "en");
|
||||||
|
}
|
||||||
|
for (const key of ["project", "mode", "routine"] as const) {
|
||||||
|
const value = params?.[key];
|
||||||
|
if (value) {
|
||||||
|
nextParams.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const suffix = nextParams.size > 0 ? `?${nextParams.toString()}` : "";
|
||||||
|
|
||||||
|
redirect(`/editor${suffix}`);
|
||||||
|
}
|
||||||