1
0
mirror of https://github.com/bitwarden/directory-connector synced 2026-01-17 16:03:20 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot]
921eb160ac [deps]: Update @types/node to v24 2026-01-17 02:08:28 +00:00
14 changed files with 6515 additions and 4002 deletions

View File

@@ -18,17 +18,15 @@
"prefix": "app", "prefix": "app",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular/build:application", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"outputPath": { "outputPath": "dist",
"base": "dist"
},
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "tsconfig.json", "tsConfig": "tsconfig.json",
"assets": [], "assets": [],
"styles": [], "styles": [],
"scripts": [], "scripts": []
"browser": "src/main.ts"
} }
} }
} }

View File

@@ -13,47 +13,42 @@ import {
@Component({ @Component({
selector: "[toast-component2]", selector: "[toast-component2]",
template: ` template: `
@if (options.closeButton) { <button
<button (click)="remove()" type="button" class="toast-close-button" aria-label="Close"> *ngIf="options.closeButton"
<span aria-hidden="true">&times;</span> (click)="remove()"
</button> type="button"
} class="toast-close-button"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<div class="icon"> <div class="icon">
<i></i> <i></i>
</div> </div>
<div> <div>
@if (title) { <div *ngIf="title" [class]="options.titleClass" [attr.aria-label]="title">
<div [class]="options.titleClass" [attr.aria-label]="title"> {{ title }} <ng-container *ngIf="duplicatesCount">[{{ duplicatesCount + 1 }}]</ng-container>
{{ title }}
@if (duplicatesCount) {
[{{ duplicatesCount + 1 }}]
}
</div>
}
@if (message && options.enableHtml) {
<div
role="alertdialog"
aria-live="polite"
[class]="options.messageClass"
[innerHTML]="message"
></div>
}
@if (message && !options.enableHtml) {
<div
role="alertdialog"
aria-live="polite"
[class]="options.messageClass"
[attr.aria-label]="message"
>
{{ message }}
</div>
}
</div>
@if (options.progressBar) {
<div>
<div class="toast-progress" [style.width]="width + '%'"></div>
</div> </div>
} <div
*ngIf="message && options.enableHtml"
role="alertdialog"
aria-live="polite"
[class]="options.messageClass"
[innerHTML]="message"
></div>
<div
*ngIf="message && !options.enableHtml"
role="alertdialog"
aria-live="polite"
[class]="options.messageClass"
[attr.aria-label]="message"
>
{{ message }}
</div>
</div>
<div *ngIf="options.progressBar">
<div class="toast-progress" [style.width]="width + '%'"></div>
</div>
`, `,
animations: [ animations: [
trigger("flyInOut", [ trigger("flyInOut", [

View File

@@ -9,7 +9,7 @@ describe("SymmetricCryptoKey", () => {
new SymmetricCryptoKey(null); new SymmetricCryptoKey(null);
}; };
expect(t).toThrow("Must provide key"); expect(t).toThrowError("Must provide key");
}); });
describe("guesses encKey from key length", () => { describe("guesses encKey from key length", () => {
@@ -63,7 +63,7 @@ describe("SymmetricCryptoKey", () => {
new SymmetricCryptoKey(makeStaticByteArray(30)); new SymmetricCryptoKey(makeStaticByteArray(30));
}; };
expect(t).toThrow("Unable to determine encType."); expect(t).toThrowError("Unable to determine encType.");
}); });
}); });
}); });

