@atlasauth/angular 0.9.0 → 0.10.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/CHANGELOG.md +6 -0
- package/dist/esm2022/lib/atlas.service.mjs +2 -2
- package/dist/esm2022/lib/atlas.ui.mjs +5 -1
- package/dist/esm2022/lib/components/attempt-flow.component.mjs +37 -5
- package/dist/esm2022/lib/components/flow-controller.mjs +20 -3
- package/dist/esm2022/lib/components/policy-host.mjs +254 -0
- package/dist/esm2022/lib/components/sign-in.component.mjs +4 -2
- package/dist/esm2022/lib/components/sign-up-form.component.mjs +69 -6
- package/dist/esm2022/lib/components/sign-up.component.mjs +7 -3
- package/dist/esm2022/lib/i18n.mjs +4 -1
- package/dist/esm2022/lib/provide-atlas.mjs +3 -2
- package/dist/esm2022/public-api.mjs +3 -1
- package/dist/fesm2022/atlasauth-angular.mjs +384 -15
- package/dist/fesm2022/atlasauth-angular.mjs.map +1 -1
- package/dist/lib/atlas.service.d.ts +1 -0
- package/dist/lib/atlas.ui.d.ts +2 -1
- package/dist/lib/components/attempt-flow.component.d.ts +5 -1
- package/dist/lib/components/flow-controller.d.ts +10 -1
- package/dist/lib/components/policy-host.d.ts +88 -0
- package/dist/lib/components/sign-up-form.component.d.ts +12 -4
- package/dist/lib/provide-atlas.d.ts +2 -1
- package/dist/public-api.d.ts +1 -0
- package/package.json +2 -2
|
@@ -4,7 +4,7 @@ import { isPlatformBrowser, DOCUMENT } from '@angular/common';
|
|
|
4
4
|
import { toSignal } from '@angular/core/rxjs-interop';
|
|
5
5
|
import { BehaviorSubject, Subject, combineLatest, firstValueFrom } from 'rxjs';
|
|
6
6
|
import { map, distinctUntilChanged, filter, take } from 'rxjs/operators';
|
|
7
|
-
import { createOrganizationAuditLog, TokenCache, SignOutNotifier, resolveFrontendApi, withDevBrowser, catalogLocale, configureReferralCapture, FapiClient, SignOutGuard, localizedErrorMessage, reauthenticate, getTemplateToken, getProviderToken, signOutReasonFromClient, readRedirectResult, completeOAuthPopupLanding, mapOAuthPopupPayload, stripRedirectParams, closeOAuthPopupAfterSignIn, SDK_HEADER, sdkHeaderValue, reportSdkAdvisory, readExpiry, msUntilRefresh, groupSetupKey, enrollmentSubmitKey, nextStep, awaitingSignUpLink, canDownloadRecoveryCodes, copyRecoveryCodes, downloadRecoveryCodes, createCaptchaController, atlasCaptchaLabels, flowFromPending, initialFlow, createMfaEnrollment, mfaChoicesFrom, fetchInstanceSettings, fetchLastSignInMethod, offeredFirstFactors, prepareFactor, signInCaptchaOptions, flowNeedsCaptcha, planFirstFactor, advanceWithCaptcha, createSignUp, prepareSecondFactorCode, resendSignUpVerification, createPasskeySignUp, finishPasskeySignUp, pendingRecoveryCodes, acknowledgeRecoveryCodes, shouldKeepPolling, pollAttempt, lastUsedMethodLabel, signUp, passkeysSupported, awaitingPasskey, OrganizationProfileController, describeAuditAction, actorFromClaims } from '@atlasauth/js';
|
|
7
|
+
import { createOrganizationAuditLog, POLICY_STRINGS, TokenCache, SignOutNotifier, resolveFrontendApi, withDevBrowser, catalogLocale, configureReferralCapture, FapiClient, SignOutGuard, localizedErrorMessage, reauthenticate, getTemplateToken, getProviderToken, signOutReasonFromClient, readRedirectResult, completeOAuthPopupLanding, mapOAuthPopupPayload, stripRedirectParams, closeOAuthPopupAfterSignIn, SDK_HEADER, sdkHeaderValue, reportSdkAdvisory, readExpiry, msUntilRefresh, policyTranslator, injectPolicyStyles, mountPolicyClickwrap, mountPolicyConsent, controllerForPending, mountPolicyAcceptStep, joinTitles, formatPolicyDate, PolicyGateController, groupSetupKey, enrollmentSubmitKey, nextStep, awaitingSignUpLink, canDownloadRecoveryCodes, copyRecoveryCodes, downloadRecoveryCodes, createCaptchaController, atlasCaptchaLabels, PolicyAcceptanceController, flowFromPending, initialFlow, createMfaEnrollment, mfaChoicesFrom, fetchInstanceSettings, fetchLastSignInMethod, offeredFirstFactors, prepareFactor, signInCaptchaOptions, flowNeedsCaptcha, planFirstFactor, advanceWithCaptcha, loadPolicies, createSignUp, prepareSecondFactorCode, resendSignUpVerification, createPasskeySignUp, finishPasskeySignUp, pendingRecoveryCodes, acknowledgeRecoveryCodes, shouldKeepPolling, pollAttempt, lastUsedMethodLabel, signUp, confirmPolicies, passkeysSupported, awaitingPasskey, OrganizationProfileController, describeAuditAction, actorFromClaims } from '@atlasauth/js';
|
|
8
8
|
export { FapiClient, SIGN_OUT_EVENT, SignOutError, advance, flowFromPending, getProviderToken, initialFlow, onAtlasSignOut, pollAttempt, prepareFactor, requestForStep, shouldKeepPolling } from '@atlasauth/js';
|
|
9
9
|
import { evaluate } from '@atlasauth/authz';
|
|
10
10
|
export { evaluate, hasFromClaims } from '@atlasauth/authz';
|
|
@@ -327,6 +327,8 @@ const EN_US = {
|
|
|
327
327
|
'impersonation.banner': 'You are signed in as {name} on someone else\'s behalf.',
|
|
328
328
|
'impersonation.returnToAdmin': 'Return to admin',
|
|
329
329
|
'impersonation.end': 'End impersonation',
|
|
330
|
+
// Policy acceptance (terms, privacy, any policy).
|
|
331
|
+
...POLICY_STRINGS,
|
|
330
332
|
'error.generic': 'Something went wrong. Please try again.',
|
|
331
333
|
'error.network': 'We could not reach the server. Check your connection.',
|
|
332
334
|
// Server errors, by the stable `reason` the Frontend API sends. Shown instead
|
|
@@ -804,7 +806,7 @@ class AtlasService {
|
|
|
804
806
|
readPendingAttempt() {
|
|
805
807
|
const result = readRedirectResult(window.location.search);
|
|
806
808
|
return result?.status && !result.ticket
|
|
807
|
-
? { id: result.attemptId, status: result.status }
|
|
809
|
+
? { id: result.attemptId, status: result.status, ...(result.policyToken ? { policyToken: result.policyToken } : {}) }
|
|
808
810
|
: null;
|
|
809
811
|
}
|
|
810
812
|
async call(path, init) {
|
|
@@ -1199,6 +1201,254 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1199
1201
|
args: ['atlasCaptchaSlot']
|
|
1200
1202
|
}] } });
|
|
1201
1203
|
|
|
1204
|
+
/** The policy UI's translator (the localization bundle, else the English policy strings) for the current Atlas service. */
|
|
1205
|
+
function policyUi(atlas) {
|
|
1206
|
+
return {
|
|
1207
|
+
t: policyTranslator((key, vars) => translate(atlas.localization, key, vars)),
|
|
1208
|
+
classes: {
|
|
1209
|
+
link: 'atlas-link',
|
|
1210
|
+
text: 'atlas-text',
|
|
1211
|
+
primaryButton: classFor('formButtonPrimary', atlas.appearance, 'atlas-button'),
|
|
1212
|
+
error: classFor('formFieldError', atlas.appearance, 'atlas-error'),
|
|
1213
|
+
},
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* `[atlasPolicies]="controller"` — draws the instance's policies (terms, privacy,
|
|
1218
|
+
* …) into the host element: `kind="consent"` (default) is the checkbox block with
|
|
1219
|
+
* its in-page viewer, `kind="clickwrap"` the "By continuing you agree to …" line.
|
|
1220
|
+
* The state is the controller's (`AtlasFlowController.policies`); the DOM comes
|
|
1221
|
+
* from `@atlasauth/js`, shared with every SDK.
|
|
1222
|
+
*/
|
|
1223
|
+
class AtlasPoliciesDirective {
|
|
1224
|
+
host = inject(ElementRef);
|
|
1225
|
+
atlas = inject(AtlasService);
|
|
1226
|
+
mounted = null;
|
|
1227
|
+
ready = false;
|
|
1228
|
+
controller = null;
|
|
1229
|
+
atlasPolicyKind = 'consent';
|
|
1230
|
+
ngOnInit() {
|
|
1231
|
+
this.ready = true;
|
|
1232
|
+
this.draw();
|
|
1233
|
+
}
|
|
1234
|
+
ngOnChanges(changes) {
|
|
1235
|
+
if (this.ready && (changes['controller'] || changes['atlasPolicyKind']))
|
|
1236
|
+
this.draw();
|
|
1237
|
+
}
|
|
1238
|
+
ngOnDestroy() {
|
|
1239
|
+
this.mounted?.destroy();
|
|
1240
|
+
}
|
|
1241
|
+
draw() {
|
|
1242
|
+
this.mounted?.destroy();
|
|
1243
|
+
this.mounted = null;
|
|
1244
|
+
if (!this.controller)
|
|
1245
|
+
return;
|
|
1246
|
+
const el = this.host.nativeElement;
|
|
1247
|
+
injectPolicyStyles(el.ownerDocument);
|
|
1248
|
+
const ui = policyUi(this.atlas);
|
|
1249
|
+
this.mounted =
|
|
1250
|
+
this.atlasPolicyKind === 'clickwrap'
|
|
1251
|
+
? mountPolicyClickwrap(el, this.controller, ui)
|
|
1252
|
+
: mountPolicyConsent(el, this.controller, ui);
|
|
1253
|
+
}
|
|
1254
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AtlasPoliciesDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1255
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: AtlasPoliciesDirective, isStandalone: true, selector: "[atlasPolicies]", inputs: { controller: ["atlasPolicies", "controller"], atlasPolicyKind: "atlasPolicyKind" }, usesOnChanges: true, ngImport: i0 });
|
|
1256
|
+
}
|
|
1257
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AtlasPoliciesDirective, decorators: [{
|
|
1258
|
+
type: Directive,
|
|
1259
|
+
args: [{ selector: '[atlasPolicies]', standalone: true }]
|
|
1260
|
+
}], propDecorators: { controller: [{
|
|
1261
|
+
type: Input,
|
|
1262
|
+
args: ['atlasPolicies']
|
|
1263
|
+
}], atlasPolicyKind: [{
|
|
1264
|
+
type: Input
|
|
1265
|
+
}] } });
|
|
1266
|
+
/**
|
|
1267
|
+
* `<atlas-policy-accept-step>` — the sign-in step for a `needs_policy_acceptance`
|
|
1268
|
+
* attempt: scroll-mode policies in their unskippable dialog, the rest as
|
|
1269
|
+
* checkboxes, then "Accept and continue". Emits `submitFlow` with the
|
|
1270
|
+
* `policy_acceptances` JSON for the flow, and `declined` with the policy title
|
|
1271
|
+
* when the user declines (cancel the attempt).
|
|
1272
|
+
*/
|
|
1273
|
+
class PolicyAcceptStepComponent {
|
|
1274
|
+
host = inject(ElementRef);
|
|
1275
|
+
atlas = inject(AtlasService);
|
|
1276
|
+
step = null;
|
|
1277
|
+
alive = true;
|
|
1278
|
+
attempt = null;
|
|
1279
|
+
busy = false;
|
|
1280
|
+
submitFlow = new EventEmitter();
|
|
1281
|
+
declined = new EventEmitter();
|
|
1282
|
+
loading = signal(true);
|
|
1283
|
+
loadingText = policyUi(this.atlas).t('policy.loading');
|
|
1284
|
+
ngOnInit() {
|
|
1285
|
+
const client = this.atlas.createFapiClient();
|
|
1286
|
+
void controllerForPending(client, this.attempt, { locale: this.atlas.locale ?? undefined }).then((controller) => {
|
|
1287
|
+
if (!this.alive)
|
|
1288
|
+
return;
|
|
1289
|
+
this.loading.set(false);
|
|
1290
|
+
const el = this.host.nativeElement.querySelector('.atlas-policy-step-host');
|
|
1291
|
+
if (!el)
|
|
1292
|
+
return;
|
|
1293
|
+
injectPolicyStyles(el.ownerDocument);
|
|
1294
|
+
this.step = mountPolicyAcceptStep(el, controller, {
|
|
1295
|
+
...policyUi(this.atlas),
|
|
1296
|
+
onSubmit: (acceptances) => this.submitFlow.emit({ policy_acceptances: JSON.stringify(acceptances) }),
|
|
1297
|
+
onDecline: (policy) => this.declined.emit(policy.title),
|
|
1298
|
+
});
|
|
1299
|
+
this.step.setBusy(this.busy);
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
ngOnChanges(changes) {
|
|
1303
|
+
if (changes['busy'])
|
|
1304
|
+
this.step?.setBusy(this.busy);
|
|
1305
|
+
}
|
|
1306
|
+
ngOnDestroy() {
|
|
1307
|
+
this.alive = false;
|
|
1308
|
+
this.step?.destroy();
|
|
1309
|
+
}
|
|
1310
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolicyAcceptStepComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1311
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: PolicyAcceptStepComponent, isStandalone: true, selector: "atlas-policy-accept-step", inputs: { attempt: "attempt", busy: "busy" }, outputs: { submitFlow: "submitFlow", declined: "declined" }, usesOnChanges: true, ngImport: i0, template: `@if (loading()) {<p class="atlas-text">{{ loadingText }}</p>}<div class="atlas-policy-step-host"></div>`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1312
|
+
}
|
|
1313
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolicyAcceptStepComponent, decorators: [{
|
|
1314
|
+
type: Component,
|
|
1315
|
+
args: [{
|
|
1316
|
+
selector: 'atlas-policy-accept-step',
|
|
1317
|
+
standalone: true,
|
|
1318
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1319
|
+
template: `@if (loading()) {<p class="atlas-text">{{ loadingText }}</p>}<div class="atlas-policy-step-host"></div>`,
|
|
1320
|
+
}]
|
|
1321
|
+
}], propDecorators: { attempt: [{
|
|
1322
|
+
type: Input
|
|
1323
|
+
}], busy: [{
|
|
1324
|
+
type: Input
|
|
1325
|
+
}], submitFlow: [{
|
|
1326
|
+
type: Output
|
|
1327
|
+
}], declined: [{
|
|
1328
|
+
type: Output
|
|
1329
|
+
}] } });
|
|
1330
|
+
/**
|
|
1331
|
+
* `<atlas-policy-gate>` — in-app re-acceptance. For a signed-in user, a banner
|
|
1332
|
+
* when a policy needs re-acceptance; "Review and accept" opens the unskippable
|
|
1333
|
+
* dialog / checkboxes and posts `/v1/client/me/policies/accept`. Projects its
|
|
1334
|
+
* content always.
|
|
1335
|
+
*/
|
|
1336
|
+
class PolicyGateComponent {
|
|
1337
|
+
host = inject(ElementRef);
|
|
1338
|
+
atlas = inject(AtlasService);
|
|
1339
|
+
ui = policyUi(this.atlas);
|
|
1340
|
+
gate;
|
|
1341
|
+
off = null;
|
|
1342
|
+
step = null;
|
|
1343
|
+
version = signal(0);
|
|
1344
|
+
accepted = new EventEmitter();
|
|
1345
|
+
reviewing = signal(false);
|
|
1346
|
+
error = signal('');
|
|
1347
|
+
title = this.ui.t('policy.bannerTitle');
|
|
1348
|
+
reviewText = this.ui.t('policy.bannerReview');
|
|
1349
|
+
linkClass = this.ui.classes.link ?? '';
|
|
1350
|
+
errorClass = this.ui.classes.error ?? '';
|
|
1351
|
+
bannerClass = 'atlas-policy-banner';
|
|
1352
|
+
cardClass = classFor('card', this.atlas.appearance, 'atlas-card');
|
|
1353
|
+
bannerText() {
|
|
1354
|
+
this.version();
|
|
1355
|
+
if (!this.gate || this.gate.pending.length === 0 || this.reviewing())
|
|
1356
|
+
return null;
|
|
1357
|
+
const t = this.ui.t;
|
|
1358
|
+
const grace = this.gate.graceEndsAt;
|
|
1359
|
+
return (t('policy.bannerBody', { policies: joinTitles(this.gate.pending.map((p) => p.title), t('policy.and')) }) +
|
|
1360
|
+
(grace ? ` ${t('policy.bannerGrace', { date: formatPolicyDate(grace) })}` : ''));
|
|
1361
|
+
}
|
|
1362
|
+
ngOnInit() {
|
|
1363
|
+
this.gate = new PolicyGateController(this.atlas.createFapiClient(), this.atlas.locale ?? undefined);
|
|
1364
|
+
this.off = this.gate.subscribe(() => this.version.update((n) => n + 1));
|
|
1365
|
+
if (this.atlas.status() === 'signed_in')
|
|
1366
|
+
void this.gate.load();
|
|
1367
|
+
}
|
|
1368
|
+
async begin() {
|
|
1369
|
+
const controller = await this.gate.begin();
|
|
1370
|
+
this.reviewing.set(true);
|
|
1371
|
+
await Promise.resolve();
|
|
1372
|
+
const el = this.host.nativeElement.querySelector('.atlas-policy-gate-host');
|
|
1373
|
+
if (!el)
|
|
1374
|
+
return;
|
|
1375
|
+
injectPolicyStyles(el.ownerDocument);
|
|
1376
|
+
this.step = mountPolicyAcceptStep(el, controller, {
|
|
1377
|
+
...this.ui,
|
|
1378
|
+
onSubmit: async () => {
|
|
1379
|
+
this.step?.setBusy(true);
|
|
1380
|
+
const res = await this.gate.accept(controller);
|
|
1381
|
+
this.step?.setBusy(false);
|
|
1382
|
+
if (!res.ok) {
|
|
1383
|
+
this.error.set(res.errors[0]?.message ?? this.ui.t('policy.requiredGeneric'));
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
this.close();
|
|
1387
|
+
this.accepted.emit();
|
|
1388
|
+
},
|
|
1389
|
+
onDecline: () => this.close(),
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
close() {
|
|
1393
|
+
this.step?.destroy();
|
|
1394
|
+
this.step = null;
|
|
1395
|
+
this.reviewing.set(false);
|
|
1396
|
+
}
|
|
1397
|
+
ngOnDestroy() {
|
|
1398
|
+
this.off?.();
|
|
1399
|
+
this.step?.destroy();
|
|
1400
|
+
}
|
|
1401
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolicyGateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1402
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: PolicyGateComponent, isStandalone: true, selector: "atlas-policy-gate", outputs: { accepted: "accepted" }, ngImport: i0, template: `
|
|
1403
|
+
@if (bannerText(); as text) {
|
|
1404
|
+
<div [class]="bannerClass" role="status" data-atlas-policy-banner="">
|
|
1405
|
+
<span
|
|
1406
|
+
><strong>{{ title }}. </strong>{{ text }}</span
|
|
1407
|
+
>
|
|
1408
|
+
<button type="button" [class]="linkClass" (click)="begin()">{{ reviewText }}</button>
|
|
1409
|
+
</div>
|
|
1410
|
+
}
|
|
1411
|
+
@if (reviewing()) {
|
|
1412
|
+
<div [class]="cardClass" data-atlas-policy-gate="">
|
|
1413
|
+
<div class="atlas-policy-gate-host"></div>
|
|
1414
|
+
@if (error()) {
|
|
1415
|
+
<p [class]="errorClass" role="alert">{{ error() }}</p>
|
|
1416
|
+
}
|
|
1417
|
+
</div>
|
|
1418
|
+
}
|
|
1419
|
+
<ng-content></ng-content>
|
|
1420
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1421
|
+
}
|
|
1422
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PolicyGateComponent, decorators: [{
|
|
1423
|
+
type: Component,
|
|
1424
|
+
args: [{
|
|
1425
|
+
selector: 'atlas-policy-gate',
|
|
1426
|
+
standalone: true,
|
|
1427
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1428
|
+
template: `
|
|
1429
|
+
@if (bannerText(); as text) {
|
|
1430
|
+
<div [class]="bannerClass" role="status" data-atlas-policy-banner="">
|
|
1431
|
+
<span
|
|
1432
|
+
><strong>{{ title }}. </strong>{{ text }}</span
|
|
1433
|
+
>
|
|
1434
|
+
<button type="button" [class]="linkClass" (click)="begin()">{{ reviewText }}</button>
|
|
1435
|
+
</div>
|
|
1436
|
+
}
|
|
1437
|
+
@if (reviewing()) {
|
|
1438
|
+
<div [class]="cardClass" data-atlas-policy-gate="">
|
|
1439
|
+
<div class="atlas-policy-gate-host"></div>
|
|
1440
|
+
@if (error()) {
|
|
1441
|
+
<p [class]="errorClass" role="alert">{{ error() }}</p>
|
|
1442
|
+
}
|
|
1443
|
+
</div>
|
|
1444
|
+
}
|
|
1445
|
+
<ng-content></ng-content>
|
|
1446
|
+
`,
|
|
1447
|
+
}]
|
|
1448
|
+
}], propDecorators: { accepted: [{
|
|
1449
|
+
type: Output
|
|
1450
|
+
}] } });
|
|
1451
|
+
|
|
1202
1452
|
/**
|
|
1203
1453
|
* The server-driven flow shell, shared by `<atlas-sign-in>` and
|
|
1204
1454
|
* `<atlas-sign-up>`. The Angular peer of React's internal `AttemptFlow`.
|
|
@@ -1267,6 +1517,8 @@ class AttemptFlowComponent {
|
|
|
1267
1517
|
*/
|
|
1268
1518
|
emailVerification = 'code';
|
|
1269
1519
|
resend = new EventEmitter();
|
|
1520
|
+
/** The user declined a policy the sign-in was waiting on (`needs_policy_acceptance`): cancel the attempt. */
|
|
1521
|
+
policyDeclined = new EventEmitter();
|
|
1270
1522
|
values = {};
|
|
1271
1523
|
t(key, vars) {
|
|
1272
1524
|
return translate(this.atlas.localization, key, vars);
|
|
@@ -1366,6 +1618,10 @@ class AttemptFlowComponent {
|
|
|
1366
1618
|
return null;
|
|
1367
1619
|
return this.t('signIn.codeSentTo', { email: this.attempt?.identifier ?? '' });
|
|
1368
1620
|
}
|
|
1621
|
+
/** The attempt is `needs_policy_acceptance`. */
|
|
1622
|
+
awaitingPolicies() {
|
|
1623
|
+
return this.step().kind === 'accept_policies';
|
|
1624
|
+
}
|
|
1369
1625
|
showSubmit() {
|
|
1370
1626
|
const kind = this.step().kind;
|
|
1371
1627
|
// Nothing to submit on a first-factor step that only offers an emailed code
|
|
@@ -1377,7 +1633,7 @@ class AttemptFlowComponent {
|
|
|
1377
1633
|
// Enrolment: nothing to submit while choosing a method or fetching the setup.
|
|
1378
1634
|
if (this.enrolling() && this.enrollmentState && !enrollmentSubmitKey(this.enrollmentState))
|
|
1379
1635
|
return false;
|
|
1380
|
-
return kind !== 'done' && kind !== 'await_oauth';
|
|
1636
|
+
return kind !== 'done' && kind !== 'await_oauth' && kind !== 'accept_policies';
|
|
1381
1637
|
}
|
|
1382
1638
|
fields() {
|
|
1383
1639
|
const step = this.step();
|
|
@@ -1411,6 +1667,9 @@ class AttemptFlowComponent {
|
|
|
1411
1667
|
return this.linkOnly() ? [] : [{ kind: 'input', name: 'code', labelKey: 'signIn.emailCodeLabel', type: 'text' }];
|
|
1412
1668
|
case 'collect_new_password':
|
|
1413
1669
|
return [{ kind: 'input', name: 'password', labelKey: 'reset.newPasswordLabel', type: 'password' }];
|
|
1670
|
+
case 'accept_policies':
|
|
1671
|
+
// Drawn by <atlas-policy-accept-step> above.
|
|
1672
|
+
return [];
|
|
1414
1673
|
case 'collect_captcha':
|
|
1415
1674
|
// §5 the server withheld the attempt until a captcha clears. Solving the
|
|
1416
1675
|
// widget resubmits the identifier on its own; the button retries.
|
|
@@ -1434,7 +1693,7 @@ class AttemptFlowComponent {
|
|
|
1434
1693
|
}
|
|
1435
1694
|
}
|
|
1436
1695
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AttemptFlowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1437
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: AttemptFlowComponent, isStandalone: true, selector: "atlas-attempt-flow", inputs: { attempt: "attempt", busy: "busy", errors: "errors", sessionKept: "sessionKept", titleKey: "titleKey", captcha: "captcha", firstFactors: "firstFactors", preparedFactor: "preparedFactor", offerEmailSecondFactor: "offerEmailSecondFactor", emailedSecondFactor: "emailedSecondFactor", offerSmsSecondFactor: "offerSmsSecondFactor", textedSecondFactor: "textedSecondFactor", enrollment: "enrollment", enrollmentState: "enrollmentState", emailVerification: "emailVerification" }, outputs: { submitFlow: "submitFlow", chooseFactor: "chooseFactor", emailSecondFactor: "emailSecondFactor", smsSecondFactor: "smsSecondFactor", resend: "resend" }, ngImport: i0, template: `
|
|
1696
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: AttemptFlowComponent, isStandalone: true, selector: "atlas-attempt-flow", inputs: { attempt: "attempt", busy: "busy", errors: "errors", sessionKept: "sessionKept", titleKey: "titleKey", captcha: "captcha", firstFactors: "firstFactors", preparedFactor: "preparedFactor", offerEmailSecondFactor: "offerEmailSecondFactor", emailedSecondFactor: "emailedSecondFactor", offerSmsSecondFactor: "offerSmsSecondFactor", textedSecondFactor: "textedSecondFactor", enrollment: "enrollment", enrollmentState: "enrollmentState", emailVerification: "emailVerification" }, outputs: { submitFlow: "submitFlow", chooseFactor: "chooseFactor", emailSecondFactor: "emailSecondFactor", smsSecondFactor: "smsSecondFactor", resend: "resend", policyDeclined: "policyDeclined" }, ngImport: i0, template: `
|
|
1438
1697
|
<div [class]="cls('card', 'atlas-card')">
|
|
1439
1698
|
<h1 [class]="cls('headerTitle', 'atlas-title')">{{ t(titleKey) }}</h1>
|
|
1440
1699
|
|
|
@@ -1560,6 +1819,16 @@ class AttemptFlowComponent {
|
|
|
1560
1819
|
}
|
|
1561
1820
|
}
|
|
1562
1821
|
|
|
1822
|
+
@if (awaitingPolicies()) {
|
|
1823
|
+
<!-- A required policy changed: scroll-mode ones in their dialog, the rest as checkboxes. -->
|
|
1824
|
+
<atlas-policy-accept-step
|
|
1825
|
+
[attempt]="attempt"
|
|
1826
|
+
[busy]="busy"
|
|
1827
|
+
(submitFlow)="submitFlow.emit($event)"
|
|
1828
|
+
(declined)="policyDeclined.emit($event)"
|
|
1829
|
+
></atlas-policy-accept-step>
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1563
1832
|
@if (showCaptcha()) {
|
|
1564
1833
|
<div class="atlas-captcha" data-atlas-captcha="" [atlasCaptchaSlot]="captcha"></div>
|
|
1565
1834
|
}
|
|
@@ -1626,7 +1895,7 @@ class AttemptFlowComponent {
|
|
|
1626
1895
|
}
|
|
1627
1896
|
</form>
|
|
1628
1897
|
</div>
|
|
1629
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: AtlasCaptchaSlotDirective, selector: "[atlasCaptchaSlot]", inputs: ["atlasCaptchaSlot"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1898
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: AtlasCaptchaSlotDirective, selector: "[atlasCaptchaSlot]", inputs: ["atlasCaptchaSlot"] }, { kind: "component", type: PolicyAcceptStepComponent, selector: "atlas-policy-accept-step", inputs: ["attempt", "busy"], outputs: ["submitFlow", "declined"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1630
1899
|
}
|
|
1631
1900
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AttemptFlowComponent, decorators: [{
|
|
1632
1901
|
type: Component,
|
|
@@ -1634,7 +1903,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1634
1903
|
selector: 'atlas-attempt-flow',
|
|
1635
1904
|
standalone: true,
|
|
1636
1905
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1637
|
-
imports: [AtlasCaptchaSlotDirective],
|
|
1906
|
+
imports: [AtlasCaptchaSlotDirective, PolicyAcceptStepComponent],
|
|
1638
1907
|
template: `
|
|
1639
1908
|
<div [class]="cls('card', 'atlas-card')">
|
|
1640
1909
|
<h1 [class]="cls('headerTitle', 'atlas-title')">{{ t(titleKey) }}</h1>
|
|
@@ -1761,6 +2030,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1761
2030
|
}
|
|
1762
2031
|
}
|
|
1763
2032
|
|
|
2033
|
+
@if (awaitingPolicies()) {
|
|
2034
|
+
<!-- A required policy changed: scroll-mode ones in their dialog, the rest as checkboxes. -->
|
|
2035
|
+
<atlas-policy-accept-step
|
|
2036
|
+
[attempt]="attempt"
|
|
2037
|
+
[busy]="busy"
|
|
2038
|
+
(submitFlow)="submitFlow.emit($event)"
|
|
2039
|
+
(declined)="policyDeclined.emit($event)"
|
|
2040
|
+
></atlas-policy-accept-step>
|
|
2041
|
+
}
|
|
2042
|
+
|
|
1764
2043
|
@if (showCaptcha()) {
|
|
1765
2044
|
<div class="atlas-captcha" data-atlas-captcha="" [atlasCaptchaSlot]="captcha"></div>
|
|
1766
2045
|
}
|
|
@@ -1869,6 +2148,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1869
2148
|
type: Input
|
|
1870
2149
|
}], resend: [{
|
|
1871
2150
|
type: Output
|
|
2151
|
+
}], policyDeclined: [{
|
|
2152
|
+
type: Output
|
|
1872
2153
|
}] } });
|
|
1873
2154
|
/** A read-only message row: `labelKey` holds the i18n key of the text to show. */
|
|
1874
2155
|
function msg(labelKey) {
|
|
@@ -2055,6 +2336,11 @@ class AtlasFlowController {
|
|
|
2055
2336
|
enrollment;
|
|
2056
2337
|
/** {@link enrollment}'s state, for templates. */
|
|
2057
2338
|
enrollmentState;
|
|
2339
|
+
/**
|
|
2340
|
+
* The instance's policies (terms, privacy, …) for the create-account form:
|
|
2341
|
+
* {@link create} sends their acceptances and reloads them after a refusal.
|
|
2342
|
+
*/
|
|
2343
|
+
policies = new PolicyAcceptanceController([]);
|
|
2058
2344
|
pollTimer = null;
|
|
2059
2345
|
identifier = '';
|
|
2060
2346
|
constructor(client, reload, pending,
|
|
@@ -2191,6 +2477,17 @@ class AtlasFlowController {
|
|
|
2191
2477
|
this.identifier = out.identifier;
|
|
2192
2478
|
await this.finish(out.state);
|
|
2193
2479
|
}
|
|
2480
|
+
/** Load the sign-up's policies into {@link policies} (`<atlas-sign-up>` calls it on init). */
|
|
2481
|
+
async loadPolicies(locale) {
|
|
2482
|
+
this.policies.setPolicies(await loadPolicies(this.client, { locale }));
|
|
2483
|
+
}
|
|
2484
|
+
/** The user declined a policy a sign-in was waiting on: cancel the attempt and say why. */
|
|
2485
|
+
declinePolicy(title) {
|
|
2486
|
+
this.state.set({
|
|
2487
|
+
...initialFlow,
|
|
2488
|
+
errors: [{ code: 'POLICY_DECLINED', message: this.t('policy.declined').replace('{policy}', title) }],
|
|
2489
|
+
});
|
|
2490
|
+
}
|
|
2194
2491
|
/**
|
|
2195
2492
|
* Create an account (`POST /v1/client/sign_ups`) from a create-account form's
|
|
2196
2493
|
* values — email, password and any configured sign-up fields — carrying the
|
|
@@ -2203,6 +2500,7 @@ class AtlasFlowController {
|
|
|
2203
2500
|
consent,
|
|
2204
2501
|
captcha: this.signUpCaptcha,
|
|
2205
2502
|
t: this.t,
|
|
2503
|
+
policies: this.policies,
|
|
2206
2504
|
});
|
|
2207
2505
|
await this.finish(next);
|
|
2208
2506
|
}
|
|
@@ -2247,7 +2545,7 @@ class AtlasFlowController {
|
|
|
2247
2545
|
*/
|
|
2248
2546
|
async createWithPasskey(values, consent = true) {
|
|
2249
2547
|
this.state.update((current) => ({ ...current, busy: true, errors: [] }));
|
|
2250
|
-
await this.finish(await createPasskeySignUp(this.client, values, { consent, captcha: this.signUpCaptcha, t: this.t }));
|
|
2548
|
+
await this.finish(await createPasskeySignUp(this.client, values, { consent, captcha: this.signUpCaptcha, t: this.t, policies: this.policies }));
|
|
2251
2549
|
}
|
|
2252
2550
|
/** The passkey-only sign-up's last step: create the passkey, and with it the account. */
|
|
2253
2551
|
async createPasskey() {
|
|
@@ -2429,6 +2727,7 @@ class SignInComponent {
|
|
|
2429
2727
|
[enrollmentState]="flow.enrollmentState()"
|
|
2430
2728
|
(emailSecondFactor)="flow.sendEmailSecondFactor()"
|
|
2431
2729
|
(smsSecondFactor)="flow.sendSmsSecondFactor()"
|
|
2730
|
+
(policyDeclined)="flow.declinePolicy($event)"
|
|
2432
2731
|
></atlas-attempt-flow>
|
|
2433
2732
|
}
|
|
2434
2733
|
@if (flow.state().attempt?.status !== 'complete' && signUpHref(); as href) {
|
|
@@ -2436,7 +2735,7 @@ class SignInComponent {
|
|
|
2436
2735
|
{{ t('signIn.noAccount') }} <a class="atlas-link" [href]="href">{{ t('signIn.signUpLink') }}</a>
|
|
2437
2736
|
</p>
|
|
2438
2737
|
}
|
|
2439
|
-
`, isInline: true, dependencies: [{ kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "captcha", "firstFactors", "preparedFactor", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification"], outputs: ["submitFlow", "chooseFactor", "emailSecondFactor", "smsSecondFactor", "resend"] }, { kind: "component", type: RecoveryCodesComponent, selector: "atlas-recovery-codes", inputs: ["codes", "busy"], outputs: ["saved"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2738
|
+
`, isInline: true, dependencies: [{ kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "captcha", "firstFactors", "preparedFactor", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification"], outputs: ["submitFlow", "chooseFactor", "emailSecondFactor", "smsSecondFactor", "resend", "policyDeclined"] }, { kind: "component", type: RecoveryCodesComponent, selector: "atlas-recovery-codes", inputs: ["codes", "busy"], outputs: ["saved"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2440
2739
|
}
|
|
2441
2740
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignInComponent, decorators: [{
|
|
2442
2741
|
type: Component,
|
|
@@ -2473,6 +2772,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2473
2772
|
[enrollmentState]="flow.enrollmentState()"
|
|
2474
2773
|
(emailSecondFactor)="flow.sendEmailSecondFactor()"
|
|
2475
2774
|
(smsSecondFactor)="flow.sendSmsSecondFactor()"
|
|
2775
|
+
(policyDeclined)="flow.declinePolicy($event)"
|
|
2476
2776
|
></atlas-attempt-flow>
|
|
2477
2777
|
}
|
|
2478
2778
|
@if (flow.state().attempt?.status !== 'complete' && signUpHref(); as href) {
|
|
@@ -2498,6 +2798,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2498
2798
|
*/
|
|
2499
2799
|
class SignUpFormComponent {
|
|
2500
2800
|
atlas = inject(AtlasService);
|
|
2801
|
+
cdr = inject(ChangeDetectorRef);
|
|
2802
|
+
unwatch = null;
|
|
2501
2803
|
settings = null;
|
|
2502
2804
|
busy = false;
|
|
2503
2805
|
errors = [];
|
|
@@ -2506,12 +2808,27 @@ class SignUpFormComponent {
|
|
|
2506
2808
|
passkey = null;
|
|
2507
2809
|
/** Whether the password / passkey toggle is shown (both are offered). */
|
|
2508
2810
|
switchable = false;
|
|
2811
|
+
/** The instance's policies (terms, privacy, …); they replace the legacy consent row. */
|
|
2812
|
+
policies = null;
|
|
2509
2813
|
/** The user asked for the other sign-up method. */
|
|
2510
2814
|
switchMode = new EventEmitter();
|
|
2511
2815
|
/** Emits the typed values and the consent tick when the form is submitted. */
|
|
2512
2816
|
submitSignUp = new EventEmitter();
|
|
2513
2817
|
values = {};
|
|
2514
2818
|
agreed = false;
|
|
2819
|
+
declined = null;
|
|
2820
|
+
ngOnChanges(changes) {
|
|
2821
|
+
if (!changes['policies'])
|
|
2822
|
+
return;
|
|
2823
|
+
this.unwatch?.();
|
|
2824
|
+
this.unwatch = this.policies?.subscribe(() => this.cdr.markForCheck()) ?? null;
|
|
2825
|
+
}
|
|
2826
|
+
ngOnDestroy() {
|
|
2827
|
+
this.unwatch?.();
|
|
2828
|
+
}
|
|
2829
|
+
hasPolicies() {
|
|
2830
|
+
return !!this.policies && this.policies.policies.length > 0;
|
|
2831
|
+
}
|
|
2515
2832
|
t(key, vars) {
|
|
2516
2833
|
return translate(this.atlas.localization, key, vars);
|
|
2517
2834
|
}
|
|
@@ -2564,10 +2881,15 @@ class SignUpFormComponent {
|
|
|
2564
2881
|
this.setValue(f.key, (on ? [...current, option] : current.filter((p) => p !== option)).join(', '));
|
|
2565
2882
|
}
|
|
2566
2883
|
showLegal() {
|
|
2884
|
+
// Instance policies replace the legacy single "I agree to the Terms" row.
|
|
2885
|
+
if (this.hasPolicies())
|
|
2886
|
+
return false;
|
|
2567
2887
|
const legal = this.settings?.legal;
|
|
2568
2888
|
return !!legal && (!!legal.termsUrl || !!legal.privacyUrl);
|
|
2569
2889
|
}
|
|
2570
2890
|
consentOk() {
|
|
2891
|
+
if (this.hasPolicies())
|
|
2892
|
+
return this.policies.canSubmit();
|
|
2571
2893
|
return !this.settings?.legal?.required || this.agreed;
|
|
2572
2894
|
}
|
|
2573
2895
|
formErrors() {
|
|
@@ -2580,13 +2902,27 @@ class SignUpFormComponent {
|
|
|
2580
2902
|
event.preventDefault();
|
|
2581
2903
|
if (this.emailUnavailable() || !this.consentOk())
|
|
2582
2904
|
return;
|
|
2905
|
+
this.declined = null;
|
|
2906
|
+
if (this.hasPolicies()) {
|
|
2907
|
+
// Scroll-mode policies are read in their unskippable dialog first.
|
|
2908
|
+
const values = { ...this.values };
|
|
2909
|
+
void confirmPolicies(this.policies, { t: policyUi(this.atlas).t }).then((res) => {
|
|
2910
|
+
if (res.ok)
|
|
2911
|
+
this.submitSignUp.emit({ values, consent: true });
|
|
2912
|
+
else {
|
|
2913
|
+
this.declined = res.declined;
|
|
2914
|
+
this.cdr.markForCheck();
|
|
2915
|
+
}
|
|
2916
|
+
});
|
|
2917
|
+
return;
|
|
2918
|
+
}
|
|
2583
2919
|
this.submitSignUp.emit({
|
|
2584
2920
|
values: { ...this.values },
|
|
2585
2921
|
consent: this.settings?.legal?.required ? this.agreed : true,
|
|
2586
2922
|
});
|
|
2587
2923
|
}
|
|
2588
2924
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignUpFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2589
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: SignUpFormComponent, isStandalone: true, selector: "atlas-sign-up-form", inputs: { settings: "settings", busy: "busy", errors: "errors", captcha: "captcha", passkey: "passkey", switchable: "switchable" }, outputs: { switchMode: "switchMode", submitSignUp: "submitSignUp" }, ngImport: i0, template: `
|
|
2925
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: SignUpFormComponent, isStandalone: true, selector: "atlas-sign-up-form", inputs: { settings: "settings", busy: "busy", errors: "errors", captcha: "captcha", passkey: "passkey", switchable: "switchable", policies: "policies" }, outputs: { switchMode: "switchMode", submitSignUp: "submitSignUp" }, usesOnChanges: true, ngImport: i0, template: `
|
|
2590
2926
|
<div [class]="cls('card', 'atlas-card')">
|
|
2591
2927
|
<h1 [class]="cls('headerTitle', 'atlas-title')">{{ t('signUp.title') }}</h1>
|
|
2592
2928
|
|
|
@@ -2715,6 +3051,15 @@ class SignUpFormComponent {
|
|
|
2715
3051
|
</label>
|
|
2716
3052
|
}
|
|
2717
3053
|
|
|
3054
|
+
@if (hasPolicies()) {
|
|
3055
|
+
<div [atlasPolicies]="policies"></div>
|
|
3056
|
+
@if (declined) {
|
|
3057
|
+
<span [class]="cls('formFieldError', 'atlas-error')" role="alert" data-atlas-policy-declined="">
|
|
3058
|
+
{{ t('policy.declined', { policy: declined }) }}
|
|
3059
|
+
</span>
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
|
|
2718
3063
|
@if (showLegal()) {
|
|
2719
3064
|
<label [class]="cls('formField', 'atlas-consent')">
|
|
2720
3065
|
@if (settings?.legal?.required) {
|
|
@@ -2754,6 +3099,9 @@ class SignUpFormComponent {
|
|
|
2754
3099
|
>
|
|
2755
3100
|
{{ t('signUp.submit') }}
|
|
2756
3101
|
</button>
|
|
3102
|
+
@if (hasPolicies()) {
|
|
3103
|
+
<p atlasPolicyKind="clickwrap" [atlasPolicies]="policies"></p>
|
|
3104
|
+
}
|
|
2757
3105
|
@if (switchable) {
|
|
2758
3106
|
<div class="atlas-alternatives">
|
|
2759
3107
|
<button
|
|
@@ -2770,7 +3118,7 @@ class SignUpFormComponent {
|
|
|
2770
3118
|
</form>
|
|
2771
3119
|
}
|
|
2772
3120
|
</div>
|
|
2773
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: AtlasCaptchaSlotDirective, selector: "[atlasCaptchaSlot]", inputs: ["atlasCaptchaSlot"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3121
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: AtlasCaptchaSlotDirective, selector: "[atlasCaptchaSlot]", inputs: ["atlasCaptchaSlot"] }, { kind: "directive", type: AtlasPoliciesDirective, selector: "[atlasPolicies]", inputs: ["atlasPolicies", "atlasPolicyKind"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2774
3122
|
}
|
|
2775
3123
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignUpFormComponent, decorators: [{
|
|
2776
3124
|
type: Component,
|
|
@@ -2778,7 +3126,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2778
3126
|
selector: 'atlas-sign-up-form',
|
|
2779
3127
|
standalone: true,
|
|
2780
3128
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2781
|
-
imports: [AtlasCaptchaSlotDirective],
|
|
3129
|
+
imports: [AtlasCaptchaSlotDirective, AtlasPoliciesDirective],
|
|
2782
3130
|
template: `
|
|
2783
3131
|
<div [class]="cls('card', 'atlas-card')">
|
|
2784
3132
|
<h1 [class]="cls('headerTitle', 'atlas-title')">{{ t('signUp.title') }}</h1>
|
|
@@ -2908,6 +3256,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2908
3256
|
</label>
|
|
2909
3257
|
}
|
|
2910
3258
|
|
|
3259
|
+
@if (hasPolicies()) {
|
|
3260
|
+
<div [atlasPolicies]="policies"></div>
|
|
3261
|
+
@if (declined) {
|
|
3262
|
+
<span [class]="cls('formFieldError', 'atlas-error')" role="alert" data-atlas-policy-declined="">
|
|
3263
|
+
{{ t('policy.declined', { policy: declined }) }}
|
|
3264
|
+
</span>
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
|
|
2911
3268
|
@if (showLegal()) {
|
|
2912
3269
|
<label [class]="cls('formField', 'atlas-consent')">
|
|
2913
3270
|
@if (settings?.legal?.required) {
|
|
@@ -2947,6 +3304,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2947
3304
|
>
|
|
2948
3305
|
{{ t('signUp.submit') }}
|
|
2949
3306
|
</button>
|
|
3307
|
+
@if (hasPolicies()) {
|
|
3308
|
+
<p atlasPolicyKind="clickwrap" [atlasPolicies]="policies"></p>
|
|
3309
|
+
}
|
|
2950
3310
|
@if (switchable) {
|
|
2951
3311
|
<div class="atlas-alternatives">
|
|
2952
3312
|
<button
|
|
@@ -2977,6 +3337,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2977
3337
|
type: Input
|
|
2978
3338
|
}], switchable: [{
|
|
2979
3339
|
type: Input
|
|
3340
|
+
}], policies: [{
|
|
3341
|
+
type: Input
|
|
2980
3342
|
}], switchMode: [{
|
|
2981
3343
|
type: Output
|
|
2982
3344
|
}], submitSignUp: [{
|
|
@@ -3028,8 +3390,10 @@ class SignUpComponent {
|
|
|
3028
3390
|
}
|
|
3029
3391
|
ngOnInit() {
|
|
3030
3392
|
// §5 the instance's sign-up fields, consent policy and captcha settings.
|
|
3031
|
-
if (typeof window !== 'undefined')
|
|
3393
|
+
if (typeof window !== 'undefined') {
|
|
3032
3394
|
void this.flow.loadSettings();
|
|
3395
|
+
void this.flow.loadPolicies(this.atlas.locale ?? undefined);
|
|
3396
|
+
}
|
|
3033
3397
|
}
|
|
3034
3398
|
ngOnDestroy() {
|
|
3035
3399
|
this.flow.destroy();
|
|
@@ -3069,6 +3433,7 @@ class SignUpComponent {
|
|
|
3069
3433
|
[busy]="flow.state().busy"
|
|
3070
3434
|
[errors]="flow.state().errors"
|
|
3071
3435
|
[captcha]="flow.signUpCaptchaDrawn() ? flow.signUpCaptcha : null"
|
|
3436
|
+
[policies]="flow.policies"
|
|
3072
3437
|
[passkey]="passkeyForm()"
|
|
3073
3438
|
[switchable]="canPasskey()"
|
|
3074
3439
|
(switchMode)="toggleMode()"
|
|
@@ -3077,7 +3442,7 @@ class SignUpComponent {
|
|
|
3077
3442
|
"
|
|
3078
3443
|
></atlas-sign-up-form>
|
|
3079
3444
|
}
|
|
3080
|
-
`, isInline: true, dependencies: [{ kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "captcha", "firstFactors", "preparedFactor", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification"], outputs: ["submitFlow", "chooseFactor", "emailSecondFactor", "smsSecondFactor", "resend"] }, { kind: "component", type: SignUpFormComponent, selector: "atlas-sign-up-form", inputs: ["settings", "busy", "errors", "captcha", "passkey", "switchable"], outputs: ["switchMode", "submitSignUp"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3445
|
+
`, isInline: true, dependencies: [{ kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "captcha", "firstFactors", "preparedFactor", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification"], outputs: ["submitFlow", "chooseFactor", "emailSecondFactor", "smsSecondFactor", "resend", "policyDeclined"] }, { kind: "component", type: SignUpFormComponent, selector: "atlas-sign-up-form", inputs: ["settings", "busy", "errors", "captcha", "passkey", "switchable", "policies"], outputs: ["switchMode", "submitSignUp"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3081
3446
|
}
|
|
3082
3447
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignUpComponent, decorators: [{
|
|
3083
3448
|
type: Component,
|
|
@@ -3120,6 +3485,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3120
3485
|
[busy]="flow.state().busy"
|
|
3121
3486
|
[errors]="flow.state().errors"
|
|
3122
3487
|
[captcha]="flow.signUpCaptchaDrawn() ? flow.signUpCaptcha : null"
|
|
3488
|
+
[policies]="flow.policies"
|
|
3123
3489
|
[passkey]="passkeyForm()"
|
|
3124
3490
|
[switchable]="canPasskey()"
|
|
3125
3491
|
(switchMode)="toggleMode()"
|
|
@@ -4216,6 +4582,9 @@ const ATLAS_UI = [
|
|
|
4216
4582
|
UserProfileComponent,
|
|
4217
4583
|
OrganizationProfileComponent,
|
|
4218
4584
|
OrganizationAuditLogComponent,
|
|
4585
|
+
AtlasPoliciesDirective,
|
|
4586
|
+
PolicyAcceptStepComponent,
|
|
4587
|
+
PolicyGateComponent,
|
|
4219
4588
|
];
|
|
4220
4589
|
|
|
4221
4590
|
/**
|
|
@@ -4273,7 +4642,7 @@ class AtlasModule {
|
|
|
4273
4642
|
return { ngModule: AtlasModule, providers };
|
|
4274
4643
|
}
|
|
4275
4644
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AtlasModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
4276
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: AtlasModule, imports: [AtlasSignedInDirective, AtlasSignedOutDirective, AtlasLoadingDirective, AtlasLoadedDirective, AtlasProtectDirective, AtlasRootDirective, SignInComponent, SignUpComponent, UserButtonComponent, OrganizationSwitcherComponent, UserProfileComponent, OrganizationProfileComponent, OrganizationAuditLogComponent], exports: [AtlasSignedInDirective, AtlasSignedOutDirective, AtlasLoadingDirective, AtlasLoadedDirective, AtlasProtectDirective, AtlasRootDirective, SignInComponent, SignUpComponent, UserButtonComponent, OrganizationSwitcherComponent, UserProfileComponent, OrganizationProfileComponent, OrganizationAuditLogComponent] });
|
|
4645
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: AtlasModule, imports: [AtlasSignedInDirective, AtlasSignedOutDirective, AtlasLoadingDirective, AtlasLoadedDirective, AtlasProtectDirective, AtlasRootDirective, SignInComponent, SignUpComponent, UserButtonComponent, OrganizationSwitcherComponent, UserProfileComponent, OrganizationProfileComponent, OrganizationAuditLogComponent, AtlasPoliciesDirective, PolicyAcceptStepComponent, PolicyGateComponent], exports: [AtlasSignedInDirective, AtlasSignedOutDirective, AtlasLoadingDirective, AtlasLoadedDirective, AtlasProtectDirective, AtlasRootDirective, SignInComponent, SignUpComponent, UserButtonComponent, OrganizationSwitcherComponent, UserProfileComponent, OrganizationProfileComponent, OrganizationAuditLogComponent, AtlasPoliciesDirective, PolicyAcceptStepComponent, PolicyGateComponent] });
|
|
4277
4646
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AtlasModule });
|
|
4278
4647
|
}
|
|
4279
4648
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AtlasModule, decorators: [{
|
|
@@ -4434,5 +4803,5 @@ function atlasChildGuard(options = {}) {
|
|
|
4434
4803
|
* Generated bundle index. Do not edit.
|
|
4435
4804
|
*/
|
|
4436
4805
|
|
|
4437
|
-
export { ATLAS_ANGULAR_SDK, ATLAS_ANGULAR_VERSION, ATLAS_OPTIONS, ATLAS_UI, AtlasCaptchaSlotDirective, AtlasFlowController, AtlasLoadedDirective, AtlasLoadingDirective, AtlasModule, AtlasOrganizationAuditLog, AtlasProtectDirective, AtlasRootDirective, AtlasService, AtlasSignedInDirective, AtlasSignedOutDirective, AttemptFlowComponent, DEFAULT_TOKENS, EN_US, ImpersonationBannerComponent, OrganizationAuditLogComponent, OrganizationProfileComponent, OrganizationSwitcherComponent, SignInComponent, SignUpComponent, SignUpFormComponent, THEMES, UserButtonComponent, UserProfileComponent, atlasChildGuard, atlasGuard, classFor, cssVariables, explicitTokens, provideAtlas, renderAppearance, resolveTokens, translate, withFallback };
|
|
4806
|
+
export { ATLAS_ANGULAR_SDK, ATLAS_ANGULAR_VERSION, ATLAS_OPTIONS, ATLAS_UI, AtlasCaptchaSlotDirective, AtlasFlowController, AtlasLoadedDirective, AtlasLoadingDirective, AtlasModule, AtlasOrganizationAuditLog, AtlasPoliciesDirective, AtlasProtectDirective, AtlasRootDirective, AtlasService, AtlasSignedInDirective, AtlasSignedOutDirective, AttemptFlowComponent, DEFAULT_TOKENS, EN_US, ImpersonationBannerComponent, OrganizationAuditLogComponent, OrganizationProfileComponent, OrganizationSwitcherComponent, PolicyAcceptStepComponent, PolicyGateComponent, SignInComponent, SignUpComponent, SignUpFormComponent, THEMES, UserButtonComponent, UserProfileComponent, atlasChildGuard, atlasGuard, classFor, cssVariables, explicitTokens, provideAtlas, renderAppearance, resolveTokens, translate, withFallback };
|
|
4438
4807
|
//# sourceMappingURL=atlasauth-angular.mjs.map
|