web: update to new formatting rules, make eslint warnings fail ci
This commit is contained in:
parent
7195b77606
commit
e6391b64f0
|
@ -25,7 +25,7 @@ class ChannelsStorage(FallbackStorage):
|
||||||
uid,
|
uid,
|
||||||
{
|
{
|
||||||
"type": "event.update",
|
"type": "event.update",
|
||||||
"levelTag": message.level_tag,
|
"level_tag": message.level_tag,
|
||||||
"tags": message.tags,
|
"tags": message.tags,
|
||||||
"message": message.message,
|
"message": message.message,
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rollup -c ./rollup.config.js",
|
"build": "rollup -c ./rollup.config.js",
|
||||||
"watch": "rollup -c -w",
|
"watch": "rollup -c -w",
|
||||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
|
"lint": "eslint . --max-warnings 0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.15.1",
|
"@fortawesome/fontawesome-free": "^5.15.1",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { DefaultClient, PBResponse } from "./client";
|
import { DefaultClient, PBResponse, QueryArguments } from "./client";
|
||||||
|
|
||||||
export class Application {
|
export class Application {
|
||||||
pk: string;
|
pk: string;
|
||||||
|
@ -21,7 +21,7 @@ export class Application {
|
||||||
return DefaultClient.fetch<Application>(["core", "applications", slug]);
|
return DefaultClient.fetch<Application>(["core", "applications", slug]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static list(filter?: { [key: string]: any }): Promise<PBResponse<Application>> {
|
static list(filter?: QueryArguments): Promise<PBResponse<Application>> {
|
||||||
return DefaultClient.fetch<PBResponse<Application>>(["core", "applications"], filter);
|
return DefaultClient.fetch<PBResponse<Application>>(["core", "applications"], filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,12 @@ import { NotFoundError, RequestError } from "./errors";
|
||||||
|
|
||||||
export const VERSION = "v2beta";
|
export const VERSION = "v2beta";
|
||||||
|
|
||||||
|
export interface QueryArguments {
|
||||||
|
[key: string]: number | string | boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export class Client {
|
export class Client {
|
||||||
makeUrl(url: string[], query?: { [key: string]: string }): string {
|
makeUrl(url: string[], query?: QueryArguments): string {
|
||||||
let builtUrl = `/api/${VERSION}/${url.join("/")}/`;
|
let builtUrl = `/api/${VERSION}/${url.join("/")}/`;
|
||||||
if (query) {
|
if (query) {
|
||||||
const queryString = Object.keys(query)
|
const queryString = Object.keys(query)
|
||||||
|
@ -14,7 +18,7 @@ export class Client {
|
||||||
return builtUrl;
|
return builtUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch<T>(url: string[], query?: { [key: string]: any }): Promise<T> {
|
fetch<T>(url: string[], query?: QueryArguments): Promise<T> {
|
||||||
const finalUrl = this.makeUrl(url, query);
|
const finalUrl = this.makeUrl(url, query);
|
||||||
return fetch(finalUrl)
|
return fetch(finalUrl)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export interface Policy {
|
export interface Policy {
|
||||||
pk: string;
|
pk: string;
|
||||||
name: string;
|
name: string;
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PolicyBinding {
|
export interface PolicyBinding {
|
||||||
|
|
|
@ -6,5 +6,6 @@ import PFAddons from "@patternfly/patternfly/patternfly-addons.css";
|
||||||
import FA from "@fortawesome/fontawesome-free/css/fontawesome.css";
|
import FA from "@fortawesome/fontawesome-free/css/fontawesome.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import PBGlobal from "../passbook.css";
|
import PBGlobal from "../passbook.css";
|
||||||
|
import { CSSResult } from "lit-element";
|
||||||
|
|
||||||
export const COMMON_STYLES = [PF, PFAddons, FA, PBGlobal];
|
export const COMMON_STYLES: CSSResult[] = [PF, PFAddons, FA, PBGlobal];
|
||||||
|
|
2
web/src/django.d.ts
vendored
2
web/src/django.d.ts
vendored
|
@ -6,5 +6,5 @@ declare namespace django {
|
||||||
function ngettext(singular: string, plural: string, count: number): string;
|
function ngettext(singular: string, plural: string, count: number): string;
|
||||||
function gettext_noop(msgid: string): string;
|
function gettext_noop(msgid: string): string;
|
||||||
function pgettext(context: string, msgid: string): string;
|
function pgettext(context: string, msgid: string): string;
|
||||||
function interpolate(fmt: string, obj: any, named: boolean): string;
|
function interpolate(fmt: string, obj: unknown, named: boolean): string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
import Chart from "chart.js";
|
import Chart from "chart.js";
|
||||||
|
|
||||||
interface TickValue {
|
interface TickValue {
|
||||||
|
@ -11,10 +11,10 @@ export class AdminLoginsChart extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
url = "";
|
url = "";
|
||||||
|
|
||||||
chart: any;
|
chart?: Chart;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return css`
|
return [css`
|
||||||
:host {
|
:host {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -26,7 +26,7 @@ export class AdminLoginsChart extends LitElement {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
}
|
}
|
||||||
`;
|
`];
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -38,14 +38,21 @@ export class AdminLoginsChart extends LitElement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated(): void {
|
||||||
fetch(this.url)
|
fetch(this.url)
|
||||||
.then((r) => r.json())
|
.then((r) => r.json())
|
||||||
.catch((e) => console.error(e))
|
.catch((e) => console.error(e))
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
const ctx = (<HTMLCanvasElement>this.shadowRoot?.querySelector("canvas")).getContext(
|
const canvas = <HTMLCanvasElement>this.shadowRoot?.querySelector("canvas");
|
||||||
"2d"
|
if (!canvas) {
|
||||||
)!;
|
console.warn("Failed to get canvas element");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
if (!ctx) {
|
||||||
|
console.warn("failed to get 2d context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
this.chart = new Chart(ctx, {
|
this.chart = new Chart(ctx, {
|
||||||
type: "bar",
|
type: "bar",
|
||||||
data: {
|
data: {
|
||||||
|
@ -102,7 +109,7 @@ export class AdminLoginsChart extends LitElement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html`<canvas></canvas>`;
|
return html`<canvas></canvas>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { customElement, html, LitElement, property } from "lit-element";
|
import { customElement, LitElement, property } from "lit-element";
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import CodeMirror from "codemirror";
|
import CodeMirror from "codemirror";
|
||||||
|
@ -17,11 +17,11 @@ export class CodeMirrorTextarea extends LitElement {
|
||||||
|
|
||||||
editor?: CodeMirror.EditorFromTextArea;
|
editor?: CodeMirror.EditorFromTextArea;
|
||||||
|
|
||||||
createRenderRoot() {
|
createRenderRoot() : ShadowRoot | Element {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated(): void {
|
||||||
const textarea = this.querySelector("textarea");
|
const textarea = this.querySelector("textarea");
|
||||||
if (!textarea) {
|
if (!textarea) {
|
||||||
return;
|
return;
|
||||||
|
@ -33,7 +33,7 @@ export class CodeMirrorTextarea extends LitElement {
|
||||||
readOnly: this.readOnly,
|
readOnly: this.readOnly,
|
||||||
autoRefresh: true,
|
autoRefresh: true,
|
||||||
});
|
});
|
||||||
this.editor.on("blur", (e) => {
|
this.editor.on("blur", () => {
|
||||||
this.editor?.save();
|
this.editor?.save();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
import { LitElement, html, customElement, property } from "lit-element";
|
|
||||||
|
|
||||||
interface ComparisonHash {
|
|
||||||
[key: string]: (a: any, b: any) => boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("fetch-fill-slot")
|
|
||||||
export class FetchFillSlot extends LitElement {
|
|
||||||
@property()
|
|
||||||
url = "";
|
|
||||||
|
|
||||||
@property()
|
|
||||||
key = "";
|
|
||||||
|
|
||||||
@property()
|
|
||||||
value = "";
|
|
||||||
|
|
||||||
comparison(slotName: string) {
|
|
||||||
const comparisonOperatorsHash = <ComparisonHash>{
|
|
||||||
"<": function (a: any, b: any) {
|
|
||||||
return a < b;
|
|
||||||
},
|
|
||||||
">": function (a: any, b: any) {
|
|
||||||
return a > b;
|
|
||||||
},
|
|
||||||
">=": function (a: any, b: any) {
|
|
||||||
return a >= b;
|
|
||||||
},
|
|
||||||
"<=": function (a: any, b: any) {
|
|
||||||
return a <= b;
|
|
||||||
},
|
|
||||||
"==": function (a: any, b: any) {
|
|
||||||
return a == b;
|
|
||||||
},
|
|
||||||
"!=": function (a: any, b: any) {
|
|
||||||
return a != b;
|
|
||||||
},
|
|
||||||
"===": function (a: any, b: any) {
|
|
||||||
return a === b;
|
|
||||||
},
|
|
||||||
"!==": function (a: any, b: any) {
|
|
||||||
return a !== b;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const tokens = slotName.split(" ");
|
|
||||||
if (tokens.length < 3) {
|
|
||||||
throw new Error("nah");
|
|
||||||
}
|
|
||||||
let a: any = tokens[0];
|
|
||||||
if (a === "value") {
|
|
||||||
a = this.value;
|
|
||||||
} else {
|
|
||||||
a = parseInt(a, 10);
|
|
||||||
}
|
|
||||||
let b: any = tokens[2];
|
|
||||||
if (b === "value") {
|
|
||||||
b = this.value;
|
|
||||||
} else {
|
|
||||||
b = parseInt(b, 10);
|
|
||||||
}
|
|
||||||
const comp = tokens[1];
|
|
||||||
if (!(comp in comparisonOperatorsHash)) {
|
|
||||||
throw new Error("Invalid comparison");
|
|
||||||
}
|
|
||||||
return comparisonOperatorsHash[comp](a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
fetch(this.url)
|
|
||||||
.then((r) => r.json())
|
|
||||||
.then((r) => r[this.key])
|
|
||||||
.then((r) => (this.value = r));
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (this.value === undefined) {
|
|
||||||
return html`<slot></slot>`;
|
|
||||||
}
|
|
||||||
let selectedSlot = "";
|
|
||||||
this.querySelectorAll("[slot]").forEach((slot) => {
|
|
||||||
const comp = slot.getAttribute("slot")!;
|
|
||||||
if (this.comparison(comp)) {
|
|
||||||
selectedSlot = comp;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.querySelectorAll("[data-value]").forEach((dv) => {
|
|
||||||
dv.textContent = this.value;
|
|
||||||
});
|
|
||||||
return html`<slot name=${selectedSlot}></slot>`;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { LitElement, html, customElement, property } from "lit-element";
|
import { LitElement, html, customElement, property, TemplateResult } from "lit-element";
|
||||||
|
|
||||||
const LEVEL_ICON_MAP: { [key: string]: string } = {
|
const LEVEL_ICON_MAP: { [key: string]: string } = {
|
||||||
error: "fas fa-exclamation-circle",
|
error: "fas fa-exclamation-circle",
|
||||||
|
@ -12,7 +12,7 @@ const ID = function (prefix: string) {
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Message {
|
interface Message {
|
||||||
levelTag: string;
|
level_tag: string;
|
||||||
tags: string;
|
tags: string;
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ export class Messages extends LitElement {
|
||||||
messageSocket?: WebSocket;
|
messageSocket?: WebSocket;
|
||||||
retryDelay = 200;
|
retryDelay = 200;
|
||||||
|
|
||||||
createRenderRoot() {
|
createRenderRoot(): ShadowRoot | Element {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,16 +38,16 @@ export class Messages extends LitElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated(): void {
|
||||||
this.fetchMessages();
|
this.fetchMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
connect() {
|
connect(): void {
|
||||||
const wsUrl = `${window.location.protocol.replace("http", "ws")}//${
|
const wsUrl = `${window.location.protocol.replace("http", "ws")}//${
|
||||||
window.location.host
|
window.location.host
|
||||||
}/ws/client/`;
|
}/ws/client/`;
|
||||||
this.messageSocket = new WebSocket(wsUrl);
|
this.messageSocket = new WebSocket(wsUrl);
|
||||||
this.messageSocket.addEventListener("open", (e) => {
|
this.messageSocket.addEventListener("open", () => {
|
||||||
console.debug(`passbook/messages: connected to ${wsUrl}`);
|
console.debug(`passbook/messages: connected to ${wsUrl}`);
|
||||||
});
|
});
|
||||||
this.messageSocket.addEventListener("close", (e) => {
|
this.messageSocket.addEventListener("close", (e) => {
|
||||||
|
@ -71,32 +71,29 @@ export class Messages extends LitElement {
|
||||||
/* Fetch messages which were stored in the session.
|
/* Fetch messages which were stored in the session.
|
||||||
* This mostly gets messages which were created when the user arrives/leaves the site
|
* This mostly gets messages which were created when the user arrives/leaves the site
|
||||||
* and especially the login flow */
|
* and especially the login flow */
|
||||||
fetchMessages() {
|
fetchMessages(): Promise<void> {
|
||||||
console.debug("passbook/messages: fetching messages over direct api");
|
console.debug("passbook/messages: fetching messages over direct api");
|
||||||
return fetch(this.url)
|
return fetch(this.url)
|
||||||
.then((r) => r.json())
|
.then((r) => r.json())
|
||||||
.then((r) => {
|
.then((r: Message[]) => {
|
||||||
r.forEach((m: any) => {
|
r.forEach((m: Message) => {
|
||||||
const message = <Message>{
|
this.renderMessage(m);
|
||||||
levelTag: m.level_tag,
|
|
||||||
tags: m.tags,
|
|
||||||
message: m.message,
|
|
||||||
};
|
|
||||||
this.renderMessage(message);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderMessage(message: Message) {
|
renderMessage(message: Message): void {
|
||||||
const container = <HTMLElement>this.querySelector(".pf-c-alert-group")!;
|
const container = <HTMLElement>this.querySelector(".pf-c-alert-group");
|
||||||
|
if (!container) {
|
||||||
|
console.warn("passbook/messages: failed to find container");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const id = ID("pb-message");
|
const id = ID("pb-message");
|
||||||
const el = document.createElement("template");
|
const el = document.createElement("template");
|
||||||
el.innerHTML = `<li id=${id} class="pf-c-alert-group__item">
|
el.innerHTML = `<li id=${id} class="pf-c-alert-group__item">
|
||||||
<div class="pf-c-alert pf-m-${message.levelTag} ${
|
<div class="pf-c-alert pf-m-${message.level_tag} ${message.level_tag === "error" ? "pf-m-danger" : ""}">
|
||||||
message.levelTag === "error" ? "pf-m-danger" : ""
|
|
||||||
}">
|
|
||||||
<div class="pf-c-alert__icon">
|
<div class="pf-c-alert__icon">
|
||||||
<i class="${LEVEL_ICON_MAP[message.levelTag]}"></i>
|
<i class="${LEVEL_ICON_MAP[message.level_tag]}"></i>
|
||||||
</div>
|
</div>
|
||||||
<p class="pf-c-alert__title">
|
<p class="pf-c-alert__title">
|
||||||
${message.message}
|
${message.message}
|
||||||
|
@ -106,10 +103,10 @@ export class Messages extends LitElement {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.querySelector(`#${id}`)?.remove();
|
this.querySelector(`#${id}`)?.remove();
|
||||||
}, 1500);
|
}, 1500);
|
||||||
container.appendChild(el.content.firstChild!);
|
container.appendChild(el.content.firstChild!); // eslint-disable-line
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html`<ul class="pf-c-alert-group pf-m-toast"></ul>`;
|
return html`<ul class="pf-c-alert-group pf-m-toast"></ul>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { gettext } from "django";
|
import { gettext } from "django";
|
||||||
import { customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import SpinnerStyle from "@patternfly/patternfly/components/Spinner/spinner.css";
|
import SpinnerStyle from "@patternfly/patternfly/components/Spinner/spinner.css";
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ export class Spinner extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
size: SpinnerSize = SpinnerSize.Medium;
|
size: SpinnerSize = SpinnerSize.Medium;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [SpinnerStyle];
|
return [SpinnerStyle];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { LitElement, html, customElement, property } from "lit-element";
|
import { LitElement, html, customElement, property, CSSResult, TemplateResult } from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import TabsStyle from "@patternfly/patternfly/components/Tabs/tabs.css";
|
import TabsStyle from "@patternfly/patternfly/components/Tabs/tabs.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -10,12 +10,23 @@ export class Tabs extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
currentPage?: string;
|
currentPage?: string;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [GlobalsStyle, TabsStyle];
|
return [GlobalsStyle, TabsStyle];
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderTab(page: Element): TemplateResult {
|
||||||
const pages = Array.from(this.querySelectorAll("[slot]")!);
|
const slot = page.attributes.getNamedItem("slot")?.value;
|
||||||
|
return html` <li class="pf-c-tabs__item ${slot === this.currentPage ? CURRENT_CLASS : ""}">
|
||||||
|
<button class="pf-c-tabs__link" @click=${() => { this.currentPage = slot; }}>
|
||||||
|
<span class="pf-c-tabs__item-text">
|
||||||
|
${page.attributes.getNamedItem("tab-title")?.value}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</li>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
const pages = Array.from(this.querySelectorAll("[slot]"));
|
||||||
if (!this.currentPage) {
|
if (!this.currentPage) {
|
||||||
if (pages.length < 1) {
|
if (pages.length < 1) {
|
||||||
return html`<h1>no tabs defined</h1>`;
|
return html`<h1>no tabs defined</h1>`;
|
||||||
|
@ -24,25 +35,7 @@ export class Tabs extends LitElement {
|
||||||
}
|
}
|
||||||
return html`<div class="pf-c-tabs">
|
return html`<div class="pf-c-tabs">
|
||||||
<ul class="pf-c-tabs__list">
|
<ul class="pf-c-tabs__list">
|
||||||
${pages.map((page) => {
|
${pages.map((page) => this.renderTab(page))}
|
||||||
const slot = page.attributes.getNamedItem("slot")?.value;
|
|
||||||
return html` <li
|
|
||||||
class="pf-c-tabs__item ${slot === this.currentPage
|
|
||||||
? CURRENT_CLASS
|
|
||||||
: ""}"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="pf-c-tabs__link"
|
|
||||||
@click=${() => {
|
|
||||||
this.currentPage = slot;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span class="pf-c-tabs__item-text">
|
|
||||||
${page.attributes.getNamedItem("tab-title")?.value}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</li>`;
|
|
||||||
})}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<slot name="${this.currentPage}"></slot>`;
|
<slot name="${this.currentPage}"></slot>`;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { getCookie } from "../../utils";
|
import { getCookie } from "../../utils";
|
||||||
import { customElement, html, property } from "lit-element";
|
import { customElement, property } from "lit-element";
|
||||||
import { ERROR_CLASS, SUCCESS_CLASS } from "../../constants";
|
import { ERROR_CLASS, SUCCESS_CLASS } from "../../constants";
|
||||||
import { SpinnerButton } from "./SpinnerButton";
|
import { SpinnerButton } from "./SpinnerButton";
|
||||||
|
|
||||||
|
@ -8,21 +8,26 @@ export class ActionButton extends SpinnerButton {
|
||||||
@property()
|
@property()
|
||||||
url = "";
|
url = "";
|
||||||
|
|
||||||
callAction() {
|
callAction(): void {
|
||||||
if (this.isRunning === true) {
|
if (this.isRunning === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setLoading();
|
this.setLoading();
|
||||||
const csrftoken = getCookie("passbook_csrf");
|
const csrftoken = getCookie("passbook_csrf");
|
||||||
|
if (!csrftoken) {
|
||||||
|
console.debug("No csrf token in cookie");
|
||||||
|
this.setDone(ERROR_CLASS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const request = new Request(this.url, {
|
const request = new Request(this.url, {
|
||||||
headers: { "X-CSRFToken": csrftoken! },
|
headers: { "X-CSRFToken": csrftoken },
|
||||||
});
|
});
|
||||||
fetch(request, {
|
fetch(request, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
mode: "same-origin",
|
mode: "same-origin",
|
||||||
})
|
})
|
||||||
.then((r) => r.json())
|
.then((r) => r.json())
|
||||||
.then((r) => {
|
.then(() => {
|
||||||
this.setDone(SUCCESS_CLASS);
|
this.setDone(SUCCESS_CLASS);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { customElement, html, LitElement } from "lit-element";
|
import { customElement, html, LitElement, TemplateResult } from "lit-element";
|
||||||
|
|
||||||
@customElement("pb-dropdown")
|
@customElement("pb-dropdown")
|
||||||
export class DropdownButton extends LitElement {
|
export class DropdownButton extends LitElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
const menu = <HTMLElement>this.querySelector(".pf-c-dropdown__menu")!;
|
const menu = <HTMLElement>this.querySelector(".pf-c-dropdown__menu");
|
||||||
this.querySelectorAll("button.pf-c-dropdown__toggle").forEach((btn) => {
|
this.querySelectorAll("button.pf-c-dropdown__toggle").forEach((btn) => {
|
||||||
btn.addEventListener("click", (e) => {
|
btn.addEventListener("click", () => {
|
||||||
menu.hidden = !menu.hidden;
|
menu.hidden = !menu.hidden;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html`<slot></slot>`;
|
return html`<slot></slot>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import ModalBoxStyle from "@patternfly/patternfly/components/ModalBox/modal-box.css";
|
import ModalBoxStyle from "@patternfly/patternfly/components/ModalBox/modal-box.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -22,7 +22,7 @@ export class ModalButton extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
open = false;
|
open = false;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
|
@ -49,7 +49,7 @@ export class ModalButton extends LitElement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHandlers() {
|
updateHandlers(): void {
|
||||||
// Ensure links close the modal
|
// Ensure links close the modal
|
||||||
this.querySelectorAll<HTMLAnchorElement>("[slot=modal] a").forEach((a) => {
|
this.querySelectorAll<HTMLAnchorElement>("[slot=modal] a").forEach((a) => {
|
||||||
if (a.target == "_blank") {
|
if (a.target == "_blank") {
|
||||||
|
@ -63,7 +63,7 @@ export class ModalButton extends LitElement {
|
||||||
});
|
});
|
||||||
// Make name field update slug field
|
// Make name field update slug field
|
||||||
this.querySelectorAll<HTMLInputElement>("input[name=name]").forEach((input) => {
|
this.querySelectorAll<HTMLInputElement>("input[name=name]").forEach((input) => {
|
||||||
input.addEventListener("input", (e) => {
|
input.addEventListener("input", () => {
|
||||||
const form = input.closest("form");
|
const form = input.closest("form");
|
||||||
if (form === null) {
|
if (form === null) {
|
||||||
return;
|
return;
|
||||||
|
@ -90,7 +90,12 @@ export class ModalButton extends LitElement {
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.indexOf("csrfmiddlewaretoken") !== -1) {
|
if (data.indexOf("csrfmiddlewaretoken") !== -1) {
|
||||||
this.querySelector("[slot=modal]")!.innerHTML = data;
|
const modalSlot = this.querySelector("[slot=modal]");
|
||||||
|
if (!modalSlot) {
|
||||||
|
console.debug("passbook/modalbutton: modal slot not found?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modalSlot.innerHTML = data;
|
||||||
console.debug("passbook/modalbutton: re-showing form");
|
console.debug("passbook/modalbutton: re-showing form");
|
||||||
this.updateHandlers();
|
this.updateHandlers();
|
||||||
} else {
|
} else {
|
||||||
|
@ -110,7 +115,7 @@ export class ModalButton extends LitElement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick(e: MouseEvent) {
|
onClick(): void {
|
||||||
if (!this.href) {
|
if (!this.href) {
|
||||||
this.updateHandlers();
|
this.updateHandlers();
|
||||||
this.open = true;
|
this.open = true;
|
||||||
|
@ -121,7 +126,11 @@ export class ModalButton extends LitElement {
|
||||||
})
|
})
|
||||||
.then((r) => r.text())
|
.then((r) => r.text())
|
||||||
.then((t) => {
|
.then((t) => {
|
||||||
this.querySelector("[slot=modal]")!.innerHTML = t;
|
const modalSlot = this.querySelector("[slot=modal]");
|
||||||
|
if (!modalSlot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modalSlot.innerHTML = t;
|
||||||
this.updateHandlers();
|
this.updateHandlers();
|
||||||
this.open = true;
|
this.open = true;
|
||||||
this.querySelectorAll<SpinnerButton>("pb-spinner-button").forEach((sb) => {
|
this.querySelectorAll<SpinnerButton>("pb-spinner-button").forEach((sb) => {
|
||||||
|
@ -134,7 +143,7 @@ export class ModalButton extends LitElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderModal() {
|
renderModal(): TemplateResult {
|
||||||
return html`<div class="pf-c-backdrop">
|
return html`<div class="pf-c-backdrop">
|
||||||
<div class="pf-l-bullseye">
|
<div class="pf-l-bullseye">
|
||||||
<div
|
<div
|
||||||
|
@ -158,8 +167,8 @@ export class ModalButton extends LitElement {
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html` <slot name="trigger" @click=${(e: any) => this.onClick(e)}></slot>
|
return html` <slot name="trigger" @click=${() => this.onClick()}></slot>
|
||||||
${this.open ? this.renderModal() : ""}`;
|
${this.open ? this.renderModal() : ""}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
|
import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -15,7 +15,7 @@ export class SpinnerButton extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
form?: string;
|
form?: string;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
GlobalsStyle,
|
GlobalsStyle,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
|
@ -35,13 +35,13 @@ export class SpinnerButton extends LitElement {
|
||||||
this.classList.add(PRIMARY_CLASS);
|
this.classList.add(PRIMARY_CLASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading() {
|
setLoading(): void {
|
||||||
this.isRunning = true;
|
this.isRunning = true;
|
||||||
this.classList.add(PROGRESS_CLASS);
|
this.classList.add(PROGRESS_CLASS);
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
setDone(statusClass: string) {
|
setDone(statusClass: string): void {
|
||||||
this.isRunning = false;
|
this.isRunning = false;
|
||||||
this.classList.remove(PROGRESS_CLASS);
|
this.classList.remove(PROGRESS_CLASS);
|
||||||
this.classList.replace(PRIMARY_CLASS, statusClass);
|
this.classList.replace(PRIMARY_CLASS, statusClass);
|
||||||
|
@ -52,7 +52,7 @@ export class SpinnerButton extends LitElement {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
callAction() {
|
callAction(): void {
|
||||||
if (this.isRunning === true) {
|
if (this.isRunning === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ export class SpinnerButton extends LitElement {
|
||||||
this.setLoading();
|
this.setLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html`<button
|
return html`<button
|
||||||
class="pf-c-button pf-m-progress ${this.classList.toString()}"
|
class="pf-c-button pf-m-progress ${this.classList.toString()}"
|
||||||
@click=${() => this.callAction()}
|
@click=${() => this.callAction()}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
|
import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -14,7 +14,7 @@ export class TokenCopyButton extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
buttonClass: string = PRIMARY_CLASS;
|
buttonClass: string = PRIMARY_CLASS;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
GlobalsStyle,
|
GlobalsStyle,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
|
@ -27,7 +27,7 @@ export class TokenCopyButton extends LitElement {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick() {
|
onClick(): void {
|
||||||
if (!this.identifier) {
|
if (!this.identifier) {
|
||||||
this.buttonClass = ERROR_CLASS;
|
this.buttonClass = ERROR_CLASS;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -45,7 +45,7 @@ export class TokenCopyButton extends LitElement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html`<button @click=${() => this.onClick()} class="pf-c-button ${this.buttonClass}">
|
return html`<button @click=${() => this.onClick()} class="pf-c-button ${this.buttonClass}">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</button>`;
|
</button>`;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import PageStyle from "@patternfly/patternfly/components/Page/page.css";
|
import PageStyle from "@patternfly/patternfly/components/Page/page.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -23,7 +23,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
||||||
{
|
{
|
||||||
name: "Monitor",
|
name: "Monitor",
|
||||||
path: ["/audit/audit/"],
|
path: ["/audit/audit/"],
|
||||||
condition: (sb: Sidebar) => {
|
condition: (sb: Sidebar): boolean => {
|
||||||
return sb.user?.is_superuser || false;
|
return sb.user?.is_superuser || false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -123,7 +123,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
||||||
path: ["/administration/tokens/"],
|
path: ["/administration/tokens/"],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
condition: (sb: Sidebar) => {
|
condition: (sb: Sidebar): boolean => {
|
||||||
return sb.user?.is_superuser || false;
|
return sb.user?.is_superuser || false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -137,7 +137,7 @@ export class Sidebar extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
user?: User;
|
user?: User;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
GlobalsStyle,
|
GlobalsStyle,
|
||||||
PageStyle,
|
PageStyle,
|
||||||
|
@ -169,7 +169,7 @@ export class Sidebar extends LitElement {
|
||||||
super();
|
super();
|
||||||
User.me().then((u) => (this.user = u));
|
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", (e) => {
|
window.addEventListener("hashchange", () => {
|
||||||
this.activePath = window.location.hash.slice(1, Infinity);
|
this.activePath = window.location.hash.slice(1, Infinity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ export class Sidebar extends LitElement {
|
||||||
</li>`;
|
</li>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html`<div class="pf-c-page__sidebar-body">
|
return html`<div class="pf-c-page__sidebar-body">
|
||||||
<nav class="pf-c-nav" aria-label="Global">
|
<nav class="pf-c-nav" aria-label="Global">
|
||||||
<ul class="pf-c-nav__list">
|
<ul class="pf-c-nav__list">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import PageStyle from "@patternfly/patternfly/components/Page/page.css";
|
import PageStyle from "@patternfly/patternfly/components/Page/page.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -8,6 +8,10 @@ import { Config } from "../../api/config";
|
||||||
export const DefaultConfig: Config = {
|
export const DefaultConfig: Config = {
|
||||||
branding_logo: " /static/dist/assets/images/logo.svg",
|
branding_logo: " /static/dist/assets/images/logo.svg",
|
||||||
branding_title: "passbook",
|
branding_title: "passbook",
|
||||||
|
|
||||||
|
error_reporting_enabled: false,
|
||||||
|
error_reporting_environment: "",
|
||||||
|
error_reporting_send_pii: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@customElement("pb-sidebar-brand")
|
@customElement("pb-sidebar-brand")
|
||||||
|
@ -15,7 +19,7 @@ export class SidebarBrand extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
config: Config = DefaultConfig;
|
config: Config = DefaultConfig;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
GlobalsStyle,
|
GlobalsStyle,
|
||||||
PageStyle,
|
PageStyle,
|
||||||
|
@ -45,7 +49,7 @@ export class SidebarBrand extends LitElement {
|
||||||
Config.get().then((c) => (this.config = c));
|
Config.get().then((c) => (this.config = c));
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
if (!this.config) {
|
if (!this.config) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, 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
|
||||||
|
@ -12,7 +12,7 @@ export class SidebarUser extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
user?: User;
|
user?: User;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
fa,
|
fa,
|
||||||
NavStyle,
|
NavStyle,
|
||||||
|
@ -44,7 +44,7 @@ export class SidebarUser extends LitElement {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
if (!this.user) {
|
if (!this.user) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { gettext } from "django";
|
import { gettext } from "django";
|
||||||
import { html, LitElement, property, TemplateResult } from "lit-element";
|
import { CSSResult, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
import { PBResponse } from "../../api/client";
|
import { PBResponse } from "../../api/client";
|
||||||
import { COMMON_STYLES } from "../../common/styles";
|
import { COMMON_STYLES } from "../../common/styles";
|
||||||
|
import { htmlFromString } from "../../utils";
|
||||||
|
|
||||||
export abstract class Table<T> extends LitElement {
|
export abstract class Table<T> extends LitElement {
|
||||||
abstract apiEndpoint(page: number): Promise<PBResponse<T>>;
|
abstract apiEndpoint(page: number): Promise<PBResponse<T>>;
|
||||||
|
@ -14,11 +15,11 @@ export abstract class Table<T> extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
page = 1;
|
page = 1;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [COMMON_STYLES];
|
return COMMON_STYLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
public fetch() {
|
public fetch(): void {
|
||||||
this.apiEndpoint(this.page).then((r) => {
|
this.apiEndpoint(this.page).then((r) => {
|
||||||
this.data = r;
|
this.data = r;
|
||||||
this.page = r.pagination.current;
|
this.page = r.pagination.current;
|
||||||
|
@ -57,11 +58,11 @@ export abstract class Table<T> extends LitElement {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
fullRow.push("</tr>");
|
fullRow.push("</tr>");
|
||||||
return html(<any>fullRow);
|
return htmlFromString(...fullRow);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTable() {
|
renderTable(): TemplateResult {
|
||||||
if (!this.data) {
|
if (!this.data) {
|
||||||
this.fetch();
|
this.fetch();
|
||||||
}
|
}
|
||||||
|
@ -85,9 +86,7 @@ export abstract class Table<T> extends LitElement {
|
||||||
<table class="pf-c-table pf-m-compact pf-m-grid-md">
|
<table class="pf-c-table pf-m-compact pf-m-grid-md">
|
||||||
<thead>
|
<thead>
|
||||||
<tr role="row">
|
<tr role="row">
|
||||||
${this.columns().map(
|
${this.columns().map((col) => html`<th role="columnheader" scope="col">${gettext(col)}</th>`)}
|
||||||
(col) => html`<th role="columnheader" scope="col">${gettext(col)}</th>`
|
|
||||||
)}
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody role="rowgroup">
|
<tbody role="rowgroup">
|
||||||
|
@ -102,7 +101,7 @@ export abstract class Table<T> extends LitElement {
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return this.renderTable();
|
return this.renderTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { html } from "lit-html";
|
import { html, TemplateResult } from "lit-html";
|
||||||
import { Table } from "./Table";
|
import { Table } from "./Table";
|
||||||
|
|
||||||
export abstract class TablePage<T> extends Table<T> {
|
export abstract class TablePage<T> extends Table<T> {
|
||||||
|
@ -6,7 +6,7 @@ export abstract class TablePage<T> extends Table<T> {
|
||||||
abstract pageDescription(): string;
|
abstract pageDescription(): string;
|
||||||
abstract pageIcon(): string;
|
abstract pageIcon(): string;
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html`<section class="pf-c-page__main-section pf-m-light">
|
return html`<section class="pf-c-page__main-section pf-m-light">
|
||||||
<div class="pf-c-content">
|
<div class="pf-c-content">
|
||||||
<h1>
|
<h1>
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { customElement, html, LitElement, property } from "lit-element";
|
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
import { Table } from "./Table";
|
import { Table } from "./Table";
|
||||||
import { COMMON_STYLES } from "../../common/styles";
|
import { COMMON_STYLES } from "../../common/styles";
|
||||||
|
|
||||||
@customElement("pb-table-pagination")
|
@customElement("pb-table-pagination")
|
||||||
export class TablePagination extends LitElement {
|
export class TablePagination extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
table?: Table<any>;
|
table?: Table<unknown>;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [COMMON_STYLES];
|
return COMMON_STYLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
previousHandler() {
|
previousHandler(): void {
|
||||||
if (!this.table?.data?.pagination.previous) {
|
if (!this.table?.data?.pagination.previous) {
|
||||||
console.debug("passbook/tables: no previous");
|
console.debug("passbook/tables: no previous");
|
||||||
return;
|
return;
|
||||||
|
@ -19,7 +19,7 @@ export class TablePagination extends LitElement {
|
||||||
this.table.page = this.table?.data?.pagination.previous;
|
this.table.page = this.table?.data?.pagination.previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextHandler() {
|
nextHandler(): void {
|
||||||
if (!this.table?.data?.pagination.next) {
|
if (!this.table?.data?.pagination.next) {
|
||||||
console.debug("passbook/tables: no next");
|
console.debug("passbook/tables: no next");
|
||||||
return;
|
return;
|
||||||
|
@ -27,7 +27,7 @@ export class TablePagination extends LitElement {
|
||||||
this.table.page = this.table?.data?.pagination.next;
|
this.table.page = this.table?.data?.pagination.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html` <div class="pf-c-pagination pf-m-compact pf-m-hidden pf-m-visible-on-md">
|
return html` <div class="pf-c-pagination pf-m-compact pf-m-hidden pf-m-visible-on-md">
|
||||||
<div class="pf-c-pagination pf-m-compact pf-m-compact pf-m-hidden pf-m-visible-on-md">
|
<div class="pf-c-pagination pf-m-compact pf-m-compact pf-m-hidden pf-m-visible-on-md">
|
||||||
<div class="pf-c-options-menu">
|
<div class="pf-c-options-menu">
|
||||||
|
@ -43,9 +43,7 @@ export class TablePagination extends LitElement {
|
||||||
<div class="pf-c-pagination__nav-control pf-m-prev">
|
<div class="pf-c-pagination__nav-control pf-m-prev">
|
||||||
<button
|
<button
|
||||||
class="pf-c-button pf-m-plain"
|
class="pf-c-button pf-m-plain"
|
||||||
@click=${() => {
|
@click=${() => {this.previousHandler();}}
|
||||||
this.previousHandler();
|
|
||||||
}}
|
|
||||||
disabled="${this.table?.data?.pagination.previous ? "true" : "false"}"
|
disabled="${this.table?.data?.pagination.previous ? "true" : "false"}"
|
||||||
aria-label="{% trans 'Go to previous page' %}"
|
aria-label="{% trans 'Go to previous page' %}"
|
||||||
>
|
>
|
||||||
|
@ -55,9 +53,7 @@ export class TablePagination extends LitElement {
|
||||||
<div class="pf-c-pagination__nav-control pf-m-next">
|
<div class="pf-c-pagination__nav-control pf-m-next">
|
||||||
<button
|
<button
|
||||||
class="pf-c-button pf-m-plain"
|
class="pf-c-button pf-m-plain"
|
||||||
@click=${() => {
|
@click=${() => {this.nextHandler();}}
|
||||||
this.nextHandler();
|
|
||||||
}}
|
|
||||||
disabled="${this.table?.data?.pagination.next ? "true" : "false"}"
|
disabled="${this.table?.data?.pagination.next ? "true" : "false"}"
|
||||||
aria-label="{% trans 'Go to next page' %}"
|
aria-label="{% trans 'Go to next page' %}"
|
||||||
>
|
>
|
||||||
|
|
|
@ -7,7 +7,6 @@ import "./elements/buttons/ModalButton";
|
||||||
import "./elements/buttons/SpinnerButton";
|
import "./elements/buttons/SpinnerButton";
|
||||||
import "./elements/buttons/TokenCopyButton";
|
import "./elements/buttons/TokenCopyButton";
|
||||||
import "./elements/CodeMirror";
|
import "./elements/CodeMirror";
|
||||||
import "./elements/FetchFillSlot";
|
|
||||||
import "./elements/Messages";
|
import "./elements/Messages";
|
||||||
import "./elements/sidebar/Sidebar";
|
import "./elements/sidebar/Sidebar";
|
||||||
import "./elements/sidebar/SidebarBrand";
|
import "./elements/sidebar/SidebarBrand";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { gettext } from "django";
|
import { gettext } from "django";
|
||||||
import { customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
import { until } from "lit-html/directives/until";
|
import { until } from "lit-html/directives/until";
|
||||||
import { AdminOverview } from "../api/admin_overview";
|
import { AdminOverview } from "../api/admin_overview";
|
||||||
import { DefaultClient } from "../api/client";
|
import { DefaultClient } from "../api/client";
|
||||||
|
@ -17,7 +17,7 @@ export class AggregateCard extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
headerLink?: string;
|
headerLink?: string;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return COMMON_STYLES;
|
return COMMON_STYLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ export class AdminOverviewPage extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
data?: AdminOverview;
|
data?: AdminOverview;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return COMMON_STYLES;
|
return COMMON_STYLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ export class FlowShellCard extends LitElement {
|
||||||
async updateCard(data: Response): Promise<void> {
|
async updateCard(data: Response): Promise<void> {
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case ResponseType.redirect:
|
case ResponseType.redirect:
|
||||||
window.location.assign(data.to!);
|
window.location.assign(data.to || "");
|
||||||
break;
|
break;
|
||||||
case ResponseType.template:
|
case ResponseType.template:
|
||||||
this.flowBody = data.body;
|
this.flowBody = data.body;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
import { Application } from "../api/application";
|
import { Application } from "../api/application";
|
||||||
import { PBResponse } from "../api/client";
|
import { PBResponse } from "../api/client";
|
||||||
import { COMMON_STYLES } from "../common/styles";
|
import { COMMON_STYLES } from "../common/styles";
|
||||||
|
@ -9,7 +9,7 @@ export class ApplicationViewPage extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
apps?: PBResponse<Application>;
|
apps?: PBResponse<Application>;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return COMMON_STYLES.concat(
|
return COMMON_STYLES.concat(
|
||||||
css`
|
css`
|
||||||
img.pf-icon {
|
img.pf-icon {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import CodeMirrorStyle from "codemirror/lib/codemirror.css";
|
import CodeMirrorStyle from "codemirror/lib/codemirror.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -61,15 +61,16 @@ export const ROUTES: Route[] = [
|
||||||
|
|
||||||
class RouteMatch {
|
class RouteMatch {
|
||||||
route: Route;
|
route: Route;
|
||||||
arguments?: RegExpExecArray;
|
arguments: { [key: string]: string; };
|
||||||
fullUrl?: string;
|
fullUrl?: string;
|
||||||
|
|
||||||
constructor(route: Route) {
|
constructor(route: Route) {
|
||||||
this.route = route;
|
this.route = route;
|
||||||
|
this.arguments = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
return this.route.render(this.arguments!.groups || {});
|
return this.route.render(this.arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
|
@ -85,7 +86,7 @@ export class RouterOutlet extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
defaultUrl?: string;
|
defaultUrl?: string;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
CodeMirrorStyle,
|
CodeMirrorStyle,
|
||||||
CodeMirrorTheme,
|
CodeMirrorTheme,
|
||||||
|
@ -110,7 +111,7 @@ export class RouterOutlet extends LitElement {
|
||||||
navigate(): void {
|
navigate(): void {
|
||||||
let activeUrl = window.location.hash.slice(1, Infinity);
|
let activeUrl = window.location.hash.slice(1, Infinity);
|
||||||
if (activeUrl === "") {
|
if (activeUrl === "") {
|
||||||
activeUrl = this.defaultUrl!;
|
activeUrl = this.defaultUrl || "/";
|
||||||
window.location.hash = `#${activeUrl}`;
|
window.location.hash = `#${activeUrl}`;
|
||||||
console.debug(`passbook/router: set to ${window.location.hash}`);
|
console.debug(`passbook/router: set to ${window.location.hash}`);
|
||||||
return;
|
return;
|
||||||
|
@ -121,7 +122,7 @@ export class RouterOutlet extends LitElement {
|
||||||
const match = route.url.exec(activeUrl);
|
const match = route.url.exec(activeUrl);
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
matchedRoute = new RouteMatch(route);
|
matchedRoute = new RouteMatch(route);
|
||||||
matchedRoute.arguments = match;
|
matchedRoute.arguments = match.groups || {};
|
||||||
matchedRoute.fullUrl = activeUrl;
|
matchedRoute.fullUrl = activeUrl;
|
||||||
console.debug(`passbook/router: found match ${matchedRoute}`);
|
console.debug(`passbook/router: found match ${matchedRoute}`);
|
||||||
return true;
|
return true;
|
||||||
|
@ -136,7 +137,7 @@ export class RouterOutlet extends LitElement {
|
||||||
</pb-site-shell>`
|
</pb-site-shell>`
|
||||||
);
|
);
|
||||||
matchedRoute = new RouteMatch(route);
|
matchedRoute = new RouteMatch(route);
|
||||||
matchedRoute.arguments = route.url.exec(activeUrl)!;
|
matchedRoute.arguments = route.url.exec(activeUrl)?.groups || {};
|
||||||
matchedRoute.fullUrl = activeUrl;
|
matchedRoute.fullUrl = activeUrl;
|
||||||
}
|
}
|
||||||
this.current = matchedRoute;
|
this.current = matchedRoute;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { css, customElement, html, LitElement, property } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import BullseyeStyle from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";
|
import BullseyeStyle from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -19,7 +19,7 @@ export class SiteShell extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
loading = false;
|
loading = false;
|
||||||
|
|
||||||
static get styles() {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
css`
|
css`
|
||||||
:host,
|
:host,
|
||||||
|
@ -44,7 +44,7 @@ export class SiteShell extends LitElement {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
loadContent() {
|
loadContent(): void {
|
||||||
if (!this._url) {
|
if (!this._url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,11 @@ export class SiteShell extends LitElement {
|
||||||
})
|
})
|
||||||
.then((r) => r.text())
|
.then((r) => r.text())
|
||||||
.then((t) => {
|
.then((t) => {
|
||||||
this.querySelector("[slot=body]")!.innerHTML = t;
|
const bodySlot = this.querySelector("[slot=body]");
|
||||||
|
if (!bodySlot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bodySlot.innerHTML = t;
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Ensure anchors only change the hash
|
// Ensure anchors only change the hash
|
||||||
|
@ -73,12 +77,13 @@ export class SiteShell extends LitElement {
|
||||||
const qs = url.search || "";
|
const qs = url.search || "";
|
||||||
a.href = `#${url.pathname}${qs}`;
|
a.href = `#${url.pathname}${qs}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.debug(`passbook/site-shell: error ${e}`);
|
||||||
a.href = `#${a.href}`;
|
a.href = `#${a.href}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Create refresh buttons
|
// Create refresh buttons
|
||||||
this.querySelectorAll("[role=pb-refresh]").forEach((rt) => {
|
this.querySelectorAll("[role=pb-refresh]").forEach((rt) => {
|
||||||
rt.addEventListener("click", (e) => {
|
rt.addEventListener("click", () => {
|
||||||
this.loadContent();
|
this.loadContent();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -87,7 +92,7 @@ export class SiteShell extends LitElement {
|
||||||
f.addEventListener("submit", (e) => {
|
f.addEventListener("submit", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const formData = new FormData(f);
|
const formData = new FormData(f);
|
||||||
const qs = new URLSearchParams(<any>(<unknown>formData)).toString();
|
const qs = new URLSearchParams((<any>formData)).toString(); // eslint-disable-line
|
||||||
window.location.hash = `#${this._url}?${qs}`;
|
window.location.hash = `#${this._url}?${qs}`;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -97,7 +102,7 @@ export class SiteShell extends LitElement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): TemplateResult {
|
||||||
return html` ${this.loading ?
|
return html` ${this.loading ?
|
||||||
html`<div class="pf-c-backdrop">
|
html`<div class="pf-c-backdrop">
|
||||||
<div class="pf-l-bullseye">
|
<div class="pf-l-bullseye">
|
||||||
|
|
|
@ -29,10 +29,10 @@ export class ApplicationList extends TablePage<Application> {
|
||||||
|
|
||||||
row(item: Application): string[] {
|
row(item: Application): string[] {
|
||||||
return [
|
return [
|
||||||
item.name!,
|
item.name,
|
||||||
item.slug!,
|
item.slug,
|
||||||
item.provider!.toString(),
|
item.provider.toString(),
|
||||||
item.provider!.toString(),
|
item.provider.toString(),
|
||||||
`
|
`
|
||||||
<pb-modal-button href="administration/policies/bindings/${item.pk}/update/">
|
<pb-modal-button href="administration/policies/bindings/${item.pk}/update/">
|
||||||
<pb-spinner-button slot="trigger" class="pf-m-secondary">
|
<pb-spinner-button slot="trigger" class="pf-m-secondary">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { gettext } from "django";
|
import { gettext } from "django";
|
||||||
import { css, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
import { Application } from "../../api/application";
|
import { Application } from "../../api/application";
|
||||||
import { DefaultClient, PBResponse } from "../../api/client";
|
import { DefaultClient, PBResponse } from "../../api/client";
|
||||||
import { PolicyBinding } from "../../api/policy_binding";
|
import { PolicyBinding } from "../../api/policy_binding";
|
||||||
|
@ -13,7 +13,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||||
|
|
||||||
apiEndpoint(page: number): Promise<PBResponse<PolicyBinding>> {
|
apiEndpoint(page: number): Promise<PBResponse<PolicyBinding>> {
|
||||||
return DefaultClient.fetch<PBResponse<PolicyBinding>>(["policies", "bindings"], {
|
return DefaultClient.fetch<PBResponse<PolicyBinding>>(["policies", "bindings"], {
|
||||||
target: this.target!,
|
target: this.target || "",
|
||||||
ordering: "order",
|
ordering: "order",
|
||||||
page: page,
|
page: page,
|
||||||
});
|
});
|
||||||
|
@ -62,7 +62,7 @@ export class ApplicationViewPage extends LitElement {
|
||||||
@property()
|
@property()
|
||||||
application?: Application;
|
application?: Application;
|
||||||
|
|
||||||
static get styles(): any[] {
|
static get styles(): CSSResult[] {
|
||||||
return COMMON_STYLES.concat(
|
return COMMON_STYLES.concat(
|
||||||
css`
|
css`
|
||||||
img.pf-icon {
|
img.pf-icon {
|
||||||
|
@ -95,12 +95,10 @@ export class ApplicationViewPage extends LitElement {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-c-card__body">
|
<div class="pf-c-card__body">
|
||||||
${this.application ?
|
${this.application ? html`
|
||||||
html`
|
|
||||||
<pb-admin-logins-chart
|
<pb-admin-logins-chart
|
||||||
url="${DefaultClient.makeUrl(["core", "applications", this.application?.slug, "metrics"])}">
|
url="${DefaultClient.makeUrl(["core", "applications", this.application?.slug, "metrics"])}">
|
||||||
</pb-admin-logins-chart>`
|
</pb-admin-logins-chart>`: ""}
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
|
||||||
export function getCookie(name: string): string | undefined {
|
export function getCookie(name: string): string | undefined {
|
||||||
let cookieValue = undefined;
|
let cookieValue = undefined;
|
||||||
if (document.cookie && document.cookie !== "") {
|
if (document.cookie && document.cookie !== "") {
|
||||||
|
@ -28,3 +30,7 @@ export function truncate(input?: string, max = 10): string {
|
||||||
|
|
||||||
return array.slice(0, max).join(" ") + ellipsis;
|
return array.slice(0, max).join(" ") + ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function htmlFromString(...strings: string[]): TemplateResult {
|
||||||
|
return html({ raw: strings, ...strings } as TemplateStringsArray);
|
||||||
|
}
|
||||||
|
|
Reference in a new issue