web: further cleanup, more linting

This commit is contained in:
Jens Langhammer 2020-12-02 15:44:40 +01:00
parent 05aeeafacc
commit c17623323a
23 changed files with 1647 additions and 39 deletions

View file

@ -5,7 +5,8 @@
}, },
"extends": [ "extends": [
"eslint:recommended", "eslint:recommended",
"plugin:@typescript-eslint/recommended" "plugin:@typescript-eslint/recommended",
"plugin:lit/recommended"
], ],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
@ -13,7 +14,8 @@
"sourceType": "module" "sourceType": "module"
}, },
"plugins": [ "plugins": [
"@typescript-eslint" "@typescript-eslint",
"lit"
], ],
"rules": { "rules": {
"indent": ["error", 4], "indent": ["error", 4],

1570
web/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,8 @@
"scripts": { "scripts": {
"build": "rollup -c ./rollup.config.js", "build": "rollup -c ./rollup.config.js",
"watch": "rollup -c -w", "watch": "rollup -c -w",
"lint": "eslint . --max-warnings 0" "lint": "eslint . --max-warnings 0",
"lit-analyse": "lit-analyzer src"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^5.15.1", "@fortawesome/fontawesome-free": "^5.15.1",
@ -29,11 +30,13 @@
"@typescript-eslint/parser": "^4.9.0", "@typescript-eslint/parser": "^4.9.0",
"eslint": "^7.14.0", "eslint": "^7.14.0",
"eslint-config-google": "^0.14.0", "eslint-config-google": "^0.14.0",
"eslint-plugin-lit": "^1.2.4",
"rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-minify-html-literals": "^1.2.5", "rollup-plugin-minify-html-literals": "^1.2.5",
"rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-sourcemaps": "^0.6.3", "rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-terser": "^7.0.2", "rollup-plugin-terser": "^7.0.2",
"ts-lit-plugin": "^1.2.1",
"typescript": "^4.1.2" "typescript": "^4.1.2"
} }
} }

View file

@ -9,7 +9,7 @@ import "codemirror/mode/python/python.js";
@customElement("pb-codemirror") @customElement("pb-codemirror")
export class CodeMirrorTextarea extends LitElement { export class CodeMirrorTextarea extends LitElement {
@property() @property({type: Boolean})
readOnly = false; readOnly = false;
@property() @property()

View file

@ -1,4 +1,5 @@
import { LitElement, html, customElement, property, CSSResult, TemplateResult } from "lit-element"; import { LitElement, html, customElement, property, CSSResult, TemplateResult } from "lit-element";
import { ifDefined } from "lit-html/directives/if-defined";
// @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
@ -38,6 +39,6 @@ export class Tabs extends LitElement {
${pages.map((page) => this.renderTab(page))} ${pages.map((page) => this.renderTab(page))}
</ul> </ul>
</div> </div>
<slot name="${this.currentPage}"></slot>`; <slot name="${ifDefined(this.currentPage)}"></slot>`;
} }
} }

View file

