import { DEFAULT_FORM_FIELD_TYPES, ADMIN_AUTH_REDIRECT_REASON_KEY, INVOICE_STATUS_LABELS, LS_TOKEN, OPERATOR_LABELS, ROLE_LABELS, SERVICE_REQUEST_STATUS_LABELS, SERVICE_REQUEST_TYPE_LABELS, STATUS_LABELS, STATUS_KIND_LABELS, TABLE_KEY_ALIASES, TABLE_MUTATION_CONFIG, TABLE_SERVER_CONFIG, TABLE_UNALIASES, PAGE_SIZE, } from "./admin/shared/constants.js"; import { createTableState } from "./admin/shared/state.js"; import { KanbanBoard } from "./admin/features/kanban/KanbanBoard.jsx"; import { ConfigSection } from "./admin/features/config/ConfigSection.jsx"; import { DashboardSection } from "./admin/features/dashboard/DashboardSection.jsx"; import { InvoicesSection } from "./admin/features/invoices/InvoicesSection.jsx"; import { RequestsSection } from "./admin/features/requests/RequestsSection.jsx"; import { QuotesSection } from "./admin/features/quotes/QuotesSection.jsx"; import { ServiceRequestsSection } from "./admin/features/service-requests/ServiceRequestsSection.jsx"; import { RequestWorkspace } from "./admin/features/requests/RequestWorkspace.jsx"; import { AvailableTablesSection } from "./admin/features/tables/AvailableTablesSection.jsx"; import { useAdminApi } from "./admin/hooks/useAdminApi.js"; import { useAdminCatalogLoaders } from "./admin/hooks/useAdminCatalogLoaders.js"; import { useKanban } from "./admin/hooks/useKanban.js"; import { useRequestWorkspace } from "./admin/hooks/useRequestWorkspace.js"; import { useTableActions } from "./admin/hooks/useTableActions.js"; import { useTableFilterActions } from "./admin/hooks/useTableFilterActions.js"; import { useTablesState } from "./admin/hooks/useTablesState.js"; import { avatarColor, boolFilterLabel, buildUniversalQuery, canAccessSection, decodeJwtPayload, detectAttachmentPreviewKind, fallbackStatusGroup, fmtAmount, fmtBytes, fmtDateOnly, fmtKanbanDate, fmtTimeOnly, getOperatorsForType, humanizeKey, localizeMeta, localizeRequestDetails, metaKindToFilterType, metaKindToRecordType, normalizeReferenceMeta, normalizeStringList, resolveAdminObjectSrc, resolveAdminRoute, resolveAvatarSrc, resolveDeadlineTone, roleLabel, sortByName, statusLabel, translateApiError, userInitials, } from "./admin/shared/utils.js"; import { AddIcon, DownloadIcon, FilterIcon, NextIcon, PrevIcon, RefreshIcon } from "./admin/shared/icons.jsx"; import QRCode from "qrcode"; (function () { const { useCallback, useEffect, useMemo, useRef, useState } = React; const LEGACY_HIDDEN_DICTIONARY_TABLES = new Set(["formFields", "topicRequiredFields", "statusTransitions"]); const NEW_REQUEST_CLIENT_OPTION = "__new_client__"; function StatusLine({ status }) { return

{status?.message || ""}

; } function Section({ active, children, id }) { return (
{children}
); } function DataTable({ headers, rows, emptyColspan, renderRow, onSort, sortClause }) { return (
{headers.map((header) => { const h = typeof header === "string" ? { key: header, label: header } : header; const sortable = Boolean(h.sortable && h.field && onSort); const active = Boolean(sortable && sortClause && sortClause.field === h.field); const direction = active ? sortClause.dir : ""; return ( ); })} {rows.length ? ( rows.map((row, index) => renderRow(row, index)) ) : ( )}
onSort(h.field) : undefined} title={sortable ? "Нажмите для сортировки" : undefined} > {h.label} {sortable ? {direction === "desc" ? "↓" : "↑"} : null}
Нет данных
); } function TablePager({ tableState, onPrev, onNext, onLoadAll, onRefresh, onCreate, onOpenFilter }) { return (
{tableState.showAll ? "Всего: " + tableState.total + " • показаны все записи" : "Всего: " + tableState.total + " • смещение: " + tableState.offset}
{onRefresh ? ( ) : null} {onCreate ? ( ) : null} {onOpenFilter ? ( ) : null}
); } function FilterToolbar({ filters, onOpen, onRemove, onEdit, getChipLabel, hideAction = false }) { return (
{filters.length ? ( filters.map((filter, index) => (
onEdit(index)} role="button" tabIndex={0} onKeyDown={(event) => { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); onEdit(index); } }} title="Редактировать фильтр" > {getChipLabel(filter)}
)) ) : ( Фильтры не заданы )}
{!hideAction ? (
) : null}
); } function Overlay({ open, onClose, children, id }) { return (
{children}
); } function IconButton({ icon, tooltip, onClick, tone, disabled = false }) { const handleClick = (event) => { if (disabled) { event.preventDefault(); event.stopPropagation(); return; } event.preventDefault(); event.stopPropagation(); if (event.nativeEvent && typeof event.nativeEvent.stopImmediatePropagation === "function") { event.nativeEvent.stopImmediatePropagation(); } if (typeof onClick === "function") onClick(event); }; const handleAuxClick = (event) => { event.preventDefault(); event.stopPropagation(); if (event.nativeEvent && typeof event.nativeEvent.stopImmediatePropagation === "function") { event.nativeEvent.stopImmediatePropagation(); } }; return ( ); } function UserAvatar({ name, email, avatarUrl, accessToken, size = 32 }) { const [broken, setBroken] = useState(false); useEffect(() => setBroken(false), [avatarUrl]); const initials = userInitials(name, email); const bg = avatarColor(name || email || initials); const src = resolveAvatarSrc(avatarUrl, accessToken, size); const canShowImage = Boolean(src && !broken); return ( {canShowImage ? ( {name= 64 ? "low" : "auto"} onError={() => setBroken(true)} /> ) : ( {initials} )} ); } function LoginScreen({ onSubmit, status }) { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [totpCode, setTotpCode] = useState(""); const submit = (event) => { event.preventDefault(); onSubmit(email, password, totpCode); }; return (

Вход в админ-панель

Используйте учетную запись администратора или юриста.

setEmail(event.target.value)} />
setPassword(event.target.value)} />
setTotpCode(event.target.value)} />
); } function FilterModal({ open, tableLabel, fields, draft, status, onClose, onFieldChange, onOpChange, onValueChange, onSubmit, onClear, getOperators, getFieldOptions, }) { if (!open) return null; const selectedField = fields.find((field) => field.field === draft.field) || fields[0] || null; const operators = getOperators(selectedField?.type || "text"); const options = selectedField ? getFieldOptions(selectedField) : []; return ( event.target.id === "filter-overlay" && onClose()}>
event.stopPropagation()}>

