@mintplayer/ng-spark 22.33.0 → 22.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/mintplayer-ng-spark-auth-account.mjs +576 -2
- package/fesm2022/mintplayer-ng-spark-auth-account.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-auth-core.mjs +24 -0
- package/fesm2022/mintplayer-ng-spark-auth-core.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-auth-models.mjs +4 -1
- package/fesm2022/mintplayer-ng-spark-auth-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-auth-register.mjs +18 -5
- package/fesm2022/mintplayer-ng-spark-auth-register.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-auth-routes.mjs +22 -1
- package/fesm2022/mintplayer-ng-spark-auth-routes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-dashboards.mjs +726 -0
- package/fesm2022/mintplayer-ng-spark-dashboards.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-panels.mjs +9 -1
- package/fesm2022/mintplayer-ng-spark-panels.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +10 -3
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/package.json +5 -1
- package/types/mintplayer-ng-spark-auth-account.d.ts +56 -1
- package/types/mintplayer-ng-spark-auth-core.d.ts +11 -1
- package/types/mintplayer-ng-spark-auth-models.d.ts +96 -1
- package/types/mintplayer-ng-spark-auth-register.d.ts +13 -0
- package/types/mintplayer-ng-spark-auth-routes.d.ts +15 -0
- package/types/mintplayer-ng-spark-dashboards.d.ts +226 -0
- package/types/mintplayer-ng-spark-panels.d.ts +16 -0
- package/types/mintplayer-ng-spark-po-detail.d.ts +3 -0
|
@@ -4,7 +4,7 @@ import { Router, RouterLink } from "@angular/router";
|
|
|
4
4
|
import { BsCardComponent, BsCardHeaderComponent } from "@mintplayer/ng-bootstrap/card";
|
|
5
5
|
import { SparkAuthService, SparkAuthTranslationService } from "@mintplayer/ng-spark/auth/core";
|
|
6
6
|
import { currentLanguage } from "@mintplayer/ng-spark/models";
|
|
7
|
-
import { SPARK_ACCOUNT_OVERVIEW_LINKS, SPARK_ACCOUNT_PROFILE_FIELDS, SPARK_AUTH_CONFIG, SPARK_AUTH_ROUTE_PATHS, SPARK_EXTERNAL_PROVIDERS, passkeysSupported } from "@mintplayer/ng-spark/auth/models";
|
|
7
|
+
import { SPARK_ACCOUNT_OVERVIEW_LINKS, SPARK_ACCOUNT_PROFILE_FIELDS, SPARK_AUTH_CONFIG, SPARK_AUTH_ROUTE_PATHS, SPARK_EXTERNAL_PROVIDERS, passkeysSupported, sparkAgentCanWrite } from "@mintplayer/ng-spark/auth/models";
|
|
8
8
|
import { TranslateKeyPipe } from "@mintplayer/ng-spark/auth/pipes";
|
|
9
9
|
import { HttpClient } from "@angular/common/http";
|
|
10
10
|
import * as i1 from "@angular/forms";
|
|
@@ -17,6 +17,8 @@ import { BsFormComponent, BsFormControlDirective } from "@mintplayer/ng-bootstra
|
|
|
17
17
|
import { BsInputGroupComponent } from "@mintplayer/ng-bootstrap/input-group";
|
|
18
18
|
import { BsSelectComponent, BsSelectOption, BsSelectValueAccessor } from "@mintplayer/ng-bootstrap/select";
|
|
19
19
|
import { BsSpinnerComponent } from "@mintplayer/ng-bootstrap/spinner";
|
|
20
|
+
import { NgTemplateOutlet } from "@angular/common";
|
|
21
|
+
import { BsBadgeComponent } from "@mintplayer/ng-bootstrap/badge";
|
|
20
22
|
function accountMessages(result) {
|
|
21
23
|
if (result.success) return [];
|
|
22
24
|
if (result.errors) {
|
|
@@ -2018,6 +2020,578 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
2018
2020
|
}]
|
|
2019
2021
|
}]
|
|
2020
2022
|
});
|
|
2021
|
-
|
|
2023
|
+
var SparkConnectedAgentsComponent = class SparkConnectedAgentsComponent {
|
|
2024
|
+
auth = inject(SparkAuthService);
|
|
2025
|
+
translation = inject(SparkAuthTranslationService);
|
|
2026
|
+
colors = Color;
|
|
2027
|
+
loading = signal(true, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
|
|
2028
|
+
busy = signal(false, ...ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []);
|
|
2029
|
+
overview = signal(null, ...ngDevMode ? [{ debugName: "overview" }] : /* istanbul ignore next */ []);
|
|
2030
|
+
messages = signal([], ...ngDevMode ? [{ debugName: "messages" }] : /* istanbul ignore next */ []);
|
|
2031
|
+
editing = signal(null, ...ngDevMode ? [{ debugName: "editing" }] : /* istanbul ignore next */ []);
|
|
2032
|
+
creating = signal(false, ...ngDevMode ? [{ debugName: "creating" }] : /* istanbul ignore next */ []);
|
|
2033
|
+
draft = signal({
|
|
2034
|
+
changes: false,
|
|
2035
|
+
types: null
|
|
2036
|
+
}, ...ngDevMode ? [{ debugName: "draft" }] : /* istanbul ignore next */ []);
|
|
2037
|
+
tokenName = signal("", ...ngDevMode ? [{ debugName: "tokenName" }] : /* istanbul ignore next */ []);
|
|
2038
|
+
tokenDays = signal(90, ...ngDevMode ? [{ debugName: "tokenDays" }] : /* istanbul ignore next */ []);
|
|
2039
|
+
createdToken = signal(null, ...ngDevMode ? [{ debugName: "createdToken" }] : /* istanbul ignore next */ []);
|
|
2040
|
+
draftValid = computed(() => this.draft().types === null || this.draft().types.length > 0, ...ngDevMode ? [{ debugName: "draftValid" }] : /* istanbul ignore next */ []);
|
|
2041
|
+
tokenValid = computed(() => {
|
|
2042
|
+
const max = this.overview()?.maxTokenLifetimeDays ?? 365;
|
|
2043
|
+
const days = this.tokenDays();
|
|
2044
|
+
return this.draftValid() && this.tokenName().trim().length > 0 && Number.isInteger(days) && days >= 1 && days <= max;
|
|
2045
|
+
}, ...ngDevMode ? [{ debugName: "tokenValid" }] : /* istanbul ignore next */ []);
|
|
2046
|
+
canWrite = sparkAgentCanWrite;
|
|
2047
|
+
async ngOnInit() {
|
|
2048
|
+
await this.load();
|
|
2049
|
+
}
|
|
2050
|
+
async load() {
|
|
2051
|
+
this.loading.set(true);
|
|
2052
|
+
const result = await this.auth.agentGrants();
|
|
2053
|
+
if (result.success && result.value) this.overview.set(result.value);
|
|
2054
|
+
else {
|
|
2055
|
+
this.overview.set(null);
|
|
2056
|
+
this.messages.set(accountMessages(result));
|
|
2057
|
+
}
|
|
2058
|
+
this.loading.set(false);
|
|
2059
|
+
}
|
|
2060
|
+
edit(grant) {
|
|
2061
|
+
this.creating.set(false);
|
|
2062
|
+
this.messages.set([]);
|
|
2063
|
+
this.draft.set({
|
|
2064
|
+
changes: sparkAgentCanWrite(grant.permissions),
|
|
2065
|
+
types: grant.types?.map((t) => t.name) ?? null
|
|
2066
|
+
});
|
|
2067
|
+
this.editing.set(grant.key);
|
|
2068
|
+
}
|
|
2069
|
+
startToken() {
|
|
2070
|
+
this.editing.set(null);
|
|
2071
|
+
this.messages.set([]);
|
|
2072
|
+
this.createdToken.set(null);
|
|
2073
|
+
this.tokenName.set("");
|
|
2074
|
+
this.tokenDays.set(this.overview()?.defaultTokenLifetimeDays ?? 90);
|
|
2075
|
+
this.draft.set({
|
|
2076
|
+
changes: false,
|
|
2077
|
+
types: null
|
|
2078
|
+
});
|
|
2079
|
+
this.creating.set(true);
|
|
2080
|
+
}
|
|
2081
|
+
setChanges(changes) {
|
|
2082
|
+
this.draft.update((d) => ({
|
|
2083
|
+
...d,
|
|
2084
|
+
changes
|
|
2085
|
+
}));
|
|
2086
|
+
}
|
|
2087
|
+
setEverything(everything) {
|
|
2088
|
+
this.draft.update((d) => ({
|
|
2089
|
+
...d,
|
|
2090
|
+
types: everything ? null : []
|
|
2091
|
+
}));
|
|
2092
|
+
}
|
|
2093
|
+
setType(type, chosen) {
|
|
2094
|
+
this.draft.update((d) => {
|
|
2095
|
+
const types = (d.types ?? []).filter((name) => name !== type.name);
|
|
2096
|
+
return {
|
|
2097
|
+
...d,
|
|
2098
|
+
types: chosen ? [...types, type.name] : types
|
|
2099
|
+
};
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
async save(grant) {
|
|
2103
|
+
const choice = this.draft();
|
|
2104
|
+
await this.run(() => this.auth.updateAgentGrant({
|
|
2105
|
+
key: grant.key,
|
|
2106
|
+
permissions: this.permission(choice),
|
|
2107
|
+
types: this.types(choice)
|
|
2108
|
+
}), () => this.editing.set(null));
|
|
2109
|
+
}
|
|
2110
|
+
async createToken() {
|
|
2111
|
+
const choice = this.draft();
|
|
2112
|
+
this.busy.set(true);
|
|
2113
|
+
this.messages.set([]);
|
|
2114
|
+
try {
|
|
2115
|
+
const result = await this.auth.createAgentToken({
|
|
2116
|
+
name: this.tokenName().trim(),
|
|
2117
|
+
expiresInDays: this.tokenDays(),
|
|
2118
|
+
permissions: this.permission(choice),
|
|
2119
|
+
types: this.types(choice)
|
|
2120
|
+
});
|
|
2121
|
+
if (!result.success || !result.value) {
|
|
2122
|
+
this.messages.set(accountMessages(result));
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
this.creating.set(false);
|
|
2126
|
+
await this.load();
|
|
2127
|
+
this.createdToken.set(result.value.token);
|
|
2128
|
+
} finally {
|
|
2129
|
+
this.busy.set(false);
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
async revoke(grant) {
|
|
2133
|
+
if (!confirm(this.translation.t("auth.agentConfirmRevoke"))) return;
|
|
2134
|
+
await this.run(() => this.auth.revokeAgentGrant(grant.key));
|
|
2135
|
+
}
|
|
2136
|
+
async revokeApplication(app) {
|
|
2137
|
+
if (!confirm(this.translation.t("auth.agentConfirmRevoke"))) return;
|
|
2138
|
+
await this.run(() => this.auth.revokeConnectedApplication(app.source, app.id));
|
|
2139
|
+
}
|
|
2140
|
+
typeLabels(types) {
|
|
2141
|
+
const labels = new Map((this.overview()?.types ?? []).map((t) => [t.name, t.label]));
|
|
2142
|
+
return types.map((t) => labels.get(t.name) ?? t.name).join(", ");
|
|
2143
|
+
}
|
|
2144
|
+
date(iso) {
|
|
2145
|
+
return iso ? new Date(iso).toLocaleDateString() : "";
|
|
2146
|
+
}
|
|
2147
|
+
value(event) {
|
|
2148
|
+
return event.target.value;
|
|
2149
|
+
}
|
|
2150
|
+
copy(token) {
|
|
2151
|
+
navigator.clipboard?.writeText(token);
|
|
2152
|
+
}
|
|
2153
|
+
permission(choice) {
|
|
2154
|
+
return choice.changes ? "Read, Write" : "Read";
|
|
2155
|
+
}
|
|
2156
|
+
types(choice) {
|
|
2157
|
+
if (choice.types === null) return null;
|
|
2158
|
+
const exposed = new Map((this.overview()?.types ?? []).map((t) => [t.name, t]));
|
|
2159
|
+
return choice.types.map((name) => ({
|
|
2160
|
+
name,
|
|
2161
|
+
permissions: choice.changes && sparkAgentCanWrite(exposed.get(name)?.permissions) ? "Read, Write" : "Read"
|
|
2162
|
+
}));
|
|
2163
|
+
}
|
|
2164
|
+
async run(call, after) {
|
|
2165
|
+
this.busy.set(true);
|
|
2166
|
+
this.messages.set([]);
|
|
2167
|
+
try {
|
|
2168
|
+
const result = await call();
|
|
2169
|
+
if (!result.success) {
|
|
2170
|
+
this.messages.set(accountMessages(result));
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
after?.();
|
|
2174
|
+
this.createdToken.set(null);
|
|
2175
|
+
await this.load();
|
|
2176
|
+
} finally {
|
|
2177
|
+
this.busy.set(false);
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
2181
|
+
minVersion: "12.0.0",
|
|
2182
|
+
version: "22.2.2",
|
|
2183
|
+
ngImport: i0,
|
|
2184
|
+
type: SparkConnectedAgentsComponent,
|
|
2185
|
+
deps: [],
|
|
2186
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
2187
|
+
});
|
|
2188
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
2189
|
+
minVersion: "17.0.0",
|
|
2190
|
+
version: "22.2.2",
|
|
2191
|
+
type: SparkConnectedAgentsComponent,
|
|
2192
|
+
isStandalone: true,
|
|
2193
|
+
selector: "spark-connected-agents",
|
|
2194
|
+
ngImport: i0,
|
|
2195
|
+
template: `
|
|
2196
|
+
<div class="d-flex justify-content-center">
|
|
2197
|
+
<bs-card style="width: 100%; max-width: 760px;">
|
|
2198
|
+
<bs-card-header><h3 class="mb-0">{{ 'auth.agentsTitle' | t }}</h3></bs-card-header>
|
|
2199
|
+
<div class="p-4">
|
|
2200
|
+
<p class="text-muted">{{ 'auth.agentsDescription' | t }}</p>
|
|
2201
|
+
@for (message of messages(); track message) {
|
|
2202
|
+
<bs-alert [type]="colors.danger" class="mb-3 d-block spark-agents-error">{{ message | t }}</bs-alert>
|
|
2203
|
+
}
|
|
2204
|
+
@if (loading()) {
|
|
2205
|
+
<div class="text-center"><bs-spinner /></div>
|
|
2206
|
+
} @else if (overview(); as data) {
|
|
2207
|
+
@for (grant of data.grants; track grant.key) {
|
|
2208
|
+
<section class="border rounded p-3 mb-3 spark-agent-grant" [attr.data-key]="grant.key">
|
|
2209
|
+
<div class="d-flex flex-wrap align-items-center gap-2">
|
|
2210
|
+
<h5 class="mb-0 text-break spark-agent-name">{{ grant.name || grant.clientId || grant.key }}</h5>
|
|
2211
|
+
<bs-badge [type]="colors.secondary">{{ 'auth.agentKind.' + grant.kind | t }}</bs-badge>
|
|
2212
|
+
@if (grant.kind === 'ExternalAuthorizationServer') {
|
|
2213
|
+
<bs-badge [type]="colors.info" class="spark-agent-issuer" [title]="'auth.agentIssuer' | t">{{ grant.issuer }}</bs-badge>
|
|
2214
|
+
} @else if (grant.kind !== 'PersonalAccessToken') {
|
|
2215
|
+
@if (grant.verifiedHost) {
|
|
2216
|
+
<bs-badge [type]="colors.success" class="spark-agent-verified">{{ grant.verifiedHost }}</bs-badge>
|
|
2217
|
+
} @else {
|
|
2218
|
+
<bs-badge [type]="colors.warning" class="spark-agent-unverified">{{ 'auth.agentUnverified' | t }}</bs-badge>
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
@if (grant.status !== 'active') {
|
|
2222
|
+
<bs-badge [type]="colors.danger" class="spark-agent-status">{{ 'auth.agentStatus.' + grant.status | t }}</bs-badge>
|
|
2223
|
+
}
|
|
2224
|
+
</div>
|
|
2225
|
+
<small class="text-muted d-block mt-1 spark-agent-dates">
|
|
2226
|
+
{{ 'auth.agentCreated' | t }} {{ date(grant.createdAt) }} ·
|
|
2227
|
+
@if (grant.lastUsedAt) { {{ 'auth.agentLastUsed' | t }} {{ date(grant.lastUsedAt) }} } @else { {{ 'auth.agentNeverUsed' | t }} }
|
|
2228
|
+
@if (grant.expiresAt) { · {{ 'auth.agentExpires' | t }} {{ date(grant.expiresAt) }} }
|
|
2229
|
+
</small>
|
|
2230
|
+
|
|
2231
|
+
@if (editing() === grant.key) {
|
|
2232
|
+
<bs-form class="d-block mt-3">
|
|
2233
|
+
@if (canWrite(grant.maxPermissions)) {
|
|
2234
|
+
<bs-checkbox [type]="'checkbox'" [name]="'changes-' + grant.key" [isToggled]="draft().changes"
|
|
2235
|
+
(isToggledChange)="setChanges($event === true)">{{ 'auth.agentAllowChanges' | t }}</bs-checkbox>
|
|
2236
|
+
}
|
|
2237
|
+
<ng-container *ngTemplateOutlet="typePicker" />
|
|
2238
|
+
</bs-form>
|
|
2239
|
+
<div class="d-flex gap-2 mt-3">
|
|
2240
|
+
<button type="button" class="btn btn-primary btn-sm spark-agent-save" [disabled]="busy() || !draftValid()" (click)="save(grant)">{{ 'auth.agentSave' | t }}</button>
|
|
2241
|
+
<button type="button" class="btn btn-outline-secondary btn-sm" [disabled]="busy()" (click)="editing.set(null)">{{ 'auth.agentCancel' | t }}</button>
|
|
2242
|
+
</div>
|
|
2243
|
+
} @else {
|
|
2244
|
+
<div class="mt-2 spark-agent-scope">
|
|
2245
|
+
<span>{{ (canWrite(grant.permissions) ? 'auth.agentReadAndChanges' : 'auth.agentReadOnly') | t }}</span> ·
|
|
2246
|
+
@if (grant.types === null) {
|
|
2247
|
+
<span>{{ 'auth.agentEverything' | t }}</span>
|
|
2248
|
+
} @else {
|
|
2249
|
+
<span>{{ typeLabels(grant.types) }}</span>
|
|
2250
|
+
}
|
|
2251
|
+
</div>
|
|
2252
|
+
<div class="d-flex flex-wrap gap-2 mt-3">
|
|
2253
|
+
<!-- A disconnected external agent (by the user or a security-stamp change) is allowed again by an edit. -->
|
|
2254
|
+
@if (grant.status === 'active' || grant.status === 'disconnected') {
|
|
2255
|
+
<button type="button" class="btn btn-outline-primary btn-sm spark-agent-edit" [disabled]="busy()" (click)="edit(grant)">{{ 'auth.agentEdit' | t }}</button>
|
|
2256
|
+
}
|
|
2257
|
+
@if (grant.status !== 'disconnected') {
|
|
2258
|
+
<button type="button" class="btn btn-danger btn-sm spark-agent-revoke" [disabled]="busy()" (click)="revoke(grant)">
|
|
2259
|
+
{{ (grant.kind === 'PersonalAccessToken' ? 'auth.agentRevokeToken' : 'auth.agentDisconnect') | t }}
|
|
2260
|
+
</button>
|
|
2261
|
+
}
|
|
2262
|
+
</div>
|
|
2263
|
+
}
|
|
2264
|
+
</section>
|
|
2265
|
+
} @empty {
|
|
2266
|
+
<p class="text-muted spark-agents-empty">{{ 'auth.agentsNone' | t }}</p>
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
@if (data.personalAccessTokens) {
|
|
2270
|
+
<hr class="my-4" />
|
|
2271
|
+
<h5>{{ 'auth.agentTokenTitle' | t }}</h5>
|
|
2272
|
+
<p class="text-muted">{{ 'auth.agentTokenDescription' | t }}</p>
|
|
2273
|
+
@if (createdToken(); as token) {
|
|
2274
|
+
<bs-alert [type]="colors.warning" class="mb-3 d-block spark-agent-token-created">
|
|
2275
|
+
<strong>{{ 'auth.agentTokenShownOnce' | t }}</strong>
|
|
2276
|
+
<code class="d-block text-break my-2 spark-agent-token">{{ token }}</code>
|
|
2277
|
+
<button type="button" class="btn btn-sm btn-outline-dark" (click)="copy(token)">{{ 'auth.agentTokenCopy' | t }}</button>
|
|
2278
|
+
</bs-alert>
|
|
2279
|
+
}
|
|
2280
|
+
@if (creating()) {
|
|
2281
|
+
<bs-form class="d-block">
|
|
2282
|
+
<div class="mb-3">
|
|
2283
|
+
<label for="sparkAgentTokenName" class="form-label">{{ 'auth.agentTokenName' | t }}</label>
|
|
2284
|
+
<input id="sparkAgentTokenName" type="text" maxlength="100" [value]="tokenName()" (input)="tokenName.set(value($event))" />
|
|
2285
|
+
</div>
|
|
2286
|
+
<div class="mb-3">
|
|
2287
|
+
<label for="sparkAgentTokenDays" class="form-label">{{ 'auth.agentTokenDays' | t }}</label>
|
|
2288
|
+
<input id="sparkAgentTokenDays" type="number" min="1" [max]="data.maxTokenLifetimeDays" [value]="tokenDays()" (input)="tokenDays.set(+value($event))" />
|
|
2289
|
+
</div>
|
|
2290
|
+
@if (canWrite(data.tokenPermissions)) {
|
|
2291
|
+
<bs-checkbox [type]="'checkbox'" [name]="'changes-new'" [isToggled]="draft().changes"
|
|
2292
|
+
(isToggledChange)="setChanges($event === true)">{{ 'auth.agentAllowChanges' | t }}</bs-checkbox>
|
|
2293
|
+
}
|
|
2294
|
+
<ng-container *ngTemplateOutlet="typePicker" />
|
|
2295
|
+
</bs-form>
|
|
2296
|
+
<div class="d-flex gap-2 mt-3">
|
|
2297
|
+
<button type="button" class="btn btn-primary spark-agent-token-create" [disabled]="busy() || !tokenValid()" (click)="createToken()">{{ 'auth.agentTokenCreate' | t }}</button>
|
|
2298
|
+
<button type="button" class="btn btn-outline-secondary" [disabled]="busy()" (click)="creating.set(false)">{{ 'auth.agentCancel' | t }}</button>
|
|
2299
|
+
</div>
|
|
2300
|
+
} @else {
|
|
2301
|
+
<button type="button" class="btn btn-outline-primary spark-agent-token-new" [disabled]="busy()" (click)="startToken()">{{ 'auth.agentTokenNew' | t }}</button>
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
@if (data.applications.length) {
|
|
2306
|
+
<hr class="my-4" />
|
|
2307
|
+
<h5>{{ 'auth.agentApplicationsTitle' | t }}</h5>
|
|
2308
|
+
@for (app of data.applications; track app.source + '|' + app.id) {
|
|
2309
|
+
<section class="border rounded p-3 mb-2 d-flex justify-content-between align-items-start gap-2 spark-contributed-app">
|
|
2310
|
+
<div class="text-break">
|
|
2311
|
+
<strong>{{ app.name }}</strong>
|
|
2312
|
+
@if (app.description) { <small class="text-muted d-block">{{ app.description }}</small> }
|
|
2313
|
+
@if (app.lastUsedAt) { <small class="text-muted d-block">{{ 'auth.agentLastUsed' | t }} {{ date(app.lastUsedAt) }}</small> }
|
|
2314
|
+
</div>
|
|
2315
|
+
<button type="button" class="btn btn-danger btn-sm" [disabled]="busy()" (click)="revokeApplication(app)">{{ 'auth.agentDisconnect' | t }}</button>
|
|
2316
|
+
</section>
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
<ng-template #typePicker>
|
|
2322
|
+
<div class="mt-2">
|
|
2323
|
+
<bs-checkbox [type]="'checkbox'" [name]="'everything'" [isToggled]="draft().types === null"
|
|
2324
|
+
(isToggledChange)="setEverything($event === true)">{{ 'auth.agentEverything' | t }}</bs-checkbox>
|
|
2325
|
+
@if (draft().types !== null) {
|
|
2326
|
+
@for (type of overview()?.types ?? []; track type.name) {
|
|
2327
|
+
<div class="ms-4 spark-agent-type" [attr.data-type]="type.name">
|
|
2328
|
+
<bs-checkbox [type]="'checkbox'" [name]="'type-' + type.name" [isToggled]="draft().types!.includes(type.name)"
|
|
2329
|
+
(isToggledChange)="setType(type, $event === true)">{{ type.label }}</bs-checkbox>
|
|
2330
|
+
@if (type.queries.length) { <small class="text-muted d-block ms-4">{{ type.queries.join(', ') }}</small> }
|
|
2331
|
+
</div>
|
|
2332
|
+
} @empty {
|
|
2333
|
+
<small class="text-muted d-block ms-4">{{ 'auth.agentNoTypes' | t }}</small>
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
</div>
|
|
2337
|
+
</ng-template>
|
|
2338
|
+
</div>
|
|
2339
|
+
</bs-card>
|
|
2340
|
+
</div>
|
|
2341
|
+
`,
|
|
2342
|
+
isInline: true,
|
|
2343
|
+
dependencies: [
|
|
2344
|
+
{
|
|
2345
|
+
kind: "component",
|
|
2346
|
+
type: BsAlertComponent,
|
|
2347
|
+
selector: "bs-alert",
|
|
2348
|
+
inputs: [
|
|
2349
|
+
"type",
|
|
2350
|
+
"announce",
|
|
2351
|
+
"isVisible"
|
|
2352
|
+
],
|
|
2353
|
+
outputs: ["isVisibleChange", "afterOpenedOrClosed"]
|
|
2354
|
+
},
|
|
2355
|
+
{
|
|
2356
|
+
kind: "component",
|
|
2357
|
+
type: BsBadgeComponent,
|
|
2358
|
+
selector: "bs-badge",
|
|
2359
|
+
inputs: [
|
|
2360
|
+
"type",
|
|
2361
|
+
"unit",
|
|
2362
|
+
"decorative"
|
|
2363
|
+
]
|
|
2364
|
+
},
|
|
2365
|
+
{
|
|
2366
|
+
kind: "component",
|
|
2367
|
+
type: BsCardComponent,
|
|
2368
|
+
selector: "bs-card",
|
|
2369
|
+
inputs: ["color", "outline"]
|
|
2370
|
+
},
|
|
2371
|
+
{
|
|
2372
|
+
kind: "component",
|
|
2373
|
+
type: BsCardHeaderComponent,
|
|
2374
|
+
selector: "bs-card-header",
|
|
2375
|
+
inputs: ["color", "navStyle"]
|
|
2376
|
+
},
|
|
2377
|
+
{
|
|
2378
|
+
kind: "component",
|
|
2379
|
+
type: BsCheckboxComponent,
|
|
2380
|
+
selector: "bs-checkbox",
|
|
2381
|
+
inputs: [
|
|
2382
|
+
"type",
|
|
2383
|
+
"isToggled",
|
|
2384
|
+
"indeterminate",
|
|
2385
|
+
"name",
|
|
2386
|
+
"value",
|
|
2387
|
+
"group"
|
|
2388
|
+
],
|
|
2389
|
+
outputs: ["isToggledChange", "indeterminateChange"]
|
|
2390
|
+
},
|
|
2391
|
+
{
|
|
2392
|
+
kind: "component",
|
|
2393
|
+
type: BsFormComponent,
|
|
2394
|
+
selector: "bs-form",
|
|
2395
|
+
inputs: ["action", "method"],
|
|
2396
|
+
outputs: ["submitted"]
|
|
2397
|
+
},
|
|
2398
|
+
{
|
|
2399
|
+
kind: "component",
|
|
2400
|
+
type: BsSpinnerComponent,
|
|
2401
|
+
selector: "bs-spinner",
|
|
2402
|
+
inputs: ["type", "color"]
|
|
2403
|
+
},
|
|
2404
|
+
{
|
|
2405
|
+
kind: "directive",
|
|
2406
|
+
type: NgTemplateOutlet,
|
|
2407
|
+
selector: "[ngTemplateOutlet]",
|
|
2408
|
+
inputs: [
|
|
2409
|
+
"ngTemplateOutletContext",
|
|
2410
|
+
"ngTemplateOutlet",
|
|
2411
|
+
"ngTemplateOutletInjector"
|
|
2412
|
+
]
|
|
2413
|
+
},
|
|
2414
|
+
{
|
|
2415
|
+
kind: "pipe",
|
|
2416
|
+
type: TranslateKeyPipe,
|
|
2417
|
+
name: "t"
|
|
2418
|
+
}
|
|
2419
|
+
],
|
|
2420
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
2421
|
+
});
|
|
2422
|
+
};
|
|
2423
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
2424
|
+
minVersion: "12.0.0",
|
|
2425
|
+
version: "22.2.2",
|
|
2426
|
+
ngImport: i0,
|
|
2427
|
+
type: SparkConnectedAgentsComponent,
|
|
2428
|
+
decorators: [{
|
|
2429
|
+
type: Component,
|
|
2430
|
+
args: [{
|
|
2431
|
+
selector: "spark-connected-agents",
|
|
2432
|
+
standalone: true,
|
|
2433
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2434
|
+
imports: [
|
|
2435
|
+
BsAlertComponent,
|
|
2436
|
+
BsBadgeComponent,
|
|
2437
|
+
BsCardComponent,
|
|
2438
|
+
BsCardHeaderComponent,
|
|
2439
|
+
BsCheckboxComponent,
|
|
2440
|
+
BsFormComponent,
|
|
2441
|
+
BsSpinnerComponent,
|
|
2442
|
+
NgTemplateOutlet,
|
|
2443
|
+
TranslateKeyPipe
|
|
2444
|
+
],
|
|
2445
|
+
template: `
|
|
2446
|
+
<div class="d-flex justify-content-center">
|
|
2447
|
+
<bs-card style="width: 100%; max-width: 760px;">
|
|
2448
|
+
<bs-card-header><h3 class="mb-0">{{ 'auth.agentsTitle' | t }}</h3></bs-card-header>
|
|
2449
|
+
<div class="p-4">
|
|
2450
|
+
<p class="text-muted">{{ 'auth.agentsDescription' | t }}</p>
|
|
2451
|
+
@for (message of messages(); track message) {
|
|
2452
|
+
<bs-alert [type]="colors.danger" class="mb-3 d-block spark-agents-error">{{ message | t }}</bs-alert>
|
|
2453
|
+
}
|
|
2454
|
+
@if (loading()) {
|
|
2455
|
+
<div class="text-center"><bs-spinner /></div>
|
|
2456
|
+
} @else if (overview(); as data) {
|
|
2457
|
+
@for (grant of data.grants; track grant.key) {
|
|
2458
|
+
<section class="border rounded p-3 mb-3 spark-agent-grant" [attr.data-key]="grant.key">
|
|
2459
|
+
<div class="d-flex flex-wrap align-items-center gap-2">
|
|
2460
|
+
<h5 class="mb-0 text-break spark-agent-name">{{ grant.name || grant.clientId || grant.key }}</h5>
|
|
2461
|
+
<bs-badge [type]="colors.secondary">{{ 'auth.agentKind.' + grant.kind | t }}</bs-badge>
|
|
2462
|
+
@if (grant.kind === 'ExternalAuthorizationServer') {
|
|
2463
|
+
<bs-badge [type]="colors.info" class="spark-agent-issuer" [title]="'auth.agentIssuer' | t">{{ grant.issuer }}</bs-badge>
|
|
2464
|
+
} @else if (grant.kind !== 'PersonalAccessToken') {
|
|
2465
|
+
@if (grant.verifiedHost) {
|
|
2466
|
+
<bs-badge [type]="colors.success" class="spark-agent-verified">{{ grant.verifiedHost }}</bs-badge>
|
|
2467
|
+
} @else {
|
|
2468
|
+
<bs-badge [type]="colors.warning" class="spark-agent-unverified">{{ 'auth.agentUnverified' | t }}</bs-badge>
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
@if (grant.status !== 'active') {
|
|
2472
|
+
<bs-badge [type]="colors.danger" class="spark-agent-status">{{ 'auth.agentStatus.' + grant.status | t }}</bs-badge>
|
|
2473
|
+
}
|
|
2474
|
+
</div>
|
|
2475
|
+
<small class="text-muted d-block mt-1 spark-agent-dates">
|
|
2476
|
+
{{ 'auth.agentCreated' | t }} {{ date(grant.createdAt) }} ·
|
|
2477
|
+
@if (grant.lastUsedAt) { {{ 'auth.agentLastUsed' | t }} {{ date(grant.lastUsedAt) }} } @else { {{ 'auth.agentNeverUsed' | t }} }
|
|
2478
|
+
@if (grant.expiresAt) { · {{ 'auth.agentExpires' | t }} {{ date(grant.expiresAt) }} }
|
|
2479
|
+
</small>
|
|
2480
|
+
|
|
2481
|
+
@if (editing() === grant.key) {
|
|
2482
|
+
<bs-form class="d-block mt-3">
|
|
2483
|
+
@if (canWrite(grant.maxPermissions)) {
|
|
2484
|
+
<bs-checkbox [type]="'checkbox'" [name]="'changes-' + grant.key" [isToggled]="draft().changes"
|
|
2485
|
+
(isToggledChange)="setChanges($event === true)">{{ 'auth.agentAllowChanges' | t }}</bs-checkbox>
|
|
2486
|
+
}
|
|
2487
|
+
<ng-container *ngTemplateOutlet="typePicker" />
|
|
2488
|
+
</bs-form>
|
|
2489
|
+
<div class="d-flex gap-2 mt-3">
|
|
2490
|
+
<button type="button" class="btn btn-primary btn-sm spark-agent-save" [disabled]="busy() || !draftValid()" (click)="save(grant)">{{ 'auth.agentSave' | t }}</button>
|
|
2491
|
+
<button type="button" class="btn btn-outline-secondary btn-sm" [disabled]="busy()" (click)="editing.set(null)">{{ 'auth.agentCancel' | t }}</button>
|
|
2492
|
+
</div>
|
|
2493
|
+
} @else {
|
|
2494
|
+
<div class="mt-2 spark-agent-scope">
|
|
2495
|
+
<span>{{ (canWrite(grant.permissions) ? 'auth.agentReadAndChanges' : 'auth.agentReadOnly') | t }}</span> ·
|
|
2496
|
+
@if (grant.types === null) {
|
|
2497
|
+
<span>{{ 'auth.agentEverything' | t }}</span>
|
|
2498
|
+
} @else {
|
|
2499
|
+
<span>{{ typeLabels(grant.types) }}</span>
|
|
2500
|
+
}
|
|
2501
|
+
</div>
|
|
2502
|
+
<div class="d-flex flex-wrap gap-2 mt-3">
|
|
2503
|
+
<!-- A disconnected external agent (by the user or a security-stamp change) is allowed again by an edit. -->
|
|
2504
|
+
@if (grant.status === 'active' || grant.status === 'disconnected') {
|
|
2505
|
+
<button type="button" class="btn btn-outline-primary btn-sm spark-agent-edit" [disabled]="busy()" (click)="edit(grant)">{{ 'auth.agentEdit' | t }}</button>
|
|
2506
|
+
}
|
|
2507
|
+
@if (grant.status !== 'disconnected') {
|
|
2508
|
+
<button type="button" class="btn btn-danger btn-sm spark-agent-revoke" [disabled]="busy()" (click)="revoke(grant)">
|
|
2509
|
+
{{ (grant.kind === 'PersonalAccessToken' ? 'auth.agentRevokeToken' : 'auth.agentDisconnect') | t }}
|
|
2510
|
+
</button>
|
|
2511
|
+
}
|
|
2512
|
+
</div>
|
|
2513
|
+
}
|
|
2514
|
+
</section>
|
|
2515
|
+
} @empty {
|
|
2516
|
+
<p class="text-muted spark-agents-empty">{{ 'auth.agentsNone' | t }}</p>
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2519
|
+
@if (data.personalAccessTokens) {
|
|
2520
|
+
<hr class="my-4" />
|
|
2521
|
+
<h5>{{ 'auth.agentTokenTitle' | t }}</h5>
|
|
2522
|
+
<p class="text-muted">{{ 'auth.agentTokenDescription' | t }}</p>
|
|
2523
|
+
@if (createdToken(); as token) {
|
|
2524
|
+
<bs-alert [type]="colors.warning" class="mb-3 d-block spark-agent-token-created">
|
|
2525
|
+
<strong>{{ 'auth.agentTokenShownOnce' | t }}</strong>
|
|
2526
|
+
<code class="d-block text-break my-2 spark-agent-token">{{ token }}</code>
|
|
2527
|
+
<button type="button" class="btn btn-sm btn-outline-dark" (click)="copy(token)">{{ 'auth.agentTokenCopy' | t }}</button>
|
|
2528
|
+
</bs-alert>
|
|
2529
|
+
}
|
|
2530
|
+
@if (creating()) {
|
|
2531
|
+
<bs-form class="d-block">
|
|
2532
|
+
<div class="mb-3">
|
|
2533
|
+
<label for="sparkAgentTokenName" class="form-label">{{ 'auth.agentTokenName' | t }}</label>
|
|
2534
|
+
<input id="sparkAgentTokenName" type="text" maxlength="100" [value]="tokenName()" (input)="tokenName.set(value($event))" />
|
|
2535
|
+
</div>
|
|
2536
|
+
<div class="mb-3">
|
|
2537
|
+
<label for="sparkAgentTokenDays" class="form-label">{{ 'auth.agentTokenDays' | t }}</label>
|
|
2538
|
+
<input id="sparkAgentTokenDays" type="number" min="1" [max]="data.maxTokenLifetimeDays" [value]="tokenDays()" (input)="tokenDays.set(+value($event))" />
|
|
2539
|
+
</div>
|
|
2540
|
+
@if (canWrite(data.tokenPermissions)) {
|
|
2541
|
+
<bs-checkbox [type]="'checkbox'" [name]="'changes-new'" [isToggled]="draft().changes"
|
|
2542
|
+
(isToggledChange)="setChanges($event === true)">{{ 'auth.agentAllowChanges' | t }}</bs-checkbox>
|
|
2543
|
+
}
|
|
2544
|
+
<ng-container *ngTemplateOutlet="typePicker" />
|
|
2545
|
+
</bs-form>
|
|
2546
|
+
<div class="d-flex gap-2 mt-3">
|
|
2547
|
+
<button type="button" class="btn btn-primary spark-agent-token-create" [disabled]="busy() || !tokenValid()" (click)="createToken()">{{ 'auth.agentTokenCreate' | t }}</button>
|
|
2548
|
+
<button type="button" class="btn btn-outline-secondary" [disabled]="busy()" (click)="creating.set(false)">{{ 'auth.agentCancel' | t }}</button>
|
|
2549
|
+
</div>
|
|
2550
|
+
} @else {
|
|
2551
|
+
<button type="button" class="btn btn-outline-primary spark-agent-token-new" [disabled]="busy()" (click)="startToken()">{{ 'auth.agentTokenNew' | t }}</button>
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
@if (data.applications.length) {
|
|
2556
|
+
<hr class="my-4" />
|
|
2557
|
+
<h5>{{ 'auth.agentApplicationsTitle' | t }}</h5>
|
|
2558
|
+
@for (app of data.applications; track app.source + '|' + app.id) {
|
|
2559
|
+
<section class="border rounded p-3 mb-2 d-flex justify-content-between align-items-start gap-2 spark-contributed-app">
|
|
2560
|
+
<div class="text-break">
|
|
2561
|
+
<strong>{{ app.name }}</strong>
|
|
2562
|
+
@if (app.description) { <small class="text-muted d-block">{{ app.description }}</small> }
|
|
2563
|
+
@if (app.lastUsedAt) { <small class="text-muted d-block">{{ 'auth.agentLastUsed' | t }} {{ date(app.lastUsedAt) }}</small> }
|
|
2564
|
+
</div>
|
|
2565
|
+
<button type="button" class="btn btn-danger btn-sm" [disabled]="busy()" (click)="revokeApplication(app)">{{ 'auth.agentDisconnect' | t }}</button>
|
|
2566
|
+
</section>
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
<ng-template #typePicker>
|
|
2572
|
+
<div class="mt-2">
|
|
2573
|
+
<bs-checkbox [type]="'checkbox'" [name]="'everything'" [isToggled]="draft().types === null"
|
|
2574
|
+
(isToggledChange)="setEverything($event === true)">{{ 'auth.agentEverything' | t }}</bs-checkbox>
|
|
2575
|
+
@if (draft().types !== null) {
|
|
2576
|
+
@for (type of overview()?.types ?? []; track type.name) {
|
|
2577
|
+
<div class="ms-4 spark-agent-type" [attr.data-type]="type.name">
|
|
2578
|
+
<bs-checkbox [type]="'checkbox'" [name]="'type-' + type.name" [isToggled]="draft().types!.includes(type.name)"
|
|
2579
|
+
(isToggledChange)="setType(type, $event === true)">{{ type.label }}</bs-checkbox>
|
|
2580
|
+
@if (type.queries.length) { <small class="text-muted d-block ms-4">{{ type.queries.join(', ') }}</small> }
|
|
2581
|
+
</div>
|
|
2582
|
+
} @empty {
|
|
2583
|
+
<small class="text-muted d-block ms-4">{{ 'auth.agentNoTypes' | t }}</small>
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
</div>
|
|
2587
|
+
</ng-template>
|
|
2588
|
+
</div>
|
|
2589
|
+
</bs-card>
|
|
2590
|
+
</div>
|
|
2591
|
+
`
|
|
2592
|
+
}]
|
|
2593
|
+
}]
|
|
2594
|
+
});
|
|
2595
|
+
export { SparkAccountOverviewComponent, SparkAccountProfileComponent, SparkChangePasswordComponent, SparkConnectedAgentsComponent, SparkExternalLoginsComponent, SparkPersonalDataComponent, SparkTwoFactorSetupComponent, accountMessages, fieldMessages };
|
|
2022
2596
|
|
|
2023
2597
|
//# sourceMappingURL=mintplayer-ng-spark-auth-account.mjs.map
|