web: remove sidebar items from sidebar class, add admin-interface

This commit is contained in:
Jens Langhammer 2020-12-02 13:56:26 +01:00
parent 832a3dda41
commit 821458373d
10 changed files with 186 additions and 153 deletions

View file

@ -3,7 +3,7 @@
{% load i18n %} {% load i18n %}
{% block body %} {% block body %}
<pb-messages url="{% url 'passbook_api:messages-list' %}"></pb-messages> <pb-messages></pb-messages>
<div class="pf-c-page"> <div class="pf-c-page">
<a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">{% trans 'Skip to content' %}</a> <a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">{% trans 'Skip to content' %}</a>
{% block page_content %} {% block page_content %}

View file

@ -1,10 +1,5 @@
{% extends "base/page.html" %} {% extends "base/skeleton.html" %}
{% block page_content %} {% block body %}
<pb-sidebar class="pf-c-page__sidebar"> <pb-interface-admin></pb-interface-admin>
</pb-sidebar>
<main class="pf-c-page__main">
<pb-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/library/">
</pb-router-outlet>
</main>
{% endblock %} {% endblock %}

View file

@ -1,5 +1,7 @@
import { DefaultClient, PBResponse } from "./client"; import { DefaultClient, PBResponse } from "./client";
let me: User;
export class User { export class User {
pk: number; pk: number;
username: string; username: string;
@ -13,7 +15,10 @@ export class User {
} }
static me(): Promise<User> { static me(): Promise<User> {
return DefaultClient.fetch<User>(["core", "users", "me"]); if (me) {
return Promise.resolve<User>(me);
}
return DefaultClient.fetch<User>(["core", "users", "me"]).then(u => me = u);
} }
static count(): Promise<number> { static count(): Promise<number> {

View file

@ -1,4 +1,5 @@
import { LitElement, html, customElement, property, TemplateResult } from "lit-element"; import { LitElement, html, customElement, TemplateResult } from "lit-element";
import { DefaultClient } from "../api/client";
const LEVEL_ICON_MAP: { [key: string]: string } = { const LEVEL_ICON_MAP: { [key: string]: string } = {
error: "fas fa-exclamation-circle", error: "fas fa-exclamation-circle",
@ -19,8 +20,7 @@ interface Message {
@customElement("pb-messages") @customElement("pb-messages")
export class Messages extends LitElement { export class Messages extends LitElement {
@property() url = DefaultClient.makeUrl(["root", "messages"]);
url = "";
messageSocket?: WebSocket; messageSocket?: WebSocket;
retryDelay = 200; retryDelay = 200;

View file

@ -6,136 +6,22 @@ import NavStyle from "@patternfly/patternfly/components/Nav/nav.css";
// @ts-ignore // @ts-ignore
import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css"; import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
import { User } from "../../api/user"; import { until } from "lit-html/directives/until";
export interface SidebarItem { export interface SidebarItem {
name: string; name: string;
path?: string[]; path?: string[];
children?: SidebarItem[]; children?: SidebarItem[];
condition?: (sb: Sidebar) => boolean; condition?: () => Promise<boolean>;
} }
export const SIDEBAR_ITEMS: SidebarItem[] = [
{
name: "Library",
path: ["/library/"],
},
{
name: "Monitor",
path: ["/audit/audit/"],
condition: (sb: Sidebar): boolean => {
return sb.user?.is_superuser || false;
},
},
{
name: "Administration",
children: [
{
name: "Overview",
path: ["/administration/overview-ng/"],
},
{
name: "System Tasks",
path: ["/administration/tasks/"],
},
{
name: "Applications",
path: ["/administration/applications/"],
},
{
name: "Sources",
path: ["/administration/sources/"],
},
{
name: "Providers",
path: ["/administration/providers/"],
},
{
name: "User Management",
children: [
{
name: "User",
path: ["/administration/users/"],
},
{
name: "Groups",
path: ["/administration/groups/"],
},
],
},
{
name: "Outposts",
children: [
{
name: "Outposts",
path: ["/administration/outposts/"],
},
{
name: "Service Connections",
path: ["/administration/outposts/service_connections/"],
},
],
},
{
name: "Policies",
children: [
{
name: "Policies",
path: ["/administration/policies/"],
},
{
name: "Bindings",
path: ["/administration/policies/bindings/"],
},
],
},
{
name: "Property Mappings",
path: ["/administration/property-mappings/"],
},
{
name: "Flows",
children: [
{
name: "Flows",
path: ["/administration/flows/"],
},
{
name: "Stages",
path: ["/administration/stages/"],
},
{
name: "Prompts",
path: ["/administration/stages/prompts/"],
},
{
name: "Invitations",
path: ["/administration/stages/invitations/"],
},
],
},
{
name: "Certificates",
path: ["/administration/crypto/certificates/"],
},
{
name: "Tokens",
path: ["/administration/tokens/"],
},
],
condition: (sb: Sidebar): boolean => {
return sb.user?.is_superuser || false;
},
},
];
@customElement("pb-sidebar") @customElement("pb-sidebar")
export class Sidebar extends LitElement { export class Sidebar extends LitElement {
@property() @property({attribute: false})
activePath: string; items: SidebarItem[] = [];
@property() @property()
user?: User; activePath: string;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [ return [
@ -145,7 +31,7 @@ export class Sidebar extends LitElement {
css` css`
.pf-c-nav__list .sidebar-brand { .pf-c-nav__list .sidebar-brand {
max-height: 82px; max-height: 82px;
margin-bottom: 0.5rem; margin-bottom: -0.5rem;
} }
.pf-c-nav__link { .pf-c-nav__link {
--pf-c-nav__link--PaddingTop: 0.5rem; --pf-c-nav__link--PaddingTop: 0.5rem;
@ -167,16 +53,15 @@ export class Sidebar extends LitElement {
constructor() { constructor() {
super(); super();
User.me().then((u) => (this.user = u));
this.activePath = window.location.hash.slice(1, Infinity); this.activePath = window.location.hash.slice(1, Infinity);
window.addEventListener("hashchange", () => { window.addEventListener("hashchange", () => {
this.activePath = window.location.hash.slice(1, Infinity); this.activePath = window.location.hash.slice(1, Infinity);
}); });
} }
renderItem(item: SidebarItem): TemplateResult { async renderItem(item: SidebarItem): Promise<TemplateResult> {
if (item.condition) { if (item.condition) {
const result = item.condition(this); const result = await item.condition();
if (!result) { if (!result) {
return html``; return html``;
} }
@ -194,7 +79,7 @@ export class Sidebar extends LitElement {
</a> </a>
<section class="pf-c-nav__subnav"> <section class="pf-c-nav__subnav">
<ul class="pf-c-nav__simple-list"> <ul class="pf-c-nav__simple-list">
${item.children?.map((i) => this.renderItem(i))} ${item.children?.map((i) => until(this.renderItem(i), html``))}
</ul> </ul>
</section>`} </section>`}
</li>`; </li>`;
@ -207,9 +92,9 @@ export class Sidebar extends LitElement {
<li class="pf-c-nav__item sidebar-brand"> <li class="pf-c-nav__item sidebar-brand">
<pb-sidebar-brand></pb-sidebar-brand> <pb-sidebar-brand></pb-sidebar-brand>
</li> </li>
${SIDEBAR_ITEMS.map((i) => this.renderItem(i))} ${this.items.map((i) => until(this.renderItem(i), html``))}
<li class="pf-c-nav__item pf-c-nav__item-bottom"> <li class="pf-c-nav__item pf-c-nav__item-bottom">
<pb-sidebar-user .user=${this.user}></pb-sidebar-user> <pb-sidebar-user></pb-sidebar-user>
</li> </li>
</ul> </ul>
</nav> </nav>

View file

@ -1,4 +1,4 @@
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; import { css, CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element";
// @ts-ignore // @ts-ignore
import NavStyle from "@patternfly/patternfly/components/Nav/nav.css"; import NavStyle from "@patternfly/patternfly/components/Nav/nav.css";
// @ts-ignore // @ts-ignore
@ -9,9 +9,6 @@ import { User } from "../../api/user";
@customElement("pb-sidebar-user") @customElement("pb-sidebar-user")
export class SidebarUser extends LitElement { export class SidebarUser extends LitElement {
@property()
user?: User;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [ return [
fa, fa,
@ -44,14 +41,12 @@ export class SidebarUser extends LitElement {
]; ];
} }
render(): TemplateResult { async render(): Promise<TemplateResult> {
if (!this.user) { const user = await User.me();
return html``;
}
return html` return html`
<a href="#/-/user/" class="pf-c-nav__link user-avatar" id="user-settings"> <a href="#/-/user/" class="pf-c-nav__link user-avatar" id="user-settings">
<img class="pf-c-avatar" src="${this.user?.avatar}" alt="" /> <img class="pf-c-avatar" src="${user.avatar}" alt="" />
<span>${this.user?.username}</span> <span>${user.username}</span>
</a> </a>
<a href="/flows/-/default/invalidation/" class="pf-c-nav__link user-logout" id="logout"> <a href="/flows/-/default/invalidation/" class="pf-c-nav__link user-logout" id="logout">
<i class="fas fa-sign-out-alt" aria-hidden="true"></i> <i class="fas fa-sign-out-alt" aria-hidden="true"></i>

View file

@ -0,0 +1,127 @@
import { customElement } from "lit-element";
import { User } from "../api/user";
import { SidebarItem } from "../elements/sidebar/Sidebar";
import { Interface } from "./Interface";
export const SIDEBAR_ITEMS: SidebarItem[] = [
{
name: "Library",
path: ["/library/"],
},
{
name: "Monitor",
path: ["/audit/audit/"],
condition: (): Promise<boolean> => {
return User.me().then(u => u.is_superuser);
},
},
{
name: "Administration",
children: [
{
name: "Overview",
path: ["/administration/overview-ng/"],
},
{
name: "System Tasks",
path: ["/administration/tasks/"],
},
{
name: "Applications",
path: ["/administration/applications/"],
},
{
name: "Sources",
path: ["/administration/sources/"],
},
{
name: "Providers",
path: ["/administration/providers/"],
},
{
name: "User Management",
children: [
{
name: "User",
path: ["/administration/users/"],
},
{
name: "Groups",
path: ["/administration/groups/"],
},
],
},
{
name: "Outposts",
children: [
{
name: "Outposts",
path: ["/administration/outposts/"],
},
{
name: "Service Connections",
path: ["/administration/outposts/service_connections/"],
},
],
},
{
name: "Policies",
children: [
{
name: "Policies",
path: ["/administration/policies/"],
},
{
name: "Bindings",
path: ["/administration/policies/bindings/"],
},
],
},
{
name: "Property Mappings",
path: ["/administration/property-mappings/"],
},
{
name: "Flows",
children: [
{
name: "Flows",
path: ["/administration/flows/"],
},
{
name: "Stages",
path: ["/administration/stages/"],
},
{
name: "Prompts",
path: ["/administration/stages/prompts/"],
},
{
name: "Invitations",
path: ["/administration/stages/invitations/"],
},
],
},
{
name: "Certificates",
path: ["/administration/crypto/certificates/"],
},
{
name: "Tokens",
path: ["/administration/tokens/"],
},
],
condition: (): Promise<boolean> => {
return User.me().then(u => u.is_superuser);
},
},
];
@customElement("pb-interface-admin")
export class AdminInterface extends Interface {
get sidebar(): SidebarItem[] {
return SIDEBAR_ITEMS;
}
}

View file

@ -0,0 +1,28 @@
import { gettext } from "django";
import { CSSResult, html, LitElement, TemplateResult } from "lit-element";
import { COMMON_STYLES } from "../common/styles";
import { SidebarItem } from "../elements/sidebar/Sidebar";
// @customElement("pb-interface")
export abstract class Interface extends LitElement {
abstract get sidebar(): SidebarItem[];
static get styles(): CSSResult[] {
return COMMON_STYLES;
}
render(): TemplateResult {
return html`<pb-messages></pb-messages>
<div class="pf-c-page">
<a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">${gettext("Skip to content")}</a>
<pb-sidebar class="pf-c-page__sidebar" .items=${this.sidebar}>
</pb-sidebar>
<main class="pf-c-page__main">
<pb-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/library/">
</pb-router-outlet>
</main>
</div>`;
}
}

View file

@ -30,3 +30,5 @@ import "./pages/admin-overview/TopApplicationsTable";
import "./pages/applications/ApplicationListPage"; import "./pages/applications/ApplicationListPage";
import "./pages/applications/ApplicationViewPage"; import "./pages/applications/ApplicationViewPage";
import "./pages/LibraryPage"; import "./pages/LibraryPage";
import "./interfaces/AdminInterface";

View file

@ -114,7 +114,3 @@ select[multiple] {
.pf-c-content h1 :first-child { .pf-c-content h1 :first-child {
margin-right: var(--pf-global--spacer--sm); margin-right: var(--pf-global--spacer--sm);
} }
.pf-c-empty-state {
height: 100vh;
}