flows: add diagrams (#415)
* flows: initial diagram implementation * web: install flowchart.js, add flow diagram page * web: adjust diagram colours for dark mode * flows: add permission checks for diagram * flows: fix formatting * web: fix formatting for web * flows: add fix when last stage has policy * flows: add test for diagram * web: flows/diagram: add support for light mode * flows: make Flows's Diagram API return json, add more tests and fix swagger response
This commit is contained in:
@ -30,6 +30,10 @@ export class Flow {
|
||||
return DefaultClient.fetch<Flow>(["flows", "instances", slug]);
|
||||
}
|
||||
|
||||
static diagram(slug: string): Promise<{ diagram: string }> {
|
||||
return DefaultClient.fetch<{ diagram: string }>(["flows", "instances", slug, "diagram"]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<PBResponse<Flow>> {
|
||||
return DefaultClient.fetch<PBResponse<Flow>>(["flows", "instances"], filter);
|
||||
}
|
||||
|
62
web/src/pages/flows/FlowDiagram.ts
Normal file
62
web/src/pages/flows/FlowDiagram.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||
import FlowChart from "flowchart.js";
|
||||
import { Flow } from "../../api/Flows";
|
||||
import { loading } from "../../utils";
|
||||
|
||||
export const FONT_COLOUR_DARK_MODE = "#fafafa";
|
||||
export const FONT_COLOUR_LIGHT_MODE = "#151515";
|
||||
export const FILL_DARK_MODE = "#18191a";
|
||||
export const FILL_LIGHT_MODE = "#f0f0f0";
|
||||
|
||||
@customElement("ak-flow-diagram")
|
||||
export class FlowDiagram extends LitElement {
|
||||
|
||||
@property()
|
||||
set flowSlug(value: string) {
|
||||
Flow.diagram(value).then((data) => {
|
||||
this.diagram = FlowChart.parse(data.diagram);
|
||||
});
|
||||
}
|
||||
|
||||
@property({attribute: false})
|
||||
diagram?: FlowChart.Instance;
|
||||
|
||||
@property()
|
||||
fontColour: string = FONT_COLOUR_DARK_MODE;
|
||||
|
||||
@property()
|
||||
fill: string = FILL_DARK_MODE;
|
||||
|
||||
createRenderRoot(): Element | ShadowRoot {
|
||||
return this;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
window.matchMedia("(prefers-color-scheme: light)").addEventListener("change", (ev) => {
|
||||
if (ev.matches) {
|
||||
this.fontColour = FONT_COLOUR_LIGHT_MODE;
|
||||
this.fill = FILL_LIGHT_MODE;
|
||||
} else {
|
||||
this.fontColour = FONT_COLOUR_DARK_MODE;
|
||||
this.fill = FILL_DARK_MODE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (this.diagram) {
|
||||
this.diagram.drawSVG(this, {
|
||||
"font-color": this.fontColour,
|
||||
"line-color": "#bebebe",
|
||||
"element-color": "#bebebe",
|
||||
"fill": this.fill,
|
||||
"yes-text": "Policy passes",
|
||||
"no-text": "Policy denies",
|
||||
});
|
||||
return html``;
|
||||
}
|
||||
return loading(this.diagram, html``);
|
||||
}
|
||||
|
||||
}
|
@ -9,6 +9,7 @@ import "../../elements/buttons/ModalButton";
|
||||
import "../../elements/buttons/SpinnerButton";
|
||||
import "../../elements/policies/BoundPoliciesList";
|
||||
import "./BoundStagesList";
|
||||
import "./FlowDiagram";
|
||||
|
||||
@customElement("ak-flow-view")
|
||||
export class FlowViewPage extends LitElement {
|
||||
@ -49,6 +50,12 @@ export class FlowViewPage extends LitElement {
|
||||
</div>
|
||||
</section>
|
||||
<ak-tabs>
|
||||
<div slot="page-1" data-tab-title="${gettext("Flow Diagram")}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-c-card">
|
||||
<ak-flow-diagram flowSlug=${this.flow.slug}>
|
||||
</ak-flow-diagram>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="page-2" data-tab-title="${gettext("Stage Bindings")}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-c-card">
|
||||
<ak-bound-stages-list .target=${this.flow.pk}>
|
||||
|
Reference in New Issue
Block a user