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, hasAccess,
accessReason: hasAccess ? "Доступ подтверждён" : "Нет доступа", accessReason: hasAccess ? "Доступ подтверждён" : "Нет доступа",
}; };
}).filter((app) => app.hasAccess); });
} }
function getAppCatalog() { function getAppCatalog() {

View File

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

View File

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

View File

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

View File

@ -53,6 +53,7 @@ export function TopBar({
description: client.legalName ?? undefined, description: client.legalName ?? undefined,
})); }));
const canOpenPlatform = me.launcherRole === "root_admin"; const canOpenPlatform = me.launcherRole === "root_admin";
const showLauncherNavigation = me.permissions.canOpenAdmin || canOpenPlatform;
return ( return (
<header className="nodedc-expanded-toolbar-shell"> <header className="nodedc-expanded-toolbar-shell">
@ -65,6 +66,8 @@ export function TopBar({
</div> </div>
<div className="nodedc-expanded-toolbar-center"> <div className="nodedc-expanded-toolbar-center">
{showLauncherNavigation ? (
<>
<NodeDcSelect <NodeDcSelect
value={activeClientId} value={activeClientId}
options={clientOptions} options={clientOptions}
@ -114,6 +117,8 @@ export function TopBar({
</button> </button>
) : null} ) : null}
</nav> </nav>
</>
) : null}
</div> </div>
<div className="nodedc-expanded-toolbar-right"> <div className="nodedc-expanded-toolbar-right">