Merge "Migrate config-model to new pattern"
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
index 037e11f..88ade26 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
@@ -29,7 +29,6 @@
} from '../../../types/common';
import {InheritedBooleanInfoConfiguredValue} from '../../../constants/constants';
import {getAppContext} from '../../../services/app-context';
-import {serverConfig$} from '../../../services/config/config-model';
import {formStyles} from '../../../styles/gr-form-styles';
import {sharedStyles} from '../../../styles/shared-styles';
import {LitElement, PropertyValues, css, html} from 'lit';
@@ -77,6 +76,8 @@
private readonly restApiService = getAppContext().restApiService;
+ private readonly configModel = getAppContext().configModel;
+
constructor() {
super();
this.query = (input: string) => this.getRepoBranchesSuggestions(input);
@@ -86,7 +87,7 @@
super.connectedCallback();
if (!this.repoName) return;
- subscribe(this, serverConfig$, config => {
+ subscribe(this, this.configModel.serverConfig$, config => {
this.privateChangesEnabled =
config?.change?.disable_private_changes ?? false;
});
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-results.ts b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
index 342f54b..ca53d28 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-results.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
@@ -64,7 +64,6 @@
} from '../../types/common';
import {labels$, latestPatchNum$} from '../../services/change/change-model';
import {getAppContext} from '../../services/app-context';
-import {repoConfig$} from '../../services/config/config-model';
import {spinnerStyles} from '../../styles/gr-spinner-styles';
import {
getLabelStatus,
@@ -540,6 +539,8 @@
private changeService = getAppContext().changeService;
+ private configModel = getAppContext().configModel;
+
static override get styles() {
return [
sharedStyles,
@@ -563,7 +564,7 @@
constructor() {
super();
- subscribe(this, repoConfig$, x => (this.repoConfig = x));
+ subscribe(this, this.configModel.repoConfig$, x => (this.repoConfig = x));
}
override render() {
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
index 1391257..be36640 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
@@ -37,8 +37,6 @@
import {AuthType} from '../../../constants/constants';
import {DropdownLink} from '../../shared/gr-dropdown/gr-dropdown';
import {getAppContext} from '../../../services/app-context';
-import {serverConfig$} from '../../../services/config/config-model';
-import {assertIsDefined} from '../../../utils/common-util';
type MainHeaderLink = RequireProperties<DropdownLink, 'url' | 'name'>;
@@ -160,6 +158,8 @@
private readonly userModel = getAppContext().userModel;
+ private readonly configModel = getAppContext().configModel;
+
private subscriptions: Subscription[] = [];
override ready() {
@@ -168,11 +168,6 @@
}
override connectedCallback() {
- // TODO(brohlfs): This just ensures that the userModel is instantiated at
- // all. We need the service to manage the model, but we are not making any
- // direct calls. Will need to find a better solution to this problem ...
- assertIsDefined(this.userModel);
-
super.connectedCallback();
this._loadAccount();
@@ -187,7 +182,7 @@
})
);
this.subscriptions.push(
- serverConfig$.subscribe(config => {
+ this.configModel.serverConfig$.subscribe(config => {
if (!config) return;
this._retrieveFeedbackURL(config);
this._retrieveRegisterURL(config);
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index c89fe20..ebfe407 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -235,10 +235,6 @@
constructor() {
super();
- // We just want to instantiate this service somewhere. It is reacting to
- // model changes and updates the config model, but at the moment the service
- // is not called from anywhere.
- getAppContext().configService;
document.addEventListener(EventType.PAGE_ERROR, e => {
this._handlePageError(e);
});
diff --git a/polygerrit-ui/app/embed/gr-diff-app-context-init.ts b/polygerrit-ui/app/embed/gr-diff-app-context-init.ts
index 0297795..17e0994 100644
--- a/polygerrit-ui/app/embed/gr-diff-app-context-init.ts
+++ b/polygerrit-ui/app/embed/gr-diff-app-context-init.ts
@@ -92,8 +92,8 @@
storageService: (_ctx: Partial<AppContext>) => {
throw new Error('storageService is not implemented');
},
- configService: (_ctx: Partial<AppContext>) => {
- throw new Error('configService is not implemented');
+ configModel: (_ctx: Partial<AppContext>) => {
+ throw new Error('configModel is not implemented');
},
userModel: (_ctx: Partial<AppContext>) => {
throw new Error('userModel is not implemented');
diff --git a/polygerrit-ui/app/services/app-context-init.ts b/polygerrit-ui/app/services/app-context-init.ts
index 001b71d..bfc56b4 100644
--- a/polygerrit-ui/app/services/app-context-init.ts
+++ b/polygerrit-ui/app/services/app-context-init.ts
@@ -25,12 +25,12 @@
import {ChecksService} from './checks/checks-service';
import {GrJsApiInterface} from '../elements/shared/gr-js-api-interface/gr-js-api-interface-element';
import {GrStorageService} from './storage/gr-storage_impl';
-import {ConfigService} from './config/config-service';
import {UserModel} from './user/user-model';
import {CommentsService} from './comments/comments-service';
import {ShortcutsService} from './shortcuts/shortcuts-service';
import {BrowserModel} from './browser/browser-model';
import {assertIsDefined} from '../utils/common-util';
+import {ConfigModel} from './config/config-model';
/**
* The AppContext lazy initializator for all services
@@ -70,9 +70,9 @@
return new GrJsApiInterface(ctx.reportingService!);
},
storageService: (_ctx: Partial<AppContext>) => new GrStorageService(),
- configService: (ctx: Partial<AppContext>) => {
+ configModel: (ctx: Partial<AppContext>) => {
assertIsDefined(ctx.restApiService, 'restApiService');
- return new ConfigService(ctx.restApiService!);
+ return new ConfigModel(ctx.restApiService!);
},
userModel: (ctx: Partial<AppContext>) => {
assertIsDefined(ctx.restApiService, 'restApiService');
diff --git a/polygerrit-ui/app/services/app-context.ts b/polygerrit-ui/app/services/app-context.ts
index d5e595d..53064fa 100644
--- a/polygerrit-ui/app/services/app-context.ts
+++ b/polygerrit-ui/app/services/app-context.ts
@@ -24,11 +24,11 @@
import {ChecksService} from './checks/checks-service';
import {JsApiService} from '../elements/shared/gr-js-api-interface/gr-js-api-types';
import {StorageService} from './storage/gr-storage';
-import {ConfigService} from './config/config-service';
import {UserModel} from './user/user-model';
import {CommentsService} from './comments/comments-service';
import {ShortcutsService} from './shortcuts/shortcuts-service';
import {BrowserModel} from './browser/browser-model';
+import {ConfigModel} from './config/config-model';
export interface AppContext {
flagsService: FlagsService;
@@ -41,7 +41,7 @@
checksService: ChecksService;
jsApiService: JsApiService;
storageService: StorageService;
- configService: ConfigService;
+ configModel: ConfigModel;
userModel: UserModel;
browserModel: BrowserModel;
shortcutsService: ShortcutsService;
diff --git a/polygerrit-ui/app/services/config/config-model.ts b/polygerrit-ui/app/services/config/config-model.ts
index f5e10c5..c0e6028 100644
--- a/polygerrit-ui/app/services/config/config-model.ts
+++ b/polygerrit-ui/app/services/config/config-model.ts
@@ -14,40 +14,74 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {ConfigInfo, ServerInfo} from '../../types/common';
-import {BehaviorSubject, Observable} from 'rxjs';
-import {map, distinctUntilChanged} from 'rxjs/operators';
+import {ConfigInfo, RepoName, ServerInfo} from '../../types/common';
+import {BehaviorSubject, from, Observable, of, Subscription} from 'rxjs';
+import {switchMap} from 'rxjs/operators';
+import {Finalizable} from '../registry';
+import {RestApiService} from '../gr-rest-api/gr-rest-api';
+import {repo$} from '../change/change-model';
+import {select} from '../../utils/observable-util';
-interface ConfigState {
+export interface ConfigState {
repoConfig?: ConfigInfo;
serverConfig?: ServerInfo;
}
-// TODO: Figure out how to best enforce immutability of all states. Use Immer?
-// Use DeepReadOnly?
-const initialState: ConfigState = {};
+export class ConfigModel implements Finalizable {
+ // TODO: Figure out how to best enforce immutability of all states. Use Immer?
+ // Use DeepReadOnly?
+ private initialState: ConfigState = {};
-const privateState$ = new BehaviorSubject(initialState);
+ private privateState$ = new BehaviorSubject(this.initialState);
-// Re-exporting as Observable so that you can only subscribe, but not emit.
-export const configState$: Observable<ConfigState> = privateState$;
+ // Re-exporting as Observable so that you can only subscribe, but not emit.
+ public configState$: Observable<ConfigState> =
+ this.privateState$.asObservable();
-export function updateRepoConfig(repoConfig?: ConfigInfo) {
- const current = privateState$.getValue();
- privateState$.next({...current, repoConfig});
+ public repoConfig$ = select(
+ this.privateState$,
+ configState => configState.repoConfig
+ );
+
+ public serverConfig$ = select(
+ this.privateState$,
+ configState => configState.serverConfig
+ );
+
+ private subscriptions: Subscription[];
+
+ constructor(readonly restApiService: RestApiService) {
+ this.subscriptions = [
+ from(this.restApiService.getConfig()).subscribe((config?: ServerInfo) => {
+ this.updateServerConfig(config);
+ }),
+ repo$
+ .pipe(
+ switchMap((repo?: RepoName) => {
+ if (repo === undefined) return of(undefined);
+ return from(this.restApiService.getProjectConfig(repo));
+ })
+ )
+ .subscribe((repoConfig?: ConfigInfo) => {
+ this.updateRepoConfig(repoConfig);
+ }),
+ ];
+ }
+
+ updateRepoConfig(repoConfig?: ConfigInfo) {
+ const current = this.privateState$.getValue();
+ this.privateState$.next({...current, repoConfig});
+ }
+
+ updateServerConfig(serverConfig?: ServerInfo) {
+ const current = this.privateState$.getValue();
+ this.privateState$.next({...current, serverConfig});
+ }
+
+ finalize() {
+ for (const s of this.subscriptions) {
+ s.unsubscribe();
+ }
+ this.subscriptions = [];
+ }
}
-
-export function updateServerConfig(serverConfig?: ServerInfo) {
- const current = privateState$.getValue();
- privateState$.next({...current, serverConfig});
-}
-
-export const repoConfig$ = configState$.pipe(
- map(configState => configState.repoConfig),
- distinctUntilChanged()
-);
-
-export const serverConfig$ = configState$.pipe(
- map(configState => configState.serverConfig),
- distinctUntilChanged()
-);
diff --git a/polygerrit-ui/app/services/config/config-service.ts b/polygerrit-ui/app/services/config/config-service.ts
deleted file mode 100644
index 667f347..0000000
--- a/polygerrit-ui/app/services/config/config-service.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * @license
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {updateRepoConfig, updateServerConfig} from './config-model';
-import {repo$} from '../change/change-model';
-import {switchMap} from 'rxjs/operators';
-import {ConfigInfo, RepoName, ServerInfo} from '../../types/common';
-import {from, of, Subscription} from 'rxjs';
-import {RestApiService} from '../gr-rest-api/gr-rest-api';
-import {Finalizable} from '../registry';
-
-export class ConfigService implements Finalizable {
- private readonly subscriptions: Subscription[] = [];
-
- constructor(readonly restApiService: RestApiService) {
- this.subscriptions.push(
- from(this.restApiService.getConfig()).subscribe((config?: ServerInfo) => {
- updateServerConfig(config);
- })
- );
- this.subscriptions.push(
- repo$
- .pipe(
- switchMap((repo?: RepoName) => {
- if (repo === undefined) return of(undefined);
- return from(this.restApiService.getProjectConfig(repo));
- })
- )
- .subscribe((repoConfig?: ConfigInfo) => {
- updateRepoConfig(repoConfig);
- })
- );
- }
-
- finalize() {
- for (const s of this.subscriptions) {
- s.unsubscribe();
- }
- this.subscriptions.splice(0, this.subscriptions.length);
- }
-}
diff --git a/polygerrit-ui/app/test/test-app-context-init.ts b/polygerrit-ui/app/test/test-app-context-init.ts
index a710b00..8bcd395b 100644
--- a/polygerrit-ui/app/test/test-app-context-init.ts
+++ b/polygerrit-ui/app/test/test-app-context-init.ts
@@ -28,11 +28,11 @@
import {ChangeService} from '../services/change/change-service';
import {ChecksService} from '../services/checks/checks-service';
import {GrJsApiInterface} from '../elements/shared/gr-js-api-interface/gr-js-api-interface-element';
-import {ConfigService} from '../services/config/config-service';
import {UserModel} from '../services/user/user-model';
import {CommentsService} from '../services/comments/comments-service';
import {ShortcutsService} from '../services/shortcuts/shortcuts-service';
import {BrowserModel} from '../services/browser/browser-model';
+import {ConfigModel} from '../services/config/config-model';
let appContext: (AppContext & Finalizable) | undefined;
@@ -64,9 +64,9 @@
return new GrJsApiInterface(ctx.reportingService!);
},
storageService: (_ctx: Partial<AppContext>) => grStorageMock,
- configService: (ctx: Partial<AppContext>) => {
+ configModel: (ctx: Partial<AppContext>) => {
assertIsDefined(ctx.restApiService, 'restApiService');
- return new ConfigService(ctx.restApiService!);
+ return new ConfigModel(ctx.restApiService!);
},
userModel: (ctx: Partial<AppContext>) => {
assertIsDefined(ctx.restApiService, 'restApiService');