Фильтр таблицы

{tableLabel ? (draft.editIndex !== null ? "Редактирование фильтра • " : "Новый фильтр • ") + "Таблица: " + tableLabel : "Выберите поле, оператор и значение."}

{!selectedField || selectedField.type === "text" ? ( ) : selectedField.type === "number" ? ( ) : selectedField.type === "date" ? ( ) : selectedField.type === "boolean" ? ( ) : selectedField.type === "reference" || selectedField.type === "enum" ? ( ) : ( )}
); } function ReassignModal({ open, status, options, value, onChange, onClose, onSubmit, trackNumber }) { if (!open) return null; return ( event.target.id === "reassign-overlay" && onClose()}>
event.stopPropagation()}>

Переназначение заявки

{trackNumber ? "Заявка: " + trackNumber : "Выберите нового юриста"}

); } function KanbanSortModal({ open, value, status, onChange, onClose, onSubmit }) { if (!open) return null; return ( event.target.id === "kanban-sort-overlay" && onClose()}>
event.stopPropagation()}>

Сортировка канбана

Выберите способ сортировки карточек.

); } function TotpSetupModal({ open, status, secret, uri, qrDataUrl, code, loading, onCodeChange, onClose, onSubmit, onCopySecret, onCopyUri, }) { if (!open) return null; return ( event.target.id === "totp-setup-overlay" && onClose()}>
event.stopPropagation()}>

Настройка 2FA

Сканируйте QR-код в Google Authenticator и подтвердите 6-значным кодом.

{qrDataUrl ? ( QR-код для настройки 2FA ) : (

QR-код не удалось сгенерировать. Используйте ключ вручную.

)}