@ -19,7 +19,7 @@ export class ModalButton extends LitElement {
@property() @property()
href?: string; href?: string;
@property() @property({type: Boolean})
open = false; open = false;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {

View file

@ -9,7 +9,7 @@ import { ColorStyles, PRIMARY_CLASS, PROGRESS_CLASS } from "../../constants";
@customElement("pb-spinner-button") @customElement("pb-spinner-button")
export class SpinnerButton extends LitElement { export class SpinnerButton extends LitElement {
@property() @property({type: Boolean})
isRunning = false; isRunning = false;
@property() @property()

View file

@ -1,5 +1,6 @@
import { gettext } from "django"; import { gettext } from "django";
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { ifDefined } from "lit-html/directives/if-defined";
import { COMMON_STYLES } from "../../common/styles"; import { COMMON_STYLES } from "../../common/styles";
@customElement("pb-aggregate-card") @customElement("pb-aggregate-card")
@ -33,7 +34,7 @@ export class AggregateCard extends LitElement {
return html`<div class="pf-c-card pf-c-card-aggregate"> return html`<div class="pf-c-card pf-c-card-aggregate">
<div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between"> <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between">
<div class="pf-c-card__header-main"> <div class="pf-c-card__header-main">
<i class="${this.icon}"></i> ${this.header ? gettext(this.header) : ""} <i class="${ifDefined(this.icon)}"></i> ${this.header ? gettext(this.header) : ""}
</div> </div>
${this.headerLink ? html`<a href="${this.headerLink}"> ${this.headerLink ? html`<a href="${this.headerLink}">
<i class="fa fa-external-link-alt"> </i> <i class="fa fa-external-link-alt"> </i>

View file

@ -1,24 +1,26 @@
import { customElement, html, property, TemplateResult } from "lit-element"; import { customElement, html, property, TemplateResult } from "lit-element";
import { until } from "lit-html/directives/until"; import { until } from "lit-html/directives/until";
import { AggregateCard } from "./AggregateCard"; import { AggregateCard } from "./AggregateCard";
import "../Spinner";
import { SpinnerSize } from "../Spinner";
@customElement("pb-aggregate-card-promise") @customElement("pb-aggregate-card-promise")
export class AggregatePromiseCard extends AggregateCard { export class AggregatePromiseCard extends AggregateCard {
@property() @property({attribute: false})
promise?: Promise<string>; promise?: Promise<Record<string, unknown>>;
promiseProxy(): Promise<TemplateResult> { promiseProxy(): Promise<TemplateResult> {
if (!this.promise) { if (!this.promise) {
return new Promise<TemplateResult>(() => html``); return new Promise<TemplateResult>(() => html``);
} }
return this.promise.then(s => { return this.promise.then(s => {
return html`<i class="fa fa-check-circle"></i> ${s}`; return html`<i class="fa fa-check-circle"></i> ${s.toString()}`;
}); });
} }
renderInner(): TemplateResult { renderInner(): TemplateResult {
return html`<p class="center-value"> return html`<p class="center-value">
${until(this.promiseProxy(), html`<pb-spinner size="large"></pb-spinner>`)} ${until(this.promiseProxy(), html`<pb-spinner size="${SpinnerSize.Large}"></pb-spinner>`)}
</p>`; </p>`;
} }

View file

@ -8,6 +8,9 @@ import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
import { until } from "lit-html/directives/until"; import { until } from "lit-html/directives/until";
import "./SidebarBrand";
import "./SidebarUser";
export interface SidebarItem { export interface SidebarItem {
name: string; name: string;
path?: string[]; path?: string[];

View file

@ -16,7 +16,7 @@ export const DefaultConfig: Config = {
@customElement("pb-sidebar-brand") @customElement("pb-sidebar-brand")
export class SidebarBrand extends LitElement { export class SidebarBrand extends LitElement {
@property() @property({attribute: false})
config: Config = DefaultConfig; config: Config = DefaultConfig;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {

View file

@ -4,15 +4,17 @@ import { PBResponse } from "../../api/client";
import { COMMON_STYLES } from "../../common/styles"; import { COMMON_STYLES } from "../../common/styles";
import { htmlFromString } from "../../utils"; import { htmlFromString } from "../../utils";
import "./TablePagination";
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>>;
abstract columns(): Array<string>; abstract columns(): Array<string>;
abstract row(item: T): Array<string>; abstract row(item: T): Array<string>;
@property() @property({attribute: false})
data?: PBResponse<T>; data?: PBResponse<T>;
@property() @property({type: Number})
page = 1; page = 1;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {

View file

@ -4,7 +4,7 @@ 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({attribute: false})
table?: Table<unknown>; table?: Table<unknown>;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
@ -44,7 +44,7 @@ export class TablePagination extends LitElement {
<button <button
class="pf-c-button pf-m-plain" class="pf-c-button pf-m-plain"
@click=${() => {this.previousHandler();}} @click=${() => {this.previousHandler();}}
disabled="${this.table?.data?.pagination.previous ? "true" : "false"}" ?disabled="${(this.table?.data?.pagination.previous || 0) > 0}"
aria-label="{% trans 'Go to previous page' %}" aria-label="{% trans 'Go to previous page' %}"
> >
<i class="fas fa-angle-left" aria-hidden="true"></i> <i class="fas fa-angle-left" aria-hidden="true"></i>
@ -54,7 +54,7 @@ export class TablePagination extends LitElement {
<button <button
class="pf-c-button pf-m-plain" class="pf-c-button pf-m-plain"
@click=${() => {this.nextHandler();}} @click=${() => {this.nextHandler();}}
disabled="${this.table?.data?.pagination.next ? "true" : "false"}" ?disabled="${(this.table?.data?.pagination.next || 0) > 0}"
aria-label="{% trans 'Go to next page' %}" aria-label="{% trans 'Go to next page' %}"
> >
<i class="fas fa-angle-right" aria-hidden="true"></i> <i class="fas fa-angle-right" aria-hidden="true"></i>

View file

@ -1,15 +1,16 @@
import { gettext } from "django"; import { gettext } from "django";
import { CSSResult, html, LitElement, TemplateResult } from "lit-element"; import { html, LitElement, TemplateResult } from "lit-element";
import { COMMON_STYLES } from "../common/styles";
import { SidebarItem } from "../elements/sidebar/Sidebar"; import { SidebarItem } from "../elements/sidebar/Sidebar";
// @customElement("pb-interface") import "../elements/Messages";
import "../pages/router/RouterOutlet";
export abstract class Interface extends LitElement { export abstract class Interface extends LitElement {
abstract get sidebar(): SidebarItem[]; abstract get sidebar(): SidebarItem[];
static get styles(): CSSResult[] { createRenderRoot(): ShadowRoot | Element {
return COMMON_STYLES; return this;
} }
render(): TemplateResult { render(): TemplateResult {

View file

@ -6,7 +6,7 @@ import { truncate } from "../utils";
@customElement("pb-library") @customElement("pb-library")
export class ApplicationViewPage extends LitElement { export class ApplicationViewPage extends LitElement {
@property() @property({attribute: false})
apps?: PBResponse<Application>; apps?: PBResponse<Application>;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {

View file

@ -5,21 +5,25 @@ import { DefaultClient } from "../../api/client";
import { User } from "../../api/user"; import { User } from "../../api/user";
import { COMMON_STYLES } from "../../common/styles"; import { COMMON_STYLES } from "../../common/styles";
import { AggregatePromiseCard } from "../../elements/cards/AggregatePromiseCard"; import { AggregatePromiseCard } from "../../elements/cards/AggregatePromiseCard";
import { SpinnerSize } from "../../elements/Spinner";
import "../../elements/AdminLoginsChart";
import "./TopApplicationsTable";
@customElement("pb-admin-status-card") @customElement("pb-admin-status-card")
export class AdminStatusCard extends AggregatePromiseCard { export class AdminStatusCard extends AggregatePromiseCard {
@property() @property({type: Number})
value?: number; value?: number;
@property() @property()
warningText?: string; warningText?: string;
@property() @property({type: Number})
lessThanThreshold?: number; lessThanThreshold?: number;
renderNone(): TemplateResult { renderNone(): TemplateResult {
return html`<pb-spinner size="large"></pb-spinner>`; return html`<pb-spinner size=${SpinnerSize.Large}></pb-spinner>`;
} }
renderGood(): TemplateResult { renderGood(): TemplateResult {
@ -47,10 +51,10 @@ export class AdminStatusCard extends AggregatePromiseCard {
@customElement("pb-admin-overview") @customElement("pb-admin-overview")
export class AdminOverviewPage extends LitElement { export class AdminOverviewPage extends LitElement {
@property() @property({attribute: false})
data?: AdminOverview; data?: AdminOverview;
@property() @property({attribute: false})
users?: Promise<number>; users?: Promise<number>;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
@ -89,7 +93,7 @@ export class AdminOverviewPage extends LitElement {
html`<p class="pb-aggregate-card"> html`<p class="pb-aggregate-card">
<i class="fa fa-check-circle"></i> 0 <i class="fa fa-check-circle"></i> 0
</p>` </p>`
: html`<pb-spinner size="large"></pb-spinner>`} : html`<pb-spinner size=${SpinnerSize.Large}></pb-spinner>`}
</pb-aggregate-card> </pb-aggregate-card>
<pb-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Policies" headerLink="#/administration/policies/"> <pb-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Policies" headerLink="#/administration/policies/">
${this.data ? ${this.data ?
@ -101,7 +105,7 @@ export class AdminOverviewPage extends LitElement {
html`<p class="pb-aggregate-card"> html`<p class="pb-aggregate-card">
<i class="fa fa-check-circle"></i> 0 <i class="fa fa-check-circle"></i> 0
</p>` </p>`
: html`<pb-spinner size="large"></pb-spinner>`} : html`<pb-spinner size=${SpinnerSize.Large}></pb-spinner>`}
</pb-aggregate-card> </pb-aggregate-card>
<pb-aggregate-card-promise <pb-aggregate-card-promise
icon="pf-icon pf-icon-user" icon="pf-icon pf-icon-user"

View file

@ -3,10 +3,12 @@ import { CSSResult, customElement, html, LitElement, property, TemplateResult }
import { AuditEvent, TopNEvent } from "../../api/events"; import { AuditEvent, TopNEvent } from "../../api/events";
import { COMMON_STYLES } from "../../common/styles"; import { COMMON_STYLES } from "../../common/styles";
import "../../elements/Spinner";
@customElement("pb-top-applications-table") @customElement("pb-top-applications-table")
export class TopApplicationsTable extends LitElement { export class TopApplicationsTable extends LitElement {
@property() @property({attribute: false})
topN?: TopNEvent[]; topN?: TopNEvent[];
static get styles(): CSSResult[] { static get styles(): CSSResult[] {

View file

@ -6,6 +6,9 @@ import { PolicyBinding } from "../../api/policy_binding";
import { COMMON_STYLES } from "../../common/styles"; import { COMMON_STYLES } from "../../common/styles";
import { Table } from "../../elements/table/Table"; import { Table } from "../../elements/table/Table";
import "../../elements/Tabs";
import "../../elements/AdminLoginsChart";
@customElement("pb-bound-policies-list") @customElement("pb-bound-policies-list")
export class BoundPoliciesList extends Table<PolicyBinding> { export class BoundPoliciesList extends Table<PolicyBinding> {
@property() @property()
@ -59,7 +62,7 @@ export class ApplicationViewPage extends LitElement {
Application.get(value).then((app) => (this.application = app)); Application.get(value).then((app) => (this.application = app));
} }
@property() @property({attribute: false})
application?: Application; application?: Application;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {

View file

@ -5,6 +5,7 @@ import BullseyeStyle from "@patternfly/patternfly/layouts/Bullseye/bullseye.css"
import SpinnerStyle from "@patternfly/patternfly/components/Spinner/spinner.css"; import SpinnerStyle from "@patternfly/patternfly/components/Spinner/spinner.css";
// @ts-ignore // @ts-ignore
import BackdropStyle from "@patternfly/patternfly/components/Backdrop/backdrop.css"; import BackdropStyle from "@patternfly/patternfly/components/Backdrop/backdrop.css";
import { SpinnerSize } from "../../elements/Spinner";
@customElement("pb-site-shell") @customElement("pb-site-shell")
export class SiteShell extends LitElement { export class SiteShell extends LitElement {
@ -16,7 +17,7 @@ export class SiteShell extends LitElement {
_url?: string; _url?: string;
@property() @property({type: Boolean})
loading = false; loading = false;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
@ -107,7 +108,7 @@ export class SiteShell extends LitElement {
html`<div class="pf-c-backdrop"> html`<div class="pf-c-backdrop">
<div class="pf-l-bullseye"> <div class="pf-l-bullseye">
<div class="pf-l-bullseye__item"> <div class="pf-l-bullseye__item">
<pb-spinner size="large"></pb-spinner> <pb-spinner size=${SpinnerSize.Large}></pb-spinner>
</div> </div>
</div> </div>
</div>` </div>`

View file

@ -9,9 +9,11 @@ import { Route } from "./Route";
import { ROUTES } from "../../routes"; import { ROUTES } from "../../routes";
import { RouteMatch } from "./RouteMatch"; import { RouteMatch } from "./RouteMatch";
import "../generic/SiteShell";
@customElement("pb-router-outlet") @customElement("pb-router-outlet")
export class RouterOutlet extends LitElement { export class RouterOutlet extends LitElement {
@property() @property({attribute: false})
current?: RouteMatch; current?: RouteMatch;
@property() @property()

View file

@ -1,6 +1,11 @@
import { html } from "lit-html"; import { html } from "lit-html";
import { Route, SLUG_REGEX } from "./pages/router/Route"; import { Route, SLUG_REGEX } from "./pages/router/Route";
import "./pages/LibraryPage";
import "./pages/admin-overview/AdminOverviewPage";
import "./pages/applications/ApplicationListPage";
import "./pages/applications/ApplicationViewPage";
export const ROUTES: Route[] = [ export const ROUTES: Route[] = [
// Prevent infinite Shell loops // Prevent infinite Shell loops
new Route(new RegExp("^/$")).redirect("/library/"), new Route(new RegExp("^/$")).redirect("/library/"),

View file

@ -9,6 +9,12 @@
"target": "esnext", "target": "esnext",
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "node",
"lib": ["es2017", "dom", "dom.iterable"] "lib": ["es2017", "dom", "dom.iterable"],
"plugins": [
{
"name": "ts-lit-plugin",
"strict": true
}
]
} }
} }