web: migrate Stage List to web
This commit is contained in:
parent
a76cbf8b70
commit
93478a55d7
|
@ -1,143 +0,0 @@
|
||||||
{% extends "administration/base.html" %}
|
|
||||||
|
|
||||||
{% load i18n %}
|
|
||||||
{% load authentik_utils %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<section class="pf-c-page__main-section pf-m-light">
|
|
||||||
<div class="pf-c-content">
|
|
||||||
<h1>
|
|
||||||
<i class="pf-icon pf-icon-plugged"></i>
|
|
||||||
{% trans 'Stages' %}
|
|
||||||
</h1>
|
|
||||||
<p>{% trans "Stages are single steps of a Flow that a user is guided through." %}</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
|
||||||
<div class="pf-c-card">
|
|
||||||
{% if object_list %}
|
|
||||||
<div class="pf-c-toolbar">
|
|
||||||
<div class="pf-c-toolbar__content">
|
|
||||||
{% include 'partials/toolbar_search.html' %}
|
|
||||||
<div class="pf-c-toolbar__bulk-select">
|
|
||||||
<ak-dropdown class="pf-c-dropdown">
|
|
||||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
|
||||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
|
||||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
<ul class="pf-c-dropdown__menu" hidden>
|
|
||||||
{% for type, name in types.items %}
|
|
||||||
<li>
|
|
||||||
<ak-modal-button href="{% url 'authentik_admin:stage-create' %}?type={{ type }}">
|
|
||||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
|
||||||
{{ name|verbose_name }}<br>
|
|
||||||
<small>
|
|
||||||
{{ name|doc }}
|
|
||||||
</small>
|
|
||||||
</button>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</ak-dropdown>
|
|
||||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
|
||||||
{% trans 'Refresh' %}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% include 'partials/pagination.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
|
|
||||||
<thead>
|
|
||||||
<tr role="row">
|
|
||||||
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
|
||||||
<th role="columnheader" scope="col">{% trans 'Flows' %}</th>
|
|
||||||
<th role="cell"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody role="rowgroup">
|
|
||||||
{% for stage in object_list %}
|
|
||||||
<tr role="row">
|
|
||||||
<th role="columnheader">
|
|
||||||
<div>
|
|
||||||
<div>{{ stage.name }}</div>
|
|
||||||
<small>{{ stage|verbose_name }}</small>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<td role="cell">
|
|
||||||
<ul>
|
|
||||||
{% for flow in stage.flow_set.all %}
|
|
||||||
<li>{{ flow.slug }}</li>
|
|
||||||
{% empty %}
|
|
||||||
<li>-</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<ak-modal-button href="{% url 'authentik_admin:stage-update' pk=stage.stage_uuid %}">
|
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
|
||||||
{% trans 'Edit' %}
|
|
||||||
</ak-spinner-button>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>
|
|
||||||
<ak-modal-button href="{% url 'authentik_admin:stage-delete' pk=stage.stage_uuid %}">
|
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
|
||||||
{% trans 'Delete' %}
|
|
||||||
</ak-spinner-button>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div class="pf-c-pagination pf-m-bottom">
|
|
||||||
{% include 'partials/pagination.html' %}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="pf-c-toolbar">
|
|
||||||
<div class="pf-c-toolbar__content">
|
|
||||||
{% include 'partials/toolbar_search.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pf-c-empty-state">
|
|
||||||
<div class="pf-c-empty-state__content">
|
|
||||||
<i class="pf-icon pf-icon-plugged pf-c-empty-state__icon" aria-hidden="true"></i>
|
|
||||||
<h1 class="pf-c-title pf-m-lg">
|
|
||||||
{% trans 'No Stages.' %}
|
|
||||||
</h1>
|
|
||||||
<div class="pf-c-empty-state__body">
|
|
||||||
{% if request.GET.search != "" %}
|
|
||||||
{% trans "Your search query doesn't match any stages." %}
|
|
||||||
{% else %}
|
|
||||||
{% trans 'Currently no stages exist. Click the button below to create one.' %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<ak-dropdown class="pf-c-dropdown">
|
|
||||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
|
||||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
|
||||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
<ul class="pf-c-dropdown__menu" hidden>
|
|
||||||
{% for type, name in types.items %}
|
|
||||||
<li>
|
|
||||||
<ak-modal-button href="{% url 'authentik_admin:stage-create' %}?type={{ type }}">
|
|
||||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
|
||||||
{{ name|verbose_name }}<br>
|
|
||||||
<small>
|
|
||||||
{{ name|doc }}
|
|
||||||
</small>
|
|
||||||
</button>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</ak-dropdown>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
{% endblock %}
|
|
|
@ -125,7 +125,6 @@ urlpatterns = [
|
||||||
name="provider-delete",
|
name="provider-delete",
|
||||||
),
|
),
|
||||||
# Stages
|
# Stages
|
||||||
path("stages/", stages.StageListView.as_view(), name="stages"),
|
|
||||||
path("stages/create/", stages.StageCreateView.as_view(), name="stage-create"),
|
path("stages/create/", stages.StageCreateView.as_view(), name="stage-create"),
|
||||||
path(
|
path(
|
||||||
"stages/<uuid:pk>/update/",
|
"stages/<uuid:pk>/update/",
|
||||||
|
|
|
@ -4,38 +4,18 @@ from django.contrib.auth.mixins import (
|
||||||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||||
)
|
)
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
from guardian.mixins import PermissionRequiredMixin
|
||||||
|
|
||||||
from authentik.admin.views.utils import (
|
from authentik.admin.views.utils import (
|
||||||
BackSuccessUrlMixin,
|
BackSuccessUrlMixin,
|
||||||
DeleteMessageView,
|
DeleteMessageView,
|
||||||
InheritanceCreateView,
|
InheritanceCreateView,
|
||||||
InheritanceListView,
|
|
||||||
InheritanceUpdateView,
|
InheritanceUpdateView,
|
||||||
SearchListMixin,
|
|
||||||
UserPaginateListMixin,
|
|
||||||
)
|
)
|
||||||
from authentik.flows.models import Stage
|
from authentik.flows.models import Stage
|
||||||
|
|
||||||
|
|
||||||
class StageListView(
|
|
||||||
LoginRequiredMixin,
|
|
||||||
PermissionListMixin,
|
|
||||||
UserPaginateListMixin,
|
|
||||||
SearchListMixin,
|
|
||||||
InheritanceListView,
|
|
||||||
):
|
|
||||||
"""Show list of all stages"""
|
|
||||||
|
|
||||||
model = Stage
|
|
||||||
template_name = "administration/stage/list.html"
|
|
||||||
permission_required = "authentik_flows.view_stage"
|
|
||||||
ordering = "name"
|
|
||||||
search_fields = ["name"]
|
|
||||||
|
|
||||||
|
|
||||||
class StageCreateView(
|
class StageCreateView(
|
||||||
SuccessMessageMixin,
|
SuccessMessageMixin,
|
||||||
BackSuccessUrlMixin,
|
BackSuccessUrlMixin,
|
||||||
|
@ -49,7 +29,7 @@ class StageCreateView(
|
||||||
template_name = "generic/create.html"
|
template_name = "generic/create.html"
|
||||||
permission_required = "authentik_flows.add_stage"
|
permission_required = "authentik_flows.add_stage"
|
||||||
|
|
||||||
success_url = reverse_lazy("authentik_admin:stages")
|
success_url = "/"
|
||||||
success_message = _("Successfully created Stage")
|
success_message = _("Successfully created Stage")
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +45,7 @@ class StageUpdateView(
|
||||||
model = Stage
|
model = Stage
|
||||||
permission_required = "authentik_flows.update_application"
|
permission_required = "authentik_flows.update_application"
|
||||||
template_name = "generic/update.html"
|
template_name = "generic/update.html"
|
||||||
success_url = reverse_lazy("authentik_admin:stages")
|
success_url = "/"
|
||||||
success_message = _("Successfully updated Stage")
|
success_message = _("Successfully updated Stage")
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,5 +55,5 @@ class StageDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessage
|
||||||
model = Stage
|
model = Stage
|
||||||
template_name = "generic/delete.html"
|
template_name = "generic/delete.html"
|
||||||
permission_required = "authentik_flows.delete_stage"
|
permission_required = "authentik_flows.delete_stage"
|
||||||
success_url = reverse_lazy("authentik_admin:stages")
|
success_url = "/"
|
||||||
success_message = _("Successfully deleted Stage")
|
success_message = _("Successfully deleted Stage")
|
||||||
|
|
|
@ -8,8 +8,8 @@ from rest_framework.serializers import ModelSerializer, SerializerMethodField
|
||||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||||
|
|
||||||
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
|
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
|
||||||
|
from authentik.flows.api.flows import FlowSerializer
|
||||||
from authentik.flows.models import Stage
|
from authentik.flows.models import Stage
|
||||||
from authentik.flows.planner import cache_key
|
|
||||||
from authentik.lib.templatetags.authentik_utils import verbose_name
|
from authentik.lib.templatetags.authentik_utils import verbose_name
|
||||||
from authentik.lib.utils.reflection import all_subclasses
|
from authentik.lib.utils.reflection import all_subclasses
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ class StageSerializer(ModelSerializer, MetaNameSerializer):
|
||||||
"""Stage Serializer"""
|
"""Stage Serializer"""
|
||||||
|
|
||||||
object_type = SerializerMethodField()
|
object_type = SerializerMethodField()
|
||||||
|
flow_set = FlowSerializer(many=True)
|
||||||
|
|
||||||
def get_object_type(self, obj: Stage) -> str:
|
def get_object_type(self, obj: Stage) -> str:
|
||||||
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
||||||
|
@ -26,13 +27,20 @@ class StageSerializer(ModelSerializer, MetaNameSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = Stage
|
model = Stage
|
||||||
fields = ["pk", "name", "object_type", "verbose_name", "verbose_name_plural"]
|
fields = [
|
||||||
|
"pk",
|
||||||
|
"name",
|
||||||
|
"object_type",
|
||||||
|
"verbose_name",
|
||||||
|
"verbose_name_plural",
|
||||||
|
"flow_set",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class StageViewSet(ReadOnlyModelViewSet):
|
class StageViewSet(ReadOnlyModelViewSet):
|
||||||
"""Stage Viewset"""
|
"""Stage Viewset"""
|
||||||
|
|
||||||
queryset = Stage.objects.all()
|
queryset = Stage.objects.all().select_related("flow_set")
|
||||||
serializer_class = StageSerializer
|
serializer_class = StageSerializer
|
||||||
search_fields = ["name"]
|
search_fields = ["name"]
|
||||||
filterset_fields = ["name"]
|
filterset_fields = ["name"]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
import { DefaultClient, AKResponse, QueryArguments, BaseInheritanceModel } from "./Client";
|
||||||
import { TypeCreate } from "./Providers";
|
import { TypeCreate } from "./Providers";
|
||||||
|
|
||||||
export enum FlowDesignation {
|
export enum FlowDesignation {
|
||||||
|
@ -49,16 +49,26 @@ export class Flow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Stage {
|
export class Stage implements BaseInheritanceModel {
|
||||||
pk: string;
|
pk: string;
|
||||||
name: string;
|
name: string;
|
||||||
__type__: string;
|
object_type: string;
|
||||||
verbose_name: string;
|
verbose_name: string;
|
||||||
|
verbose_name_plural: string;
|
||||||
|
flow_set: Flow[];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
throw Error();
|
throw Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get(slug: string): Promise<Stage> {
|
||||||
|
return DefaultClient.fetch<Stage>(["stages", "all", slug]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static list(filter?: QueryArguments): Promise<AKResponse<Stage>> {
|
||||||
|
return DefaultClient.fetch<AKResponse<Stage>>(["stages", "all"], filter);
|
||||||
|
}
|
||||||
|
|
||||||
static getTypes(): Promise<TypeCreate[]> {
|
static getTypes(): Promise<TypeCreate[]> {
|
||||||
return DefaultClient.fetch<TypeCreate[]>(["stages", "all", "types"]);
|
return DefaultClient.fetch<TypeCreate[]>(["stages", "all", "types"]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,37 +20,37 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
||||||
return User.me().then(u => u.is_superuser);
|
return User.me().then(u => u.is_superuser);
|
||||||
}),
|
}),
|
||||||
new SidebarItem("Resources").children(
|
new SidebarItem("Resources").children(
|
||||||
new SidebarItem("Applications", "/applications").activeWhen(
|
new SidebarItem("Applications", "/core/applications").activeWhen(
|
||||||
`^/applications/(?<slug>${SLUG_REGEX})$`
|
`^/core/applications/(?<slug>${SLUG_REGEX})$`
|
||||||
),
|
),
|
||||||
new SidebarItem("Sources", "/sources").activeWhen(
|
new SidebarItem("Sources", "/core/sources").activeWhen(
|
||||||
`^/sources/(?<slug>${SLUG_REGEX})$`,
|
`^/core/sources/(?<slug>${SLUG_REGEX})$`,
|
||||||
),
|
),
|
||||||
new SidebarItem("Providers", "/providers"),
|
new SidebarItem("Providers", "/core/providers"),
|
||||||
new SidebarItem("Outposts", "/outposts"),
|
new SidebarItem("Outposts", "/outpost/outposts"),
|
||||||
new SidebarItem("Outpost Service Connections", "/outpost-service-connections"),
|
new SidebarItem("Outpost Service Connections", "/outpost/service-connections"),
|
||||||
).when((): Promise<boolean> => {
|
).when((): Promise<boolean> => {
|
||||||
return User.me().then(u => u.is_superuser);
|
return User.me().then(u => u.is_superuser);
|
||||||
}),
|
}),
|
||||||
new SidebarItem("Customisation").children(
|
new SidebarItem("Customisation").children(
|
||||||
new SidebarItem("Policies", "/policies"),
|
new SidebarItem("Policies", "/policy/policies"),
|
||||||
new SidebarItem("Property Mappings", "/property-mappings"),
|
new SidebarItem("Property Mappings", "/core/property-mappings"),
|
||||||
).when((): Promise<boolean> => {
|
).when((): Promise<boolean> => {
|
||||||
return User.me().then(u => u.is_superuser);
|
return User.me().then(u => u.is_superuser);
|
||||||
}),
|
}),
|
||||||
new SidebarItem("Flows").children(
|
new SidebarItem("Flows").children(
|
||||||
new SidebarItem("Flows", "/flows").activeWhen(`^/flows/(?<slug>${SLUG_REGEX})$`),
|
new SidebarItem("Flows", "/flow/flows").activeWhen(`^/flow/flows/(?<slug>${SLUG_REGEX})$`),
|
||||||
new SidebarItem("Stages", "/administration/stages/"),
|
new SidebarItem("Stages", "/flow/stages"),
|
||||||
new SidebarItem("Prompts", "/administration/stages_prompts/"),
|
new SidebarItem("Prompts", "/administration/stages_prompts/"),
|
||||||
new SidebarItem("Invitations", "/administration/stages/invitations/"),
|
new SidebarItem("Invitations", "/administration/stages/invitations/"),
|
||||||
).when((): Promise<boolean> => {
|
).when((): Promise<boolean> => {
|
||||||
return User.me().then(u => u.is_superuser);
|
return User.me().then(u => u.is_superuser);
|
||||||
}),
|
}),
|
||||||
new SidebarItem("Identity & Cryptography").children(
|
new SidebarItem("Identity & Cryptography").children(
|
||||||
new SidebarItem("User", "/users"),
|
new SidebarItem("User", "/identity/users"),
|
||||||
new SidebarItem("Groups", "/groups"),
|
new SidebarItem("Groups", "/identity/groups"),
|
||||||
new SidebarItem("Certificates", "/crypto/certificates"),
|
new SidebarItem("Certificates", "/crypto/certificates"),
|
||||||
new SidebarItem("Tokens", "/tokens"),
|
new SidebarItem("Tokens", "/core/tokens"),
|
||||||
).when((): Promise<boolean> => {
|
).when((): Promise<boolean> => {
|
||||||
return User.me().then(u => u.is_superuser);
|
return User.me().then(u => u.is_superuser);
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -36,7 +36,7 @@ export class AdminOverviewPage extends LitElement {
|
||||||
<ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Apps with most usage" style="grid-column-end: span 2;grid-row-end: span 3;">
|
<ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Apps with most usage" style="grid-column-end: span 2;grid-row-end: span 3;">
|
||||||
<ak-top-applications-table></ak-top-applications-table>
|
<ak-top-applications-table></ak-top-applications-table>
|
||||||
</ak-aggregate-card>
|
</ak-aggregate-card>
|
||||||
<ak-admin-status-card-provider class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/providers/">
|
<ak-admin-status-card-provider class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/core/providers/">
|
||||||
</ak-admin-status-card-provider>
|
</ak-admin-status-card-provider>
|
||||||
<ak-admin-status-card-policy-unbound class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-infrastructure" header="Policies" headerLink="#/administration/policies/">
|
<ak-admin-status-card-policy-unbound class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-infrastructure" header="Policies" headerLink="#/administration/policies/">
|
||||||
</ak-admin-status-card-policy-unbound>
|
</ak-admin-status-card-policy-unbound>
|
||||||
|
|
|
@ -50,7 +50,7 @@ export class ApplicationListPage extends TablePage<Application> {
|
||||||
item.meta_icon ?
|
item.meta_icon ?
|
||||||
html`<img class="app-icon pf-c-avatar" src="${item.meta_icon}" alt="${gettext("Application Icon")}">` :
|
html`<img class="app-icon pf-c-avatar" src="${item.meta_icon}" alt="${gettext("Application Icon")}">` :
|
||||||
html`<i class="pf-icon pf-icon-arrow"></i>`,
|
html`<i class="pf-icon pf-icon-arrow"></i>`,
|
||||||
html`<a href="#/applications/${item.slug}">
|
html`<a href="#/core/applications/${item.slug}">
|
||||||
<div>
|
<div>
|
||||||
${item.name}
|
${item.name}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -80,7 +80,7 @@ export class ApplicationViewPage extends LitElement {
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="pf-c-description-list__description">
|
<dd class="pf-c-description-list__description">
|
||||||
<div class="pf-c-description-list__text">
|
<div class="pf-c-description-list__text">
|
||||||
<a href="#/providers/${this.application.provider.pk}">
|
<a href="#/core/providers/${this.application.provider.pk}">
|
||||||
${this.application.provider.name}
|
${this.application.provider.name}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -107,7 +107,7 @@ export class EventInfo extends LitElement {
|
||||||
<span>${until(Flow.list({
|
<span>${until(Flow.list({
|
||||||
flow_uuid: this.event.context.flow as string,
|
flow_uuid: this.event.context.flow as string,
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
return html`<a href="#/flows/${resp.results[0].slug}">${resp.results[0].name}</a>`;
|
return html`<a href="#/flow/flows/${resp.results[0].slug}">${resp.results[0].name}</a>`;
|
||||||
}), html`<ak-spinner size=${SpinnerSize.Medium}></ak-spinner>`)}
|
}), html`<ak-spinner size=${SpinnerSize.Medium}></ak-spinner>`)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -47,7 +47,7 @@ export class FlowListPage extends TablePage<Flow> {
|
||||||
|
|
||||||
row(item: Flow): TemplateResult[] {
|
row(item: Flow): TemplateResult[] {
|
||||||
return [
|
return [
|
||||||
html`<a href="#/flows/${item.slug}">
|
html`<a href="#/flow/flows/${item.slug}">
|
||||||
<code>${item.slug}</code>
|
<code>${item.slug}</code>
|
||||||
</a>`,
|
</a>`,
|
||||||
html`${item.name}`,
|
html`${item.name}`,
|
||||||
|
|
|
@ -48,7 +48,7 @@ export class OutpostListPage extends TablePage<Outpost> {
|
||||||
return [
|
return [
|
||||||
html`${item.name}`,
|
html`${item.name}`,
|
||||||
html`<ul>${item.providers_obj.map((p) => {
|
html`<ul>${item.providers_obj.map((p) => {
|
||||||
return html`<li><a href="#/providers/${p.pk}">${p.name}</a></li>`;
|
return html`<li><a href="#/core/providers/${p.pk}">${p.name}</a></li>`;
|
||||||
})}</ul>`,
|
})}</ul>`,
|
||||||
html`<ak-outpost-health outpostId=${item.pk}></ak-outpost-health>`,
|
html`<ak-outpost-health outpostId=${item.pk}></ak-outpost-health>`,
|
||||||
html`
|
html`
|
||||||
|
|
|
@ -47,13 +47,13 @@ export class ProviderListPage extends TablePage<Provider> {
|
||||||
|
|
||||||
row(item: Provider): TemplateResult[] {
|
row(item: Provider): TemplateResult[] {
|
||||||
return [
|
return [
|
||||||
html`<a href="#/providers/${item.pk}">
|
html`<a href="#/core/providers/${item.pk}">
|
||||||
${item.name}
|
${item.name}
|
||||||
</a>`,
|
</a>`,
|
||||||
item.assigned_application_name ?
|
item.assigned_application_name ?
|
||||||
html`<i class="pf-icon pf-icon-ok"></i>
|
html`<i class="pf-icon pf-icon-ok"></i>
|
||||||
${gettext("Assigned to application ")}
|
${gettext("Assigned to application ")}
|
||||||
<a href="#/applications/${item.assigned_application_slug}">${item.assigned_application_name}</a>` :
|
<a href="#/core/applications/${item.assigned_application_slug}">${item.assigned_application_name}</a>` :
|
||||||
html`<i class="pf-icon pf-icon-warning-triangle"></i>
|
html`<i class="pf-icon pf-icon-warning-triangle"></i>
|
||||||
${gettext("Warning: Provider not assigned to any application.")}`,
|
${gettext("Warning: Provider not assigned to any application.")}`,
|
||||||
html`${item.verbose_name}`,
|
html`${item.verbose_name}`,
|
||||||
|
|
|
@ -14,7 +14,7 @@ export class RelatedApplicationButton extends LitElement {
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
if (this.provider?.assigned_application_slug) {
|
if (this.provider?.assigned_application_slug) {
|
||||||
return html`<a href="#/applications/${this.provider.assigned_application_slug}">
|
return html`<a href="#/core/applications/${this.provider.assigned_application_slug}">
|
||||||
${this.provider.assigned_application_name}
|
${this.provider.assigned_application_name}
|
||||||
</a>`;
|
</a>`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ export class SourceListPage extends TablePage<Source> {
|
||||||
|
|
||||||
row(item: Source): TemplateResult[] {
|
row(item: Source): TemplateResult[] {
|
||||||
return [
|
return [
|
||||||
html`<a href="#/sources/${item.slug}">
|
html`<a href="#/core/sources/${item.slug}">
|
||||||
<div>${item.name}</div>
|
<div>${item.name}</div>
|
||||||
${item.enabled ? html`` : html`<small>${gettext("Disabled")}</small>`}
|
${item.enabled ? html`` : html`<small>${gettext("Disabled")}</small>`}
|
||||||
</a>`,
|
</a>`,
|
||||||
|
|
100
web/src/pages/stages/StageListPage.ts
Normal file
100
web/src/pages/stages/StageListPage.ts
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, html, property, TemplateResult } from "lit-element";
|
||||||
|
import { AKResponse } from "../../api/Client";
|
||||||
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
|
import { TablePage } from "../../elements/table/TablePage";
|
||||||
|
|
||||||
|
import "../../elements/buttons/ModalButton";
|
||||||
|
import "../../elements/buttons/SpinnerButton";
|
||||||
|
import "../../elements/buttons/Dropdown";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
|
import { Stage } from "../../api/Flows";
|
||||||
|
|
||||||
|
@customElement("ak-stage-list")
|
||||||
|
export class StageListPage extends TablePage<Stage> {
|
||||||
|
pageTitle(): string {
|
||||||
|
return "Stages";
|
||||||
|
}
|
||||||
|
pageDescription(): string | undefined {
|
||||||
|
return "Stages are single steps of a Flow that a user is guided through.";
|
||||||
|
}
|
||||||
|
pageIcon(): string {
|
||||||
|
return "pf-icon pf-icon-plugged";
|
||||||
|
}
|
||||||
|
searchEnabled(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property()
|
||||||
|
order = "name";
|
||||||
|
|
||||||
|
apiEndpoint(page: number): Promise<AKResponse<Stage>> {
|
||||||
|
return Stage.list({
|
||||||
|
ordering: this.order,
|
||||||
|
page: page,
|
||||||
|
search: this.search || "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
columns(): TableColumn[] {
|
||||||
|
return [
|
||||||
|
new TableColumn("Name", "name"),
|
||||||
|
new TableColumn("Flows"),
|
||||||
|
new TableColumn(""),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
row(item: Stage): TemplateResult[] {
|
||||||
|
return [
|
||||||
|
html`<div>
|
||||||
|
<div>${item.name}</div>
|
||||||
|
<small>${item.verbose_name}</small>
|
||||||
|
</div>`,
|
||||||
|
html`${item.flow_set.map((flow) => {
|
||||||
|
return html`<a href="#/flow/flows/${flow.slug}">
|
||||||
|
<code>${flow.slug}</code>
|
||||||
|
</a>`;
|
||||||
|
})}`,
|
||||||
|
html`
|
||||||
|
<ak-modal-button href="${Stage.adminUrl(`${item.pk}/update/`)}">
|
||||||
|
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||||
|
${gettext("Edit")}
|
||||||
|
</ak-spinner-button>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>
|
||||||
|
<ak-modal-button href="${Stage.adminUrl(`${item.pk}/delete/`)}">
|
||||||
|
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||||
|
${gettext("Delete")}
|
||||||
|
</ak-spinner-button>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
renderToolbar(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<ak-dropdown class="pf-c-dropdown">
|
||||||
|
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||||
|
<span class="pf-c-dropdown__toggle-text">${gettext("Create")}</span>
|
||||||
|
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<ul class="pf-c-dropdown__menu" hidden>
|
||||||
|
${until(Stage.getTypes().then((types) => {
|
||||||
|
return types.map((type) => {
|
||||||
|
return html`<li>
|
||||||
|
<ak-modal-button href="${type.link}">
|
||||||
|
<button slot="trigger" class="pf-c-dropdown__menu-item">${type.name}<br>
|
||||||
|
<small>${type.description}</small>
|
||||||
|
</button>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>
|
||||||
|
</li>`;
|
||||||
|
});
|
||||||
|
}), html`<ak-spinner></ak-spinner>`)}
|
||||||
|
</ul>
|
||||||
|
</ak-dropdown>
|
||||||
|
${super.renderToolbar()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import "./pages/events/RuleListPage";
|
||||||
import "./pages/events/TransportListPage";
|
import "./pages/events/TransportListPage";
|
||||||
import "./pages/flows/FlowListPage";
|
import "./pages/flows/FlowListPage";
|
||||||
import "./pages/flows/FlowViewPage";
|
import "./pages/flows/FlowViewPage";
|
||||||
|
import "./pages/groups/GroupListPage";
|
||||||
import "./pages/LibraryPage";
|
import "./pages/LibraryPage";
|
||||||
import "./pages/outposts/OutpostListPage";
|
import "./pages/outposts/OutpostListPage";
|
||||||
import "./pages/outposts/OutpostServiceConnectionListPage";
|
import "./pages/outposts/OutpostServiceConnectionListPage";
|
||||||
|
@ -20,10 +21,10 @@ import "./pages/providers/ProviderListPage";
|
||||||
import "./pages/providers/ProviderViewPage";
|
import "./pages/providers/ProviderViewPage";
|
||||||
import "./pages/sources/SourcesListPage";
|
import "./pages/sources/SourcesListPage";
|
||||||
import "./pages/sources/SourceViewPage";
|
import "./pages/sources/SourceViewPage";
|
||||||
import "./pages/groups/GroupListPage";
|
import "./pages/stages/StageListPage";
|
||||||
import "./pages/users/UserListPage";
|
|
||||||
import "./pages/tokens/TokenListPage";
|
|
||||||
import "./pages/system-tasks/SystemTaskListPage";
|
import "./pages/system-tasks/SystemTaskListPage";
|
||||||
|
import "./pages/tokens/TokenListPage";
|
||||||
|
import "./pages/users/UserListPage";
|
||||||
|
|
||||||
export const ROUTES: Route[] = [
|
export const ROUTES: Route[] = [
|
||||||
// Prevent infinite Shell loops
|
// Prevent infinite Shell loops
|
||||||
|
@ -32,24 +33,25 @@ export const ROUTES: Route[] = [
|
||||||
new Route(new RegExp("^/library$"), html`<ak-library></ak-library>`),
|
new Route(new RegExp("^/library$"), html`<ak-library></ak-library>`),
|
||||||
new Route(new RegExp("^/administration/overview$"), html`<ak-admin-overview></ak-admin-overview>`),
|
new Route(new RegExp("^/administration/overview$"), html`<ak-admin-overview></ak-admin-overview>`),
|
||||||
new Route(new RegExp("^/administration/system-tasks$"), html`<ak-system-task-list></ak-system-task-list>`),
|
new Route(new RegExp("^/administration/system-tasks$"), html`<ak-system-task-list></ak-system-task-list>`),
|
||||||
new Route(new RegExp("^/providers$"), html`<ak-provider-list></ak-provider-list>`),
|
new Route(new RegExp("^/core/providers$"), html`<ak-provider-list></ak-provider-list>`),
|
||||||
new Route(new RegExp(`^/providers/(?<id>${ID_REGEX})$`)).then((args) => {
|
new Route(new RegExp(`^/core/providers/(?<id>${ID_REGEX})$`)).then((args) => {
|
||||||
return html`<ak-provider-view .providerID=${parseInt(args.id, 10)}></ak-provider-view>`;
|
return html`<ak-provider-view .providerID=${parseInt(args.id, 10)}></ak-provider-view>`;
|
||||||
}),
|
}),
|
||||||
new Route(new RegExp("^/applications$"), html`<ak-application-list></ak-application-list>`),
|
new Route(new RegExp("^/core/applications$"), html`<ak-application-list></ak-application-list>`),
|
||||||
new Route(new RegExp(`^/applications/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
new Route(new RegExp(`^/core/applications/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
||||||
return html`<ak-application-view .args=${args}></ak-application-view>`;
|
return html`<ak-application-view .args=${args}></ak-application-view>`;
|
||||||
}),
|
}),
|
||||||
new Route(new RegExp("^/sources$"), html`<ak-source-list></ak-source-list>`),
|
new Route(new RegExp("^/core/sources$"), html`<ak-source-list></ak-source-list>`),
|
||||||
new Route(new RegExp(`^/sources/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
new Route(new RegExp(`^/core/sources/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
||||||
return html`<ak-source-view .args=${args}></ak-source-view>`;
|
return html`<ak-source-view .args=${args}></ak-source-view>`;
|
||||||
}),
|
}),
|
||||||
new Route(new RegExp("^/policies$"), html`<ak-policy-list></ak-policy-list>`),
|
new Route(new RegExp("^/policy/policies$"), html`<ak-policy-list></ak-policy-list>`),
|
||||||
new Route(new RegExp("^/groups$"), html`<ak-group-list></ak-group-list>`),
|
new Route(new RegExp("^/identity/groups$"), html`<ak-group-list></ak-group-list>`),
|
||||||
new Route(new RegExp("^/users$"), html`<ak-user-list></ak-user-list>`),
|
new Route(new RegExp("^/identity/users$"), html`<ak-user-list></ak-user-list>`),
|
||||||
new Route(new RegExp("^/flows$"), html`<ak-flow-list></ak-flow-list>`),
|
new Route(new RegExp("^/core/tokens$"), html`<ak-token-list></ak-token-list>`),
|
||||||
new Route(new RegExp("^/tokens$"), html`<ak-token-list></ak-token-list>`),
|
new Route(new RegExp("^/flow/stages$"), html`<ak-stage-list></ak-stage-list>`),
|
||||||
new Route(new RegExp(`^/flows/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
new Route(new RegExp("^/flow/flows$"), html`<ak-flow-list></ak-flow-list>`),
|
||||||
|
new Route(new RegExp(`^/flow/flows/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
||||||
return html`<ak-flow-view .flowSlug=${args.slug}></ak-flow-view>`;
|
return html`<ak-flow-view .flowSlug=${args.slug}></ak-flow-view>`;
|
||||||
}),
|
}),
|
||||||
new Route(new RegExp("^/events/log$"), html`<ak-event-list></ak-event-list>`),
|
new Route(new RegExp("^/events/log$"), html`<ak-event-list></ak-event-list>`),
|
||||||
|
@ -58,8 +60,8 @@ export const ROUTES: Route[] = [
|
||||||
}),
|
}),
|
||||||
new Route(new RegExp("^/events/transports$"), html`<ak-event-transport-list></ak-event-transport-list>`),
|
new Route(new RegExp("^/events/transports$"), html`<ak-event-transport-list></ak-event-transport-list>`),
|
||||||
new Route(new RegExp("^/events/rules$"), html`<ak-event-rule-list></ak-event-rule-list>`),
|
new Route(new RegExp("^/events/rules$"), html`<ak-event-rule-list></ak-event-rule-list>`),
|
||||||
new Route(new RegExp("^/property-mappings$"), html`<ak-property-mapping-list></ak-property-mapping-list>`),
|
new Route(new RegExp("^/core/property-mappings$"), html`<ak-property-mapping-list></ak-property-mapping-list>`),
|
||||||
new Route(new RegExp("^/outposts$"), html`<ak-outpost-list></ak-outpost-list>`),
|
new Route(new RegExp("^/outpost/outposts$"), html`<ak-outpost-list></ak-outpost-list>`),
|
||||||
new Route(new RegExp("^/outpost-service-connections$"), html`<ak-outpost-service-connection-list></ak-outpost-service-connection-list>`),
|
new Route(new RegExp("^/outpost/service-connections$"), html`<ak-outpost-service-connection-list></ak-outpost-service-connection-list>`),
|
||||||
new Route(new RegExp("^/crypto/certificates$"), html`<ak-crypto-certificatekeypair-list></ak-crypto-certificatekeypair-list>`),
|
new Route(new RegExp("^/crypto/certificates$"), html`<ak-crypto-certificatekeypair-list></ak-crypto-certificatekeypair-list>`),
|
||||||
];
|
];
|
||||||
|
|
Reference in a new issue