feat(admin-ui): minimal React+Vite+TanStack scaffolding
- Vite 7 + React 19 + TanStack Router (file-based) + TanStack Query - Tailwind v4 (CSS-first config, OKLCH brand colors) - i18next + react-i18next с RU/EN switcher в header - Axios client с Accept-Language interceptor + JWT placeholder - 2 pages: /dictionaries (list cards) + /dictionaries/$name (records table) - Dockerfile (node build + nginx serving + API proxy) - README + .gitignore Backend: - Новый GET /api/v1/dictionaries в read-api (DictionaryListController), фильтрует по доступному scope через ScopeContext - DictionaryListItem DTO без heavy schema_json routeTree.gen.ts — stub; реальное содержимое генерится Vite plugin'ом при первом 'pnpm dev'.
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
||||
package cloud.nstart.terravault.ordinis.readapi.dto;
|
||||
|
||||
import cloud.nstart.terravault.ordinis.domain.DataScope;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Облегчённое представление справочника для list-эндпоинта (без schema_json,
|
||||
* чтобы не таскать тяжёлые JSON Schema на главную). Полная схема — отдельным
|
||||
* GET /api/v1/dictionaries/{name}.
|
||||
*/
|
||||
public record DictionaryListItem(
|
||||
UUID id,
|
||||
String name,
|
||||
String displayName,
|
||||
String description,
|
||||
DataScope scope,
|
||||
String schemaVersion,
|
||||
String bundle,
|
||||
List<String> supportedLocales,
|
||||
String defaultLocale,
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt) {}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package cloud.nstart.terravault.ordinis.readapi.web;
|
||||
|
||||
import cloud.nstart.terravault.ordinis.auth.ScopeContext;
|
||||
import cloud.nstart.terravault.ordinis.domain.DataScope;
|
||||
import cloud.nstart.terravault.ordinis.domain.definition.DictionaryDefinition;
|
||||
import cloud.nstart.terravault.ordinis.domain.definition.DictionaryDefinitionRepository;
|
||||
import cloud.nstart.terravault.ordinis.readapi.dto.DictionaryListItem;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* GET /api/v1/dictionaries — список доступных справочников. Фильтрация по
|
||||
* scope такая же, как для records: возвращаются только справочники со scope ⊆
|
||||
* текущим разрешённым scope клиенту.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/dictionaries")
|
||||
public class DictionaryListController {
|
||||
|
||||
private final DictionaryDefinitionRepository repository;
|
||||
private final ScopeContext scopeContext;
|
||||
|
||||
public DictionaryListController(
|
||||
DictionaryDefinitionRepository repository, ScopeContext scopeContext) {
|
||||
this.repository = repository;
|
||||
this.scopeContext = scopeContext;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<DictionaryListItem> list(
|
||||
@RequestParam(value = "as_scope", required = false) String asScope) {
|
||||
|
||||
Set<DataScope> scopes = scopeContext.resolveForRead(asScope);
|
||||
return repository.findAll().stream()
|
||||
.filter(d -> scopes.contains(d.getScope()))
|
||||
.map(DictionaryListController::toItem)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static DictionaryListItem toItem(DictionaryDefinition d) {
|
||||
return new DictionaryListItem(
|
||||
d.getId(),
|
||||
d.getName(),
|
||||
d.getDisplayName(),
|
||||
d.getDescription(),
|
||||
d.getScope(),
|
||||
d.getSchemaVersion(),
|
||||
d.getBundle(),
|
||||
d.getSupportedLocales() == null ? List.of() : List.of(d.getSupportedLocales()),
|
||||
d.getDefaultLocale(),
|
||||
d.getCreatedAt(),
|
||||
d.getUpdatedAt());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user