9917
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -73,19 +73,19 @@
"test:types": "npx tsc --noEmit" "test:types": "npx tsc --noEmit"
}, },
"devDependencies": { "devDependencies": {
"@angular-eslint/eslint-plugin-template": "21.1.0", "@angular-devkit/build-angular": "20.3.3",
"@angular-eslint/template-parser": "21.1.0", "@angular-eslint/eslint-plugin-template": "20.7.0",
"@angular/build": "21.0.5", "@angular-eslint/template-parser": "20.7.0",
"@angular/compiler-cli": "21.0.8", "@angular/compiler-cli": "20.3.16",
"@electron/notarize": "2.5.0", "@electron/notarize": "2.5.0",
"@electron/rebuild": "4.0.1", "@electron/rebuild": "4.0.1",
"@fluffy-spoon/substitute": "1.208.0", "@fluffy-spoon/substitute": "1.208.0",
"@microsoft/microsoft-graph-types": "2.43.1", "@microsoft/microsoft-graph-types": "2.43.1",
"@ngtools/webpack": "21.0.5", "@ngtools/webpack": "20.3.3",
"@types/inquirer": "8.2.10", "@types/inquirer": "8.2.10",
"@types/jest": "30.0.0", "@types/jest": "29.5.14",
"@types/lowdb": "1.0.15", "@types/lowdb": "1.0.15",
"@types/node": "22.19.2", "@types/node": "24.10.6",
"@types/node-fetch": "2.6.12", "@types/node-fetch": "2.6.12",
"@types/node-forge": "1.3.11", "@types/node-forge": "1.3.11",
"@types/proper-lockfile": "4.1.4", "@types/proper-lockfile": "4.1.4",
@@ -94,9 +94,7 @@
"@typescript-eslint/eslint-plugin": "8.50.0", "@typescript-eslint/eslint-plugin": "8.50.0",
"@typescript-eslint/parser": "8.50.0", "@typescript-eslint/parser": "8.50.0",
"@yao-pkg/pkg": "5.16.1", "@yao-pkg/pkg": "5.16.1",
"babel-loader": "9.2.1",
"clean-webpack-plugin": "4.0.0", "clean-webpack-plugin": "4.0.0",
"jest-environment-jsdom": "30.2.0",
"concurrently": "9.2.0", "concurrently": "9.2.0",
"copy-webpack-plugin": "13.0.0", "copy-webpack-plugin": "13.0.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
@@ -119,10 +117,10 @@
"html-loader": "5.1.0", "html-loader": "5.1.0",
"html-webpack-plugin": "5.6.3", "html-webpack-plugin": "5.6.3",
"husky": "9.1.7", "husky": "9.1.7",
"jest": "30.2.0", "jest": "29.7.0",
"jest-junit": "16.0.0", "jest-junit": "16.0.0",
"jest-mock-extended": "4.0.0", "jest-mock-extended": "3.0.7",
"jest-preset-angular": "16.0.0", "jest-preset-angular": "14.6.0",
"lint-staged": "16.2.6", "lint-staged": "16.2.6",
"mini-css-extract-plugin": "2.9.2", "mini-css-extract-plugin": "2.9.2",
"minimatch": "5.1.2", "minimatch": "5.1.2",
@@ -145,16 +143,16 @@
"zone.js": "0.15.1" "zone.js": "0.15.1"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "21.0.8", "@angular/animations": "20.3.16",
"@angular/cdk": "21.0.6", "@angular/cdk": "20.2.14",
"@angular/cli": "21.0.5", "@angular/cli": "20.3.3",
"@angular/common": "21.0.8", "@angular/common": "20.3.16",
"@angular/compiler": "21.0.8", "@angular/compiler": "20.3.16",
"@angular/core": "21.0.8", "@angular/core": "20.3.16",
"@angular/forms": "21.0.8", "@angular/forms": "20.3.16",
"@angular/platform-browser": "21.0.8", "@angular/platform-browser": "20.3.16",
"@angular/platform-browser-dynamic": "21.0.8", "@angular/platform-browser-dynamic": "20.3.16",
"@angular/router": "21.0.8", "@angular/router": "20.3.16",
"@microsoft/microsoft-graph-client": "3.0.7", "@microsoft/microsoft-graph-client": "3.0.7",
"big-integer": "1.6.52", "big-integer": "1.6.52",
"bootstrap": "5.3.7", "bootstrap": "5.3.7",

View File

@@ -1,4 +1,4 @@
import { enableProdMode, provideZoneChangeDetection } from "@angular/core"; import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { isDev } from "@/jslib/electron/src/utils"; import { isDev } from "@/jslib/electron/src/utils";
@@ -11,7 +11,4 @@ if (!isDev()) {
enableProdMode(); enableProdMode();
} }
platformBrowserDynamic().bootstrapModule(AppModule, { platformBrowserDynamic().bootstrapModule(AppModule, { preserveWhitespaces: true });
applicationProviders: [provideZoneChangeDetection()],
preserveWhitespaces: true,
});

View File

@@ -3,25 +3,17 @@
<div class="card-body"> <div class="card-body">
<p> <p>
{{ "lastGroupSync" | i18n }}: {{ "lastGroupSync" | i18n }}:
@if (!lastGroupSync) { <span *ngIf="!lastGroupSync">-</span>
<span>-</span>
}
{{ lastGroupSync | date: "medium" }} {{ lastGroupSync | date: "medium" }}
<br /> <br />
{{ "lastUserSync" | i18n }}: {{ "lastUserSync" | i18n }}:
@if (!lastUserSync) { <span *ngIf="!lastUserSync">-</span>
<span>-</span>
}
{{ lastUserSync | date: "medium" }} {{ lastUserSync | date: "medium" }}
</p> </p>
<p> <p>
{{ "syncStatus" | i18n }}: {{ "syncStatus" | i18n }}:
@if (syncRunning) { <strong *ngIf="syncRunning" class="text-success">{{ "running" | i18n }}</strong>
<strong class="text-success">{{ "running" | i18n }}</strong> <strong *ngIf="!syncRunning" class="text-danger">{{ "stopped" | i18n }}</strong>
}
@if (!syncRunning) {
<strong class="text-danger">{{ "stopped" | i18n }}</strong>
}
</p> </p>
<form #startForm [appApiAction]="startPromise" class="d-inline"> <form #startForm [appApiAction]="startPromise" class="d-inline">
<button <button
@@ -68,85 +60,57 @@
/> />
<label class="form-check-label" for="simSinceLast">{{ "testLastSync" | i18n }}</label> <label class="form-check-label" for="simSinceLast">{{ "testLastSync" | i18n }}</label>
</div> </div>
@if (!simForm.loading && (simUsers || simGroups)) { <ng-container *ngIf="!simForm.loading && (simUsers || simGroups)">
<hr /> <hr />
<div class="row"> <div class="row">
<div class="col-lg"> <div class="col-lg">
<h4>{{ "users" | i18n }}</h4> <h4>{{ "users" | i18n }}</h4>
@if (simEnabledUsers && simEnabledUsers.length) { <ul class="bwi-ul testing-list" *ngIf="simEnabledUsers && simEnabledUsers.length">
<ul class="bwi-ul testing-list"> <li *ngFor="let u of simEnabledUsers" title="{{ u.referenceId }}">
@for (u of simEnabledUsers; track u) { <i class="bwi bwi-li bwi-user"></i>
<li title="{{ u.referenceId }}"> {{ u.displayName }}
<i class="bwi bwi-li bwi-user"></i> </li>
{{ u.displayName }} </ul>
</li> <p *ngIf="!simEnabledUsers || !simEnabledUsers.length">
} {{ "noUsers" | i18n }}
</ul> </p>
}
@if (!simEnabledUsers || !simEnabledUsers.length) {
<p>
{{ "noUsers" | i18n }}
</p>
}
<h4>{{ "disabledUsers" | i18n }}</h4> <h4>{{ "disabledUsers" | i18n }}</h4>
@if (simDisabledUsers && simDisabledUsers.length) { <ul class="bwi-ul testing-list" *ngIf="simDisabledUsers && simDisabledUsers.length">
<ul class="bwi-ul testing-list"> <li *ngFor="let u of simDisabledUsers" title="{{ u.referenceId }}">
@for (u of simDisabledUsers; track u) { <i class="bwi bwi-li bwi-user"></i>
<li title="{{ u.referenceId }}"> {{ u.displayName }}
<i class="bwi bwi-li bwi-user"></i> </li>
{{ u.displayName }} </ul>
</li> <p *ngIf="!simDisabledUsers || !simDisabledUsers.length">
} {{ "noUsers" | i18n }}
</ul> </p>
}
@if (!simDisabledUsers || !simDisabledUsers.length) {
<p>
{{ "noUsers" | i18n }}
</p>
}
<h4>{{ "deletedUsers" | i18n }}</h4> <h4>{{ "deletedUsers" | i18n }}</h4>
@if (simDeletedUsers && simDeletedUsers.length) { <ul class="bwi-ul testing-list" *ngIf="simDeletedUsers && simDeletedUsers.length">
<ul class="bwi-ul testing-list"> <li *ngFor="let u of simDeletedUsers" title="{{ u.referenceId }}">
@for (u of simDeletedUsers; track u) { <i class="bwi bwi-li bwi-user"></i>
<li title="{{ u.referenceId }}"> {{ u.displayName }}
<i class="bwi bwi-li bwi-user"></i> </li>
{{ u.displayName }} </ul>
</li> <p *ngIf="!simDeletedUsers || !simDeletedUsers.length">
} {{ "noUsers" | i18n }}
</ul> </p>
}
@if (!simDeletedUsers || !simDeletedUsers.length) {
<p>
{{ "noUsers" | i18n }}
</p>
}
</div> </div>
<div class="col-lg"> <div class="col-lg">
<h4>{{ "groups" | i18n }}</h4> <h4>{{ "groups" | i18n }}</h4>
@if (simGroups && simGroups.length) { <ul class="bwi-ul testing-list" *ngIf="simGroups && simGroups.length">
<ul class="bwi-ul testing-list"> <li *ngFor="let g of simGroups" title="{{ g.referenceId }}">
@for (g of simGroups; track g) { <i class="bwi bwi-li bwi-sitemap"></i>
<li title="{{ g.referenceId }}"> {{ g.displayName }}
<i class="bwi bwi-li bwi-sitemap"></i> <ul class="small" *ngIf="g.users && g.users.length">
{{ g.displayName }} <li *ngFor="let u of g.users" title="{{ u.referenceId }}">
@if (g.users && g.users.length) { {{ u.displayName }}
<ul class="small">
@for (u of g.users; track u) {
<li title="{{ u.referenceId }}">
{{ u.displayName }}
</li>
}
</ul>
}
</li> </li>
} </ul>
</ul> </li>
} </ul>
@if (!simGroups || !simGroups.length) { <p *ngIf="!simGroups || !simGroups.length">{{ "noGroups" | i18n }}</p>
<p>{{ "noGroups" | i18n }}</p>
}
</div> </div>
</div> </div>
} </ng-container>
</div> </div>
</div> </div>

View File

@@ -6,11 +6,9 @@
<div class="mb-3"> <div class="mb-3">
<label for="directory" class="form-label">{{ "type" | i18n }}</label> <label for="directory" class="form-label">{{ "type" | i18n }}</label>
<select class="form-select" id="directory" name="Directory" [(ngModel)]="directory"> <select class="form-select" id="directory" name="Directory" [(ngModel)]="directory">
@for (o of directoryOptions; track o) { <option *ngFor="let o of directoryOptions" [ngValue]="o.value">
<option [ngValue]="o.value"> {{ o.name }}
{{ o.name }} </option>
</option>
}
</select> </select>
</div> </div>
<div [hidden]="directory != directoryType.Ldap"> <div [hidden]="directory != directoryType.Ldap">
@@ -53,22 +51,20 @@
<label class="form-check-label" for="ad">{{ "ldapAd" | i18n }}</label> <label class="form-check-label" for="ad">{{ "ldapAd" | i18n }}</label>
</div> </div>
</div> </div>
@if (!ldap.ad) { <div class="mb-3" *ngIf="!ldap.ad">
<div class="mb-3"> <div class="form-check">
<div class="form-check"> <input
<input class="form-check-input"
class="form-check-input" type="checkbox"
type="checkbox" id="pagedSearch"
id="pagedSearch" [(ngModel)]="ldap.pagedSearch"
[(ngModel)]="ldap.pagedSearch" name="PagedSearch"
name="PagedSearch" />
/> <label class="form-check-label" for="pagedSearch">{{
<label class="form-check-label" for="pagedSearch">{{ "ldapPagedResults" | i18n
"ldapPagedResults" | i18n }}</label>
}}</label>
</div>
</div> </div>
} </div>
<div class="mb-3"> <div class="mb-3">
<div class="form-check"> <div class="form-check">
<input <input
@@ -83,122 +79,116 @@
}}</label> }}</label>
</div> </div>
</div> </div>
@if (ldap.ssl) { <div class="ms-4" *ngIf="ldap.ssl">
<div class="ms-4"> <div class="mb-3">
<div class="mb-3"> <div class="form-check">
<div class="form-check"> <input
<input class="form-check-input"
class="form-check-input" type="radio"
type="radio" [value]="false"
[value]="false" id="ssl"
id="ssl" [(ngModel)]="ldap.startTls"
[(ngModel)]="ldap.startTls" name="SSL"
name="SSL" />
/> <label class="form-check-label" for="ssl">{{ "ldapSsl" | i18n }}</label>
<label class="form-check-label" for="ssl">{{ "ldapSsl" | i18n }}</label>
</div>
<div class="form-check">
<input
class="form-check-input"
type="radio"
[value]="true"
id="startTls"
[(ngModel)]="ldap.startTls"
name="StartTLS"
/>
<label class="form-check-label" for="startTls">{{ "ldapTls" | i18n }}</label>
</div>
</div> </div>
@if (ldap.startTls) { <div class="form-check">
<div class="ms-4"> <input
<p>{{ "ldapTlsUntrustedDesc" | i18n }}</p> class="form-check-input"
<div class="mb-3"> type="radio"
<label for="tlsCaPath" class="form-label">{{ "ldapTlsCa" | i18n }}</label> [value]="true"
<input id="startTls"
type="file" [(ngModel)]="ldap.startTls"
class="form-control mb-2" name="StartTLS"
id="tlsCaPath_file" />
(change)="setSslPath('tlsCaPath')" <label class="form-check-label" for="startTls">{{ "ldapTls" | i18n }}</label>
/>
<input
type="text"
class="form-control"
id="tlsCaPath"
name="TLSCaPath"
[(ngModel)]="ldap.tlsCaPath"
/>
</div>
</div>
}
@if (!ldap.startTls) {
<div class="ms-4">
<p>{{ "ldapSslUntrustedDesc" | i18n }}</p>
<div class="mb-3">
<label for="sslCertPath" class="form-label">{{ "ldapSslCert" | i18n }}</label>
<input
type="file"
class="form-control mb-2"
id="sslCertPath_file"
(change)="setSslPath('sslCertPath')"
/>
<input
type="text"
class="form-control"
id="sslCertPath"
name="SSLCertPath"
[(ngModel)]="ldap.sslCertPath"
/>
</div>
<div class="mb-3">
<label for="sslKeyPath" class="form-label">{{ "ldapSslKey" | i18n }}</label>
<input
type="file"
class="form-control mb-2"
id="sslKeyPath_file"
(change)="setSslPath('sslKeyPath')"
/>
<input
type="text"
class="form-control"
id="sslKeyPath"
name="SSLKeyPath"
[(ngModel)]="ldap.sslKeyPath"
/>
</div>
<div class="mb-3">
<label for="sslCaPath" class="form-label">{{ "ldapSslCa" | i18n }}</label>
<input
type="file"
class="form-control mb-2"
id="sslCaPath_file"
(change)="setSslPath('sslCaPath')"
/>
<input
type="text"
class="form-control"
id="sslCaPath"
name="SSLCaPath"
[(ngModel)]="ldap.sslCaPath"
/>
</div>
</div>
}
<div class="mb-3">
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
id="certDoNotVerify"
[(ngModel)]="ldap.sslAllowUnauthorized"
name="CertDoNoVerify"
/>
<label class="form-check-label" for="certDoNotVerify">{{
"ldapCertDoNotVerify" | i18n
}}</label>
</div>
</div> </div>
</div> </div>
} <div class="ms-4" *ngIf="ldap.startTls">
<p>{{ "ldapTlsUntrustedDesc" | i18n }}</p>
<div class="mb-3">
<label for="tlsCaPath" class="form-label">{{ "ldapTlsCa" | i18n }}</label>
<input
type="file"
class="form-control mb-2"
id="tlsCaPath_file"
(change)="setSslPath('tlsCaPath')"
/>
<input
type="text"
class="form-control"
id="tlsCaPath"
name="TLSCaPath"
[(ngModel)]="ldap.tlsCaPath"
/>
</div>
</div>
<div class="ms-4" *ngIf="!ldap.startTls">
<p>{{ "ldapSslUntrustedDesc" | i18n }}</p>
<div class="mb-3">
<label for="sslCertPath" class="form-label">{{ "ldapSslCert" | i18n }}</label>
<input
type="file"
class="form-control mb-2"
id="sslCertPath_file"
(change)="setSslPath('sslCertPath')"
/>
<input
type="text"
class="form-control"
id="sslCertPath"
name="SSLCertPath"
[(ngModel)]="ldap.sslCertPath"
/>
</div>
<div class="mb-3">
<label for="sslKeyPath" class="form-label">{{ "ldapSslKey" | i18n }}</label>
<input
type="file"
class="form-control mb-2"
id="sslKeyPath_file"
(change)="setSslPath('sslKeyPath')"
/>
<input
type="text"
class="form-control"
id="sslKeyPath"
name="SSLKeyPath"
[(ngModel)]="ldap.sslKeyPath"
/>
</div>
<div class="mb-3">
<label for="sslCaPath" class="form-label">{{ "ldapSslCa" | i18n }}</label>
<input
type="file"
class="form-control mb-2"
id="sslCaPath_file"
(change)="setSslPath('sslCaPath')"
/>
<input
type="text"
class="form-control"
id="sslCaPath"
name="SSLCaPath"
[(ngModel)]="ldap.sslCaPath"
/>
</div>
</div>
<div class="mb-3">
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
id="certDoNotVerify"
[(ngModel)]="ldap.sslAllowUnauthorized"
name="CertDoNoVerify"
/>
<label class="form-check-label" for="certDoNotVerify">{{
"ldapCertDoNotVerify" | i18n
}}</label>
</div>
</div>
</div>
<div class="mb-3" [hidden]="true"> <div class="mb-3" [hidden]="true">
<div class="form-check"> <div class="form-check">
<input <input
@@ -221,12 +211,10 @@
name="Username" name="Username"
[(ngModel)]="ldap.username" [(ngModel)]="ldap.username"
/> />
@if (ldap.ad) { <div class="form-text" *ngIf="ldap.ad">{{ "ex" | i18n }} company\admin</div>
<div class="form-text">{{ "ex" | i18n }} company\admin</div> <div class="form-text" *ngIf="!ldap.ad">
} {{ "ex" | i18n }} cn=admin,dc=company,dc=com
@if (!ldap.ad) { </div>
<div class="form-text">{{ "ex" | i18n }} cn=admin,dc=company,dc=com</div>
}
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="password" class="form-label">{{ "password" | i18n }}</label> <label for="password" class="form-label">{{ "password" | i18n }}</label>
@@ -616,24 +604,18 @@
name="UserFilter" name="UserFilter"
[(ngModel)]="sync.userFilter" [(ngModel)]="sync.userFilter"
></textarea> ></textarea>
@if (directory === directoryType.Ldap) { <div class="form-text" *ngIf="directory === directoryType.Ldap">
<div class="form-text"> {{ "ex" | i18n }} (&amp;(givenName=John)(|(l=Dallas)(l=Austin)))
{{ "ex" | i18n }} (&amp;(givenName=John)(|(l=Dallas)(l=Austin))) </div>
</div> <div class="form-text" *ngIf="directory === directoryType.EntraID">
} {{ "ex" | i18n }} exclude:joe&#64;company.com
@if (directory === directoryType.EntraID) { </div>
<div class="form-text">{{ "ex" | i18n }} exclude:joe&#64;company.com</div> <div class="form-text" *ngIf="directory === directoryType.Okta">
} {{ "ex" | i18n }} exclude:joe&#64;company.com | profile.firstName eq "John"
@if (directory === directoryType.Okta) { </div>
<div class="form-text"> <div class="form-text" *ngIf="directory === directoryType.GSuite">
{{ "ex" | i18n }} exclude:joe&#64;company.com | profile.firstName eq "John" {{ "ex" | i18n }} exclude:joe&#64;company.com | orgUnitPath=/Engineering
</div> </div>
}
@if (directory === directoryType.GSuite) {
<div class="form-text">
{{ "ex" | i18n }} exclude:joe&#64;company.com | orgUnitPath=/Engineering
</div>
}
</div> </div>
<div class="mb-3" [hidden]="directory != directoryType.Ldap"> <div class="mb-3" [hidden]="directory != directoryType.Ldap">
<label for="userPath" class="form-label">{{ "userPath" | i18n }}</label> <label for="userPath" class="form-label">{{ "userPath" | i18n }}</label>
@@ -699,20 +681,18 @@
name="GroupFilter" name="GroupFilter"
[(ngModel)]="sync.groupFilter" [(ngModel)]="sync.groupFilter"
></textarea> ></textarea>
@if (directory === directoryType.Ldap) { <div class="form-text" *ngIf="directory === directoryType.Ldap">
<div class="form-text"> {{ "ex" | i18n }} (&amp;(objectClass=group)(!(cn=Sales*))(!(cn=IT*)))
{{ "ex" | i18n }} (&amp;(objectClass=group)(!(cn=Sales*))(!(cn=IT*))) </div>
</div> <div class="form-text" *ngIf="directory === directoryType.EntraID">
} {{ "ex" | i18n }} include:Sales,IT
@if (directory === directoryType.EntraID) { </div>
<div class="form-text">{{ "ex" | i18n }} include:Sales,IT</div> <div class="form-text" *ngIf="directory === directoryType.Okta">
} {{ "ex" | i18n }} include:Sales,IT | type eq "APP_GROUP"
@if (directory === directoryType.Okta) { </div>
<div class="form-text">{{ "ex" | i18n }} include:Sales,IT | type eq "APP_GROUP"</div> <div class="form-text" *ngIf="directory === directoryType.GSuite">
} {{ "ex" | i18n }} include:Sales,IT
@if (directory === directoryType.GSuite) { </div>
<div class="form-text">{{ "ex" | i18n }} include:Sales,IT</div>
}
</div> </div>
<div class="mb-3" [hidden]="directory != directoryType.Ldap"> <div class="mb-3" [hidden]="directory != directoryType.Ldap">
<label for="groupPath" class="form-label">{{ "groupPath" | i18n }}</label> <label for="groupPath" class="form-label">{{ "groupPath" | i18n }}</label>
@@ -723,12 +703,8 @@
name="GroupPath" name="GroupPath"
[(ngModel)]="sync.groupPath" [(ngModel)]="sync.groupPath"
/> />
@if (!ldap.ad) { <div class="form-text" *ngIf="!ldap.ad">{{ "ex" | i18n }} CN=Groups</div>
<div class="form-text">{{ "ex" | i18n }} CN=Groups</div> <div class="form-text" *ngIf="ldap.ad">{{ "ex" | i18n }} CN=Users</div>
}
@if (ldap.ad) {
<div class="form-text">{{ "ex" | i18n }} CN=Users</div>
}
</div> </div>
<div [hidden]="directory != directoryType.Ldap || ldap.ad"> <div [hidden]="directory != directoryType.Ldap || ldap.ad">
<div class="mb-3"> <div class="mb-3">

