sync: latest changes before Gitea migration
This commit is contained in:
1 parent
c2cc439fc5
commit
acba5dd5f1
148 files changed
+13001
-696
No files matched your search
@@ -0,0 +1,463 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru-ru">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Leadera — Фильтры и реорганизация списка диаграмм Ганта — docs.a2v.space</title>
|
||||
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../../css/custom.css">
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="../../">docs.a2v.space</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarMain" aria-controls="navbarMain" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarMain">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../../diary/">Дневник</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../../kb/">База знаний</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../../plans/">Планы</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../../leadera/">Leadera</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../../guides/">Инструкции</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../../creds/">Креды</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../../personal-site/">Личный сайт</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<form class="d-flex search-form" role="search">
|
||||
<input class="form-control me-2" type="search" placeholder="Поиск..." aria-label="Search" id="search-input">
|
||||
<button class="btn btn-outline-light" type="submit">Найти</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-outline-light d-md-none ms-2" type="button" data-bs-toggle="collapse" data-bs-target="#sidebar" aria-expanded="false" aria-controls="sidebar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
<div id="search-results" class="search-results" style="display: none;">
|
||||
<div class="search-results-content">
|
||||
<button type="button" class="btn-close float-end" id="close-search"></button>
|
||||
<h5>Результаты поиска</h5>
|
||||
<ul id="results-list"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
|
||||
<aside class="col-md-3 col-lg-2 d-md-block sidebar collapse" id="sidebar">
|
||||
<div class="sidebar-content">
|
||||
|
||||
|
||||
|
||||
<h6>Разделы</h6>
|
||||
<ul class="nav flex-column">
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="../../diary/">Дневник</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="../../kb/">База знаний</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="../../plans/">Планы</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="../../leadera/">Leadera</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="../../guides/">Инструкции</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="../../creds/">Креды</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="../../personal-site/">Личный сайт</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
<main class="col-md-9 col-lg-10 main-content">
|
||||
|
||||
<div class="article-content">
|
||||
<h1>Leadera — Фильтры и реорганизация списка диаграмм Ганта</h1>
|
||||
<div class="source-path mb-3">
|
||||
<small class="text-muted">
|
||||
📁 <code id="source-path" class="user-select-all">~/Projects/docs-a2v/content/leadera/leadera-gantt-filters.md</code>
|
||||
<button class="btn btn-sm btn-outline-secondary ms-1 py-0 px-1" onclick="navigator.clipboard.writeText('~/Projects/docs-a2v/content/leadera\/leadera-gantt-filters.md')" title="Копировать путь">
|
||||
📋
|
||||
</button>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="tags mb-3">
|
||||
|
||||
<a href="../../tags/leadera/" class="tag">leadera</a>
|
||||
|
||||
<a href="../../tags/gantt/" class="tag">gantt</a>
|
||||
|
||||
<a href="../../tags/api/" class="tag">api</a>
|
||||
|
||||
<a href="../../tags/frontend/" class="tag">frontend</a>
|
||||
|
||||
<a href="../../tags/requirements/" class="tag">requirements</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<h1 id="фильтры-и-реорганизация-списка-диаграмм-ганта">Фильтры и реорганизация списка диаграмм Ганта</h1>
|
||||
<p><strong>Дата:</strong> 07.04.2026
|
||||
<strong>Статус:</strong> Требования
|
||||
<strong>Проект:</strong> Leadera (dev — sand.a2v.space)</p>
|
||||
<hr>
|
||||
<h2 id="1-постановка-задачи">1. Постановка задачи</h2>
|
||||
<p>Список диаграмм Ганта должен показывать <strong>все доступные пользователю диаграммы</strong> из всех пространств (spaces), с возможностью фильтрации и поиска. Сейчас список привязан к одному пространству — нужно убрать эту зависимость и добавить удобный toolbar.</p>
|
||||
<hr>
|
||||
<h2 id="2-изменения-api">2. Изменения API</h2>
|
||||
<h3 id="21-новый-endpoint-списка-диаграмм">2.1. Новый endpoint списка диаграмм</h3>
|
||||
<p><strong>Было:</strong></p>
|
||||
<pre tabindex="0"><code>GET /api/v1/spaces/{spaceId}/gantt-charts?page=1&per_page=10
|
||||
</code></pre><p><strong>Стало:</strong></p>
|
||||
<pre tabindex="0"><code>GET /api/v1/gantt-charts?page=1&per_page=10
|
||||
</code></pre><p>Пользователь видит все диаграммы из <strong>всех пространств</strong>, где он является подтверждённым участником (статус <code>accepted</code>).</p>
|
||||
<h3 id="22-параметры-фильтрации-и-поиска">2.2. Параметры фильтрации и поиска</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Параметр</th>
|
||||
<th>Тип</th>
|
||||
<th>Описание</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>page</code></td>
|
||||
<td>int</td>
|
||||
<td>Номер страницы (default: 1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>per_page</code></td>
|
||||
<td>int</td>
|
||||
<td>Записей на странице (default: 10)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>space_id</code></td>
|
||||
<td>UUID (optional)</td>
|
||||
<td>Фильтр по конкретному пространству</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>created_by</code></td>
|
||||
<td>UUID (optional)</td>
|
||||
<td>Фильтр по создателю диаграммы</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>search</code></td>
|
||||
<td>string (optional)</td>
|
||||
<td>Поиск по назвению и описанию (ILIKE, case-insensitive)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>sort</code></td>
|
||||
<td>string (optional)</td>
|
||||
<td>Сортировка: <code>created_at</code>, <code>updated_at</code>, <code>title</code> (default: <code>updated_at</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>order</code></td>
|
||||
<td>string (optional)</td>
|
||||
<td><code>asc</code> / <code>desc</code> (default: <code>desc</code>)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><strong>Примеры:</strong></p>
|
||||
<pre tabindex="0"><code>GET /api/v1/gantt-charts?search=миграция
|
||||
GET /api/v1/gantt-charts?space_id=0b334ded-...&created_by=a1b2c3d4-...
|
||||
GET /api/v1/gantt-charts?page=2&per_page=20&sort=title&order=asc
|
||||
</code></pre><h3 id="23-изменение-структуры-ответа">2.3. Изменение структуры ответа</h3>
|
||||
<p>Добавить поле <code>space</code> в каждую диаграмму:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"data"</span>: [
|
||||
</span></span><span style="display:flex;"><span> {
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"id"</span>: <span style="color:#e6db74">"uuid"</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"title"</span>: <span style="color:#e6db74">"Миграция backend"</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"description"</span>: <span style="color:#e6db74">"..."</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"created_by"</span>: <span style="color:#e6db74">"uuid"</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"created_by_name"</span>: <span style="color:#e6db74">"Антон Агальцов"</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"created_at"</span>: <span style="color:#e6db74">"2026-04-01T10:00:00Z"</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"updated_at"</span>: <span style="color:#e6db74">"2026-04-07T09:00:00Z"</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"space"</span>: {
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"id"</span>: <span style="color:#e6db74">"uuid"</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"name"</span>: <span style="color:#e6db74">"IT Ландшафт"</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"color"</span>: <span style="color:#e6db74">"#c4623a"</span>
|
||||
</span></span><span style="display:flex;"><span> },
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"is_archived"</span>: <span style="color:#66d9ef">false</span>
|
||||
</span></span><span style="display:flex;"><span> }
|
||||
</span></span><span style="display:flex;"><span> ],
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"pagination"</span>: {
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"page"</span>: <span style="color:#ae81ff">1</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"per_page"</span>: <span style="color:#ae81ff">10</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"total"</span>: <span style="color:#ae81ff">42</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"total_pages"</span>: <span style="color:#ae81ff">5</span>
|
||||
</span></span><span style="display:flex;"><span> }
|
||||
</span></span><span style="display:flex;"><span>}
|
||||
</span></span></code></pre></div><h3 id="24-endpoint-для-списка-фильтров">2.4. Endpoint для списка фильтров</h3>
|
||||
<p>Вспомогательный endpoint для заполнения dropdown-фильтров:</p>
|
||||
<pre tabindex="0"><code>GET /api/v1/gantt-charts/filters
|
||||
</code></pre><p><strong>Ответ:</strong></p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"spaces"</span>: [
|
||||
</span></span><span style="display:flex;"><span> { <span style="color:#f92672">"id"</span>: <span style="color:#e6db74">"uuid"</span>, <span style="color:#f92672">"name"</span>: <span style="color:#e6db74">"IT Ландшафт"</span>, <span style="color:#f92672">"color"</span>: <span style="color:#e6db74">"#c4623a"</span> },
|
||||
</span></span><span style="display:flex;"><span> { <span style="color:#f92672">"id"</span>: <span style="color:#e6db74">"uuid"</span>, <span style="color:#f92672">"name"</span>: <span style="color:#e6db74">"DevOps"</span>, <span style="color:#f92672">"color"</span>: <span style="color:#e6db74">"#27ae60"</span> }
|
||||
</span></span><span style="display:flex;"><span> ],
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">"creators"</span>: [
|
||||
</span></span><span style="display:flex;"><span> { <span style="color:#f92672">"id"</span>: <span style="color:#e6db74">"uuid"</span>, <span style="color:#f92672">"display_name"</span>: <span style="color:#e6db74">"Антон Агальцов"</span> },
|
||||
</span></span><span style="display:flex;"><span> { <span style="color:#f92672">"id"</span>: <span style="color:#e6db74">"uuid"</span>, <span style="color:#f92672">"display_name"</span>: <span style="color:#e6db74">"Иван Петров"</span> }
|
||||
</span></span><span style="display:flex;"><span> ]
|
||||
</span></span><span style="display:flex;"><span>}
|
||||
</span></span></code></pre></div><p><strong>Логика <code>creators</code>:</strong> уникальные создатели всех диаграмм, доступных текущему пользователю. Получается через DISTINCT-запрос по <code>created_by</code> с JOIN на users.</p>
|
||||
<h3 id="25-backend--изменения-в-go">2.5. Backend — изменения в Go</h3>
|
||||
<p><strong>Файлы для изменения:</strong></p>
|
||||
<h4 id="internalhandlersgantt_handlergo"><code>internal/handlers/gantt_handler.go</code></h4>
|
||||
<ul>
|
||||
<li>Добавить новый handler <code>ListAllGanttCharts</code> — без привязки к space</li>
|
||||
<li>Зарегистрировать маршрут <code>GET /gantt-charts</code> (без <code>/spaces/:id/</code>)</li>
|
||||
<li>Парсить query-параметры: <code>space_id</code>, <code>created_by</code>, <code>search</code>, <code>sort</code>, <code>order</code></li>
|
||||
<li>Старый маршрут <code>GET /spaces/:id/gantt-charts</code> — оставить для обратной совместимости (или удалить, если не используется)</li>
|
||||
</ul>
|
||||
<h4 id="internalservicegantt_servicego"><code>internal/service/gantt_service.go</code></h4>
|
||||
<ul>
|
||||
<li>Новый метод <code>ListAll(ctx, userId, filters)</code> — запрашивает все spaces пользователя (через <code>space_member</code> с <code>status=accepted</code>), затем выбирает все gantt_charts из этих spaces с фильтрами</li>
|
||||
</ul>
|
||||
<h4 id="internalrepositorygantt_repositorygo"><code>internal/repository/gantt_repository.go</code></h4>
|
||||
<ul>
|
||||
<li>Новый метод с динамическим SQL:
|
||||
<ul>
|
||||
<li>Базовый JOIN: <code>gantt_charts</code> → <code>spaces</code> → <code>space_members</code></li>
|
||||
<li>WHERE: <code>space_members.user_id = $1 AND space_members.status = 'accepted'</code></li>
|
||||
<li>Опциональные фильтры: <code>AND space_id = $N</code>, <code>AND created_by = $N</code>, <code>AND (title ILIKE '%' || $N || '%' OR description ILIKE '%' || $N || '%')</code></li>
|
||||
<li>Возвращать поле <code>space</code> (id, name, color) через JOIN</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h4 id="internaldtogantt"><code>internal/dto/gantt/</code></h4>
|
||||
<ul>
|
||||
<li>Новые DTO: <code>GanttChartListFilters</code>, <code>GanttChartWithSpaceResponse</code>, <code>GanttFiltersResponse</code></li>
|
||||
</ul>
|
||||
<p><strong>SQL (пример):</strong></p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">SELECT</span> gc.<span style="color:#f92672">*</span>, s.id <span style="color:#66d9ef">as</span> space_id, s.name <span style="color:#66d9ef">as</span> space_name, s.color <span style="color:#66d9ef">as</span> space_color,
|
||||
</span></span><span style="display:flex;"><span> u.display_name <span style="color:#66d9ef">as</span> created_by_name
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span> gantt_charts gc
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">JOIN</span> spaces s <span style="color:#66d9ef">ON</span> s.id <span style="color:#f92672">=</span> gc.space_id
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">JOIN</span> space_members sm <span style="color:#66d9ef">ON</span> sm.space_id <span style="color:#f92672">=</span> s.id
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">LEFT</span> <span style="color:#66d9ef">JOIN</span> users u <span style="color:#66d9ef">ON</span> u.id <span style="color:#f92672">=</span> gc.created_by
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">WHERE</span> sm.user_id <span style="color:#f92672">=</span> <span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">1</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">AND</span> sm.status <span style="color:#f92672">=</span> <span style="color:#e6db74">'accepted'</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">AND</span> (<span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">2</span>::uuid <span style="color:#66d9ef">IS</span> <span style="color:#66d9ef">NULL</span> <span style="color:#66d9ef">OR</span> gc.space_id <span style="color:#f92672">=</span> <span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">2</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">AND</span> (<span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">3</span>::uuid <span style="color:#66d9ef">IS</span> <span style="color:#66d9ef">NULL</span> <span style="color:#66d9ef">OR</span> gc.created_by <span style="color:#f92672">=</span> <span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">3</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">AND</span> (<span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">4</span>::text <span style="color:#66d9ef">IS</span> <span style="color:#66d9ef">NULL</span> <span style="color:#66d9ef">OR</span> gc.title <span style="color:#66d9ef">ILIKE</span> <span style="color:#e6db74">'%'</span> <span style="color:#f92672">||</span> <span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">4</span> <span style="color:#f92672">||</span> <span style="color:#e6db74">'%'</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">OR</span> gc.description <span style="color:#66d9ef">ILIKE</span> <span style="color:#e6db74">'%'</span> <span style="color:#f92672">||</span> <span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">4</span> <span style="color:#f92672">||</span> <span style="color:#e6db74">'%'</span>)
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">ORDER</span> <span style="color:#66d9ef">BY</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">CASE</span> <span style="color:#66d9ef">WHEN</span> <span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">5</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">'title'</span> <span style="color:#66d9ef">THEN</span> gc.title <span style="color:#66d9ef">END</span>,
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">CASE</span> <span style="color:#66d9ef">WHEN</span> <span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">5</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">'created_at'</span> <span style="color:#66d9ef">THEN</span> gc.created_at::text <span style="color:#66d9ef">END</span>,
|
||||
</span></span><span style="display:flex;"><span> gc.updated_at <span style="color:#66d9ef">DESC</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">LIMIT</span> <span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">6</span> <span style="color:#66d9ef">OFFSET</span> <span style="color:#960050;background-color:#1e0010">$</span><span style="color:#ae81ff">7</span>;
|
||||
</span></span></code></pre></div><hr>
|
||||
<h2 id="3-изменения-frontend-angular">3. Изменения Frontend (Angular)</h2>
|
||||
<h3 id="31-toolbar-фильтров">3.1. Toolbar фильтров</h3>
|
||||
<p>Добавить toolbar над списком диаграмм:</p>
|
||||
<pre tabindex="0"><code>┌──────────────────────────────────────────────────────────────────┐
|
||||
│ [🔍 Поиск... ] [▼ Пространство] │
|
||||
│ [▼ Создатель] [▼ Сортировка] [Сбросить фильтры] │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
</code></pre><p><strong>Компоненты:</strong></p>
|
||||
<ul>
|
||||
<li><strong>Строка поиска</strong> — input с debounce (300ms), поиск по назвению и описанию</li>
|
||||
<li><strong>Dropdown «Пространство»</strong> — список из <code>/gantt-charts/filters</code>, с цветовой меткой</li>
|
||||
<li><strong>Dropdown «Создатель»</strong> — список уникальных создателей</li>
|
||||
<li><strong>Dropdown «Сортировка»</strong> — по дате обновления, дате создания, названию</li>
|
||||
<li><strong>Кнопка «Сбросить»</strong> — очищает все фильтры</li>
|
||||
</ul>
|
||||
<p><strong>Состояние фильтров в URL</strong> (query params):</p>
|
||||
<pre tabindex="0"><code>/gantt?search=миграция&space_id=xxx&sort=updated_at
|
||||
</code></pre><p>Это позволяет делиться ссылкой с уже настроенными фильтрами.</p>
|
||||
<h3 id="32-карточка-диаграммы--бейдж-пространства">3.2. Карточка диаграммы — бейдж пространства</h3>
|
||||
<p>На каждой карточке добавить бейдж с названием пространства:</p>
|
||||
<pre tabindex="0"><code>┌─────────────────────────────────────┐
|
||||
│ 🟠 IT Ландшафт │ ← бейдж с цветом пространства
|
||||
│ Миграция backend │
|
||||
│ Перевод PHP→Go, этап 2 │
|
||||
│ Создал: Антон А. · 07.04.2026 │
|
||||
└─────────────────────────────────────┘
|
||||
</code></pre><h3 id="33-форма-создания-диаграммы--выбор-пространства">3.3. Форма создания диаграммы — выбор пространства</h3>
|
||||
<p>В модальном окне создания:</p>
|
||||
<ul>
|
||||
<li>Dropdown со списком пространств, где пользователь имеет роль <strong>editor</strong> или выше</li>
|
||||
<li>Валидация: если пользователь не editor ни в одном пространстве — показать сообщение «Нет доступных пространств для создания»</li>
|
||||
</ul>
|
||||
<p><strong>Запрос доступных пространств:</strong> переиспользовать существующий <code>GET /api/v1/spaces</code> с фильтрацией на клиенте по <code>role ∈ [owner, admin, editor]</code>, либо добавить параметр <code>?min_role=editor</code> на backend.</p>
|
||||
<h3 id="34-изменение-routing">3.4. Изменение routing</h3>
|
||||
<p><strong>Было:</strong></p>
|
||||
<pre tabindex="0"><code>/gantt → список гантов текущего пространства
|
||||
</code></pre><p><strong>Стало:</strong></p>
|
||||
<pre tabindex="0"><code>/gantt → список всех доступных гантов (из всех пространств)
|
||||
</code></pre><p>Убрать зависимость от <code>SpaceStorageService.getSelectedSpaceId()</code> в списке гантов.</p>
|
||||
<h3 id="35-frontend--файлы-для-изменения">3.5. Frontend — файлы для изменения</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Файл</th>
|
||||
<th>Изменение</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>pages/gantt/services/gantt.service.ts</code></td>
|
||||
<td>Новый метод <code>listAll(filters)</code>, <code>getFilters()</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>pages/gantt/gantt.component.ts</code></td>
|
||||
<td>Подключить toolbar, парсинг URL-параметров</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>pages/gantt/gantt.component.html</code></td>
|
||||
<td>Добавить toolbar, бейджи на карточках</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>pages/gantt/components/gantt-card/</code></td>
|
||||
<td>Добавить бейдж пространства</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>pages/gantt/components/create-chart-modal/</code></td>
|
||||
<td>Dropdown выбора пространства</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>core/models/</code></td>
|
||||
<td>Обновить модели: добавить <code>space</code> в GanttChart</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr>
|
||||
<h2 id="4-обратная-совместимость">4. Обратная совместимость</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Endpoint</th>
|
||||
<th>Статус</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>GET /api/v1/spaces/{id}/gantt-charts</code></td>
|
||||
<td>Сохранить (для детального view внутри пространства)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GET /api/v1/gantt-charts</code></td>
|
||||
<td><strong>Новый</strong> — глобальный список</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GET /api/v1/gantt-charts/filters</code></td>
|
||||
<td><strong>Новый</strong> — данные для dropdown’ов</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>POST /api/v1/spaces/{id}/gantt-charts</code></td>
|
||||
<td>Сохранить (создание в контексте пространства)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Все CRUD для sections/tasks</td>
|
||||
<td>Без изменений</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr>
|
||||
<h2 id="5-критерии-приёмки">5. Критерии приёмки</h2>
|
||||
<ul>
|
||||
<li><input disabled="" type="checkbox"> Endpoint <code>GET /api/v1/gantt-charts</code> возвращает все доступные диаграммы</li>
|
||||
<li><input disabled="" type="checkbox"> Фильтр по <code>space_id</code> — показывает только диаграммы конкретного пространства</li>
|
||||
<li><input disabled="" type="checkbox"> Фильтр по <code>created_by</code> — показывает только диаграммы выбранного создателя</li>
|
||||
<li><input disabled="" type="checkbox"> Поиск <code>search</code> — ищет по title и description (case-insensitive)</li>
|
||||
<li><input disabled="" type="checkbox"> Dropdown фильтров заполняется реальными данными из <code>/filters</code></li>
|
||||
<li><input disabled="" type="checkbox"> Карточка диаграммы показывает бейдж пространства с цветом</li>
|
||||
<li><input disabled="" type="checkbox"> Форма создания предлагает только пространства с ролью ≥ editor</li>
|
||||
<li><input disabled="" type="checkbox"> Состояние фильтров сохраняется в URL (можно поделиться ссылкой)</li>
|
||||
<li><input disabled="" type="checkbox"> Старые endpoints (<code>/spaces/{id}/gantt-charts</code>) продолжают работать</li>
|
||||
<li><input disabled="" type="checkbox"> Swagger документация обновлена</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<h2 id="6-порядок-реализации">6. Порядок реализации</h2>
|
||||
<ol>
|
||||
<li>Backend: DTO для новых запросов/ответов</li>
|
||||
<li>Backend: Repository — SQL-запрос с фильтрами + JOIN на spaces</li>
|
||||
<li>Backend: Service — <code>ListAll</code>, <code>GetFilters</code></li>
|
||||
<li>Backend: Handler — <code>ListAllGanttCharts</code>, <code>GetGanttFilters</code>, регистрация маршрутов</li>
|
||||
<li>Backend: Swagger — обновить документацию</li>
|
||||
<li>Frontend: Модели — обновить GanttChart, добавить Space в ответ</li>
|
||||
<li>Frontend: Service — <code>listAll()</code>, <code>getFilters()</code></li>
|
||||
<li>Frontend: Toolbar компонент — поиск + dropdown’ы</li>
|
||||
<li>Frontend: Карточка — бейдж пространства</li>
|
||||
<li>Frontend: Модальное окно создания — dropdown пространства</li>
|
||||
<li>Frontend: URL-параметры — синхронизация фильтров с router</li>
|
||||
<li>Тестирование</li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<p class="text-center mb-0">© 2026 docs.a2v.space</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/fuse.js@7.0.0/dist/fuse.min.js"></script>
|
||||
|
||||
|
||||
<script src="../../js/search.js"></script>
|
||||
<script src="../../js/creds.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user