UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: витрина сервисов и таблицы Launcher

This commit is contained in:
DCCONSTRUCTIONS 2026-05-12 15:29:49 +03:00
parent b3915a851c
commit 06a6160a46
5 changed files with 86 additions and 64 deletions

View File

@ -1921,7 +1921,7 @@ function getAppsForUser(userGroups) {
hasAccess,
accessReason: hasAccess ? "Доступ подтверждён" : "Нет доступа",
};
}).filter((app) => app.hasAccess);
});
}
function getAppCatalog() {

View File

@ -171,16 +171,16 @@ export function LauncherApp() {
effectiveAccess: {
...service.effectiveAccess,
allowed: false,
visible: false,
visible: true,
openEnabled: false,
reason: "Нет доступа",
},
};
}
const appVisible = app.hasAccess && app.status !== "hidden" && app.status !== "disabled";
const allowed = appVisible && service.effectiveAccess.allowed;
const openEnabled = appVisible && app.status === "active" && service.effectiveAccess.openEnabled;
const appVisible = app.status !== "hidden" && app.status !== "disabled";
const allowed = app.hasAccess && appVisible && service.effectiveAccess.allowed;
const openEnabled = allowed && app.status === "active" && service.effectiveAccess.openEnabled;
return {
...service,
@ -191,7 +191,7 @@ export function LauncherApp() {
effectiveAccess: {
...service.effectiveAccess,
allowed,
visible: appVisible && service.effectiveAccess.visible,
visible: appVisible,
openEnabled,
reason: !app.hasAccess ? app.accessReason || "Нет доступа" : service.effectiveAccess.reason,
},

View File

@ -2259,15 +2259,20 @@ code {
background: var(--access-matrix-table-bg) !important;
}
.table-shell--users {
.table-shell--users,
.table-shell--sticky-user-column {
position: relative;
--admin-users-table-bg: rgb(20, 20, 22);
margin-top: 1rem;
padding: 0 0 1rem;
background: var(--admin-users-table-bg) !important;
}
.table-shell--users .table-toolbar {
.table-shell--users {
margin-top: 1rem;
}
.table-shell--users .table-toolbar,
.table-shell--sticky-user-column .table-toolbar {
position: sticky;
left: 0;
z-index: 6;
@ -2278,7 +2283,8 @@ code {
background: var(--admin-users-table-bg);
}
.table-shell--users .admin-data-table {
.table-shell--users .admin-data-table,
.table-shell--sticky-user-column .admin-data-table {
margin: 0;
}
@ -2288,12 +2294,16 @@ code {
}
.admin-data-table--users th,
.admin-data-table--users td {
.admin-data-table--users td,
.admin-data-table--sticky-user-column th,
.admin-data-table--sticky-user-column td {
white-space: nowrap;
}
.admin-data-table--users th:nth-child(1),
.admin-data-table--users td:nth-child(1) {
.admin-data-table--users td:nth-child(1),
.admin-data-table--sticky-user-column th:nth-child(1),
.admin-data-table--sticky-user-column td:nth-child(1) {
position: sticky;
left: 0;
z-index: 3;
@ -2302,7 +2312,8 @@ code {
background: var(--admin-users-table-bg);
}
.admin-data-table--users th:nth-child(1) {
.admin-data-table--users th:nth-child(1),
.admin-data-table--sticky-user-column th:nth-child(1) {
z-index: 4;
}
@ -2345,6 +2356,12 @@ code {
table-layout: fixed;
}
.admin-data-table--platform-users th:nth-child(1),
.admin-data-table--platform-users td:nth-child(1) {
width: 18rem;
min-width: 18rem;
}
.admin-data-table--platform-users th,
.admin-data-table--platform-users td {
white-space: nowrap;
@ -3682,7 +3699,7 @@ code {
}
.access-cell-menu {
min-width: 10.75rem;
min-width: 20rem;
}
.access-cell-menu .nodedc-ui-option[data-tone="green"][data-selected="true"] {

View File

@ -1040,7 +1040,7 @@ function PlatformUsersSection({
return (
<>
<GlassSurface className="table-shell table-shell--platform-users">
<GlassSurface className="table-shell table-shell--sticky-user-column table-shell--platform-users">
<div className="table-toolbar">
<div>
<h3>Пользователи платформы</h3>
@ -1049,7 +1049,7 @@ function PlatformUsersSection({
</p>
</div>
</div>
<table className="admin-data-table admin-data-table--platform-users">
<table className="admin-data-table admin-data-table--sticky-user-column admin-data-table--platform-users">
<thead>
<tr>
<th>Пользователь</th>
@ -1346,7 +1346,7 @@ const accessAssignmentOptions: Array<NodeDcSelectOption<AccessAssignmentValue>>
];
const publicOperationalCoreAccessOptions: Array<NodeDcSelectOption<AccessAssignmentValue>> = [
{ value: "unset", label: "—", description: "Не назначен" },
{ value: "unset", label: "—", description: "Не назначен", hidden: true },
{ value: "viewer", label: "Workspace Guest", description: "Доступ к приглашённому workspace", tone: "green" },
{ value: "member", label: "Workspace Member", description: "Доступ к приглашённому workspace", tone: "green" },
{ value: "admin", label: "Service Admin", description: "Self-service", tone: "green" },
@ -3196,7 +3196,7 @@ function MainStatusControl({
value={value}
options={mainStatusOptions}
label="MAIN статус"
minMenuWidth={172}
minMenuWidth={320}
menuClassName="access-cell-menu"
onChange={onChange}
trigger={({ open, toggle, setTriggerRef, selectedOption }) => (

View File

@ -53,6 +53,7 @@ export function TopBar({
description: client.legalName ?? undefined,
}));
const canOpenPlatform = me.launcherRole === "root_admin";
const showLauncherNavigation = me.permissions.canOpenAdmin || canOpenPlatform;
return (
<header className="nodedc-expanded-toolbar-shell">
@ -65,55 +66,59 @@ export function TopBar({
</div>
<div className="nodedc-expanded-toolbar-center">
<NodeDcSelect
value={activeClientId}
options={clientOptions}
label="Выбрать клиента"
searchable
minMenuWidth={248}
onChange={(clientId) => onClientChange(clientId)}
trigger={({ open, toggle, setTriggerRef }) => (
<button
ref={setTriggerRef}
className="nodedc-expanded-workspace-button"
title={activeClient?.name ?? "Клиент"}
type="button"
aria-label="Выбрать клиента"
aria-expanded={open}
onClick={toggle}
>
{activeClient?.avatarUrl ? <img src={activeClient.avatarUrl} alt="" className="nodedc-expanded-workspace-avatar" /> : null}
</button>
)}
/>
{showLauncherNavigation ? (
<>
<NodeDcSelect
value={activeClientId}
options={clientOptions}
label="Выбрать клиента"
searchable
minMenuWidth={248}
onChange={(clientId) => onClientChange(clientId)}
trigger={({ open, toggle, setTriggerRef }) => (
<button
ref={setTriggerRef}
className="nodedc-expanded-workspace-button"
title={activeClient?.name ?? "Клиент"}
type="button"
aria-label="Выбрать клиента"
aria-expanded={open}
onClick={toggle}
>
{activeClient?.avatarUrl ? <img src={activeClient.avatarUrl} alt="" className="nodedc-expanded-workspace-avatar" /> : null}
</button>
)}
/>
<nav className="nodedc-expanded-nav-group" aria-label="Навигация лаунчера">
<button className="nodedc-expanded-nav-button" type="button" data-active={!adminOpen} onClick={onOpenShowcase}>
<span>Витрина</span>
</button>
<nav className="nodedc-expanded-nav-group" aria-label="Навигация лаунчера">
<button className="nodedc-expanded-nav-button" type="button" data-active={!adminOpen} onClick={onOpenShowcase}>
<span>Витрина</span>
</button>
{me.permissions.canOpenAdmin ? (
<button
className="nodedc-expanded-nav-button"
type="button"
data-active={adminOpen && adminMode === "admin"}
onClick={onOpenAdmin}
>
<span>Администрирование</span>
</button>
) : null}
{me.permissions.canOpenAdmin ? (
<button
className="nodedc-expanded-nav-button"
type="button"
data-active={adminOpen && adminMode === "admin"}
onClick={onOpenAdmin}
>
<span>Администрирование</span>
</button>
) : null}
{canOpenPlatform ? (
<button
className="nodedc-expanded-nav-button"
type="button"
data-active={adminOpen && adminMode === "platform"}
onClick={onOpenPlatform}
>
<span>Платформа</span>
</button>
) : null}
</nav>
{canOpenPlatform ? (
<button
className="nodedc-expanded-nav-button"
type="button"
data-active={adminOpen && adminMode === "platform"}
onClick={onOpenPlatform}
>
<span>Платформа</span>
</button>
) : null}
</nav>
</>
) : null}
</div>
<div className="nodedc-expanded-toolbar-right">