View File

@@ -28,4 +28,4 @@ $danger: map_get($theme-colors, "danger");
$secondary: map_get($theme-colors, "secondary"); $secondary: map_get($theme-colors, "secondary");
$secondary-alt: map_get($theme-colors, "secondary-alt"); $secondary-alt: map_get($theme-colors, "secondary-alt");
@import "bootstrap/scss/bootstrap.scss"; @import "~bootstrap/scss/bootstrap.scss";

View File

@@ -1,4 +1,4 @@
@import "bootstrap/scss/_variables.scss"; @import "~bootstrap/scss/_variables.scss";
html.os_windows { html.os_windows {
body { body {

View File

@@ -1,4 +1,4 @@
@import "bootstrap/scss/_variables.scss"; @import "~bootstrap/scss/_variables.scss";
body { body {
padding: 10px 0 20px 0; padding: 10px 0 20px 0;

View File

@@ -1,6 +1,6 @@
@import "ngx-toastr/toastr"; @import "~ngx-toastr/toastr";
@import "bootstrap/scss/_variables.scss"; @import "~bootstrap/scss/_variables.scss";
.toast-container { .toast-container {
.toast-close-button { .toast-close-button {

View File

@@ -1,7 +1,7 @@
import { webcrypto } from "crypto"; import { webcrypto } from "crypto";
import { TextEncoder, TextDecoder } from "util";
Object.assign(globalThis, { TextEncoder, TextDecoder }); import "jest-preset-angular/setup-jest";
Object.defineProperty(window, "CSS", { value: null }); Object.defineProperty(window, "CSS", { value: null });
Object.defineProperty(window, "getComputedStyle", { Object.defineProperty(window, "getComputedStyle", {
value: () => { value: () => {

View File

@@ -5,7 +5,7 @@
}, },
"compilerOptions": { "compilerOptions": {
"pretty": true, "pretty": true,
"moduleResolution": "bundler", "moduleResolution": "node",
"noImplicitAny": true, "noImplicitAny": true,
"target": "ES2016", "target": "ES2016",
"module": "ES2020", "module": "ES2020",