Skip to content

Commit 93a7608

Browse files
Separated runtime and UI configurations (#486)
Separated runtime and UI configurations
1 parent aa8829d commit 93a7608

13 files changed

+96
-102
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
### Changed
1414
- Readme section: modified 'Run' button into a link
1515
- Hint extension for tile widget account
16+
- Separated runtime and UI configurations
1617
### Fixed
1718
- Typo in feature flags (enableDatasetEnvVarsManagement)
1819
^

images/kamu-web-ui/Dockerfile

-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,5 @@ RUN cd /usr/share/nginx/html && \
1717
rm -r kamu-web-ui-any.tar.gz kamu-web-ui-any
1818

1919
COPY runtime-config.json /usr/share/nginx/html/assets/runtime-config.json
20-
COPY runtime-config-single-tenant.json /usr/share/nginx/html/assets/runtime-config-single-tenant.json
2120

2221
USER nginx

images/kamu-web-ui/runtime-config-single-tenant.json

-13
This file was deleted.
+1-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
{
22
"apiServerGqlUrl": "http://localhost:8080/graphql",
33
"apiServerHttpUrl": "http://localhost:8080",
4-
"githubClientId": "361a3b4fda86d0234d2f",
5-
"ingestUploadFileLimitMb": 50,
6-
"featureFlags": {
7-
"enableLogout": true
8-
}
4+
"githubClientId": "361a3b4fda86d0234d2f"
95
}

src/app/api/mock/auth.mock.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { GraphQLError } from "graphql";
22
import { AccountFragment, AccountType, FetchAccountDetailsMutation, LoginMutation } from "../kamu.graphql.interface";
3-
import { AppConfigLoginInstructions, LoginMethod } from "src/app/app-config.model";
3+
import { AppLoginInstructions, LoginMethod } from "src/app/app-config.model";
44
import { PasswordLoginCredentials } from "../auth.api.model";
55

66
export const TEST_GITHUB_CODE = "12345";
@@ -17,7 +17,7 @@ const mockPasswordLoginCredentials: PasswordLoginCredentials = {
1717
password: TEST_PASSWORD,
1818
};
1919

20-
export const mockLoginInstructions: AppConfigLoginInstructions = {
20+
export const mockLoginInstructions: AppLoginInstructions = {
2121
loginMethod: LoginMethod.PASSWORD,
2222
loginCredentialsJson: JSON.stringify(mockPasswordLoginCredentials),
2323
};

src/app/app-config.model.ts

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
export interface AppConfig {
1+
export interface AppRuntimeConfig {
22
apiServerGqlUrl: string;
33
apiServerHttpUrl: string;
44
githubClientId?: string;
5-
ingestUploadFileLimitMb: number;
6-
featureFlags: AppConfigFeatureFlags;
7-
loginInstructions?: AppConfigLoginInstructions;
5+
loginInstructions?: AppLoginInstructions;
86
grafanaLogs?: GrafanaLogsConfiguration;
97
}
108

11-
export interface AppConfigLoginInstructions {
9+
export interface AppLoginInstructions {
1210
loginMethod: string;
1311
loginCredentialsJson: string;
1412
}
@@ -18,14 +16,19 @@ export enum LoginMethod {
1816
GITHUB = "oauth_github",
1917
}
2018

21-
export interface AppConfigFeatureFlags {
19+
export interface GrafanaLogsConfiguration {
20+
taskDetailsUrl?: string;
21+
flowHistoryUrl?: string;
22+
}
23+
24+
export interface AppUIConfig {
25+
ingestUploadFileLimitMb: number;
26+
featureFlags: AppUIConfigFeatureFlags;
27+
}
28+
29+
export interface AppUIConfigFeatureFlags {
2230
enableLogout: boolean;
2331
enableScheduling: boolean;
2432
enableDatasetEnvVarsManagement: boolean;
2533
enableTermsOfService: boolean;
2634
}
27-
28-
export interface GrafanaLogsConfiguration {
29-
taskDetailsUrl?: string;
30-
flowHistoryUrl?: string;
31-
}

src/app/app-config.service.ts

+59-38
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,119 @@
11
import { Injectable } from "@angular/core";
22
import {
3-
AppConfig,
4-
AppConfigFeatureFlags,
5-
AppConfigLoginInstructions,
3+
AppRuntimeConfig,
4+
AppUIConfigFeatureFlags,
5+
AppLoginInstructions,
66
GrafanaLogsConfiguration,
7+
AppUIConfig,
78
} from "./app-config.model";
89
import { environment } from "src/environments/environment";
910
import { MaybeUndefined } from "./common/app.types";
11+
import AppValues from "./common/app.values";
1012

1113
@Injectable({
1214
providedIn: "root",
1315
})
1416
export class AppConfigService {
15-
private appConfig?: AppConfig;
17+
private appRuntimeConfig?: AppRuntimeConfig;
18+
private appUiConfig?: AppUIConfig;
1619

1720
get apiServerUrl(): string {
18-
if (!this.appConfig) {
19-
this.appConfig = AppConfigService.loadAppConfig();
21+
if (!this.appRuntimeConfig) {
22+
this.appRuntimeConfig = AppConfigService.loadAppRuntimeConfig();
2023
}
2124

2225
return new URL(this.apiServerGqlUrl).origin;
2326
}
2427

2528
get apiServerGqlUrl(): string {
26-
if (!this.appConfig) {
27-
this.appConfig = AppConfigService.loadAppConfig();
29+
if (!this.appRuntimeConfig) {
30+
this.appRuntimeConfig = AppConfigService.loadAppRuntimeConfig();
2831
}
2932

30-
return this.appConfig.apiServerGqlUrl;
33+
return this.appRuntimeConfig.apiServerGqlUrl;
3134
}
3235

3336
get apiServerHttpUrl(): string {
34-
if (!this.appConfig) {
35-
this.appConfig = AppConfigService.loadAppConfig();
37+
if (!this.appRuntimeConfig) {
38+
this.appRuntimeConfig = AppConfigService.loadAppRuntimeConfig();
3639
}
3740

38-
return this.appConfig.apiServerHttpUrl;
41+
return this.appRuntimeConfig.apiServerHttpUrl;
3942
}
4043

41-
get ingestUploadFileLimitMb(): number {
42-
if (!this.appConfig) {
43-
this.appConfig = AppConfigService.loadAppConfig();
44+
get githubClientId(): MaybeUndefined<string> {
45+
if (!this.appRuntimeConfig) {
46+
this.appRuntimeConfig = AppConfigService.loadAppRuntimeConfig();
4447
}
4548

46-
return this.appConfig.ingestUploadFileLimitMb;
49+
return this.appRuntimeConfig.githubClientId;
4750
}
4851

49-
get githubClientId(): MaybeUndefined<string> {
50-
if (!this.appConfig) {
51-
this.appConfig = AppConfigService.loadAppConfig();
52+
get grafanaLogs(): GrafanaLogsConfiguration | null {
53+
if (!this.appRuntimeConfig) {
54+
this.appRuntimeConfig = AppConfigService.loadAppRuntimeConfig();
5255
}
5356

54-
return this.appConfig.githubClientId;
57+
return this.appRuntimeConfig.grafanaLogs ?? null;
5558
}
5659

57-
get featureFlags(): AppConfigFeatureFlags {
58-
if (!this.appConfig) {
59-
this.appConfig = AppConfigService.loadAppConfig();
60+
get loginInstructions(): AppLoginInstructions | null {
61+
if (!this.appRuntimeConfig) {
62+
this.appRuntimeConfig = AppConfigService.loadAppRuntimeConfig();
6063
}
6164

62-
return this.appConfig.featureFlags;
65+
if (this.appRuntimeConfig.loginInstructions) {
66+
return this.appRuntimeConfig.loginInstructions;
67+
} else {
68+
return null;
69+
}
6370
}
6471

65-
get grafanaLogs(): GrafanaLogsConfiguration | null {
66-
if (!this.appConfig) {
67-
this.appConfig = AppConfigService.loadAppConfig();
72+
get ingestUploadFileLimitMb(): number {
73+
if (!this.appRuntimeConfig) {
74+
this.appRuntimeConfig = AppConfigService.loadAppRuntimeConfig();
75+
}
76+
if (!this.appUiConfig) {
77+
this.appUiConfig = AppConfigService.loadAppUIConfig(this.appRuntimeConfig);
6878
}
6979

70-
return this.appConfig.grafanaLogs ?? null;
80+
return this.appUiConfig.ingestUploadFileLimitMb;
7181
}
7282

73-
get loginInstructions(): AppConfigLoginInstructions | null {
74-
if (!this.appConfig) {
75-
this.appConfig = AppConfigService.loadAppConfig();
83+
get featureFlags(): AppUIConfigFeatureFlags {
84+
if (!this.appRuntimeConfig) {
85+
this.appRuntimeConfig = AppConfigService.loadAppRuntimeConfig();
7686
}
77-
78-
if (this.appConfig.loginInstructions) {
79-
return this.appConfig.loginInstructions;
80-
} else {
81-
return null;
87+
if (!this.appUiConfig) {
88+
this.appUiConfig = AppConfigService.loadAppUIConfig(this.appRuntimeConfig);
8289
}
90+
91+
return this.appUiConfig.featureFlags;
8392
}
8493

85-
private static loadAppConfig(): AppConfig {
94+
private static loadAppRuntimeConfig(): AppRuntimeConfig {
8695
const request = new XMLHttpRequest();
8796
request.open("GET", environment.runtime_config_file, false);
8897
request.send(null);
89-
const data: AppConfig = JSON.parse(request.responseText) as AppConfig;
98+
const data: AppRuntimeConfig = JSON.parse(request.responseText) as AppRuntimeConfig;
9099
return {
91100
...data,
92101
apiServerGqlUrl: AppConfigService.toRemoteURL(data.apiServerGqlUrl),
93102
};
94103
}
95104

105+
private static loadAppUIConfig(app_runtime_config: AppRuntimeConfig): AppUIConfig {
106+
const request = new XMLHttpRequest();
107+
request.open("GET", app_runtime_config.apiServerHttpUrl + "/ui-config", false);
108+
try {
109+
request.send(null);
110+
const data: AppUIConfig = JSON.parse(request.responseText) as AppUIConfig;
111+
return data;
112+
} catch (error) {
113+
return AppValues.DEFAULT_UI_CONFIGURATION;
114+
}
115+
}
116+
96117
// If loopback or any address is used - replace hostname with hostname from the browser
97118
private static toRemoteURL(url: string): string {
98119
const turl = new URL(url);

src/app/app.component.ts

+2-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { MaybeNull } from "./common/app.types";
1212
import _ from "lodash";
1313
import { isMobileView, promiseWithCatch } from "./common/app.helpers";
1414
import { AppConfigService } from "./app-config.service";
15-
import { AppConfigFeatureFlags, LoginMethod } from "./app-config.model";
15+
import { AppUIConfigFeatureFlags, LoginMethod } from "./app-config.model";
1616
import { LoginService } from "./auth/login/login.service";
1717
import { loadErrorMessages } from "@apollo/client/dev";
1818
import { isDevMode } from "@angular/core";
@@ -37,19 +37,13 @@ export class AppComponent extends BaseComponent implements OnInit {
3737
accountType: AccountType.User,
3838
isAdmin: false,
3939
};
40-
public static readonly DEFAULT_FEATURE_FLAGS: AppConfigFeatureFlags = {
41-
enableLogout: true,
42-
enableScheduling: true,
43-
enableDatasetEnvVarsManagement: true,
44-
enableTermsOfService: true,
45-
};
4640

4741
public readonly APP_LOGO = `/${AppValues.APP_LOGO}`;
4842

4943
public isMobileView = false;
5044
public isHeaderVisible = true;
5145

52-
public featureFlags: AppConfigFeatureFlags = AppComponent.DEFAULT_FEATURE_FLAGS;
46+
public featureFlags: AppUIConfigFeatureFlags = AppValues.DEFAULT_UI_FEATURE_FLAGS;
5347
public loggedAccount: AccountFragment = AppComponent.ANONYMOUS_ACCOUNT_INFO;
5448
public loginMethods: LoginMethod[] = [];
5549

src/app/auth/logged-user.service.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { isNull } from "lodash";
77
import { AppConfigService } from "../app-config.service";
88
import { AccountFragment } from "../api/kamu.graphql.interface";
99
import { UnsubscribeDestroyRefAdapter } from "../common/unsubscribe.ondestroy.adapter";
10-
import { AppConfigLoginInstructions } from "../app-config.model";
10+
import { AppLoginInstructions } from "../app-config.model";
1111
import { Apollo } from "apollo-angular";
1212
import { promiseWithCatch } from "../common/app.helpers";
1313
import { LoginService } from "./login/login.service";
@@ -39,7 +39,7 @@ export class LoggedUserService extends UnsubscribeDestroyRefAdapter {
3939
}
4040

4141
public initializeCompletes(): Observable<void> {
42-
const loginInstructions: AppConfigLoginInstructions | null = this.appConfigService.loginInstructions;
42+
const loginInstructions: AppLoginInstructions | null = this.appConfigService.loginInstructions;
4343
if (loginInstructions) {
4444
return this.loginService.genericLogin(
4545
loginInstructions.loginMethod,

src/app/common/app.values.ts

+13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Injectable } from "@angular/core";
2+
import { AppUIConfig, AppUIConfigFeatureFlags } from "../app-config.model";
23

34
@Injectable()
45
export default class AppValues {
@@ -50,4 +51,16 @@ const language = 'typescript';
5051
5152
### Blockquote
5253
> Blockquote to the max`;
54+
55+
public static readonly DEFAULT_UI_FEATURE_FLAGS: AppUIConfigFeatureFlags = {
56+
enableLogout: true,
57+
enableScheduling: true,
58+
enableDatasetEnvVarsManagement: true,
59+
enableTermsOfService: true,
60+
};
61+
62+
public static readonly DEFAULT_UI_CONFIGURATION: AppUIConfig = {
63+
ingestUploadFileLimitMb: 50,
64+
featureFlags: AppValues.DEFAULT_UI_FEATURE_FLAGS,
65+
};
5366
}

src/app/components/app-header/app-header.component.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { AccountFragment } from "src/app/api/kamu.graphql.interface";
2323
import { NgbTypeaheadSelectItemEvent } from "@ng-bootstrap/ng-bootstrap";
2424
import ProjectLinks from "src/app/project-links";
2525
import { NavigationService } from "src/app/services/navigation.service";
26-
import { AppConfigFeatureFlags, LoginMethod } from "src/app/app-config.model";
26+
import { AppUIConfigFeatureFlags, LoginMethod } from "src/app/app-config.model";
2727
import { AccountSettingsTabs } from "src/app/auth/settings/account-settings.constants";
2828
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
2929

@@ -40,7 +40,7 @@ export class AppHeaderComponent extends BaseComponent implements OnInit {
4040
@Input({ required: true }) public isMobileView: boolean;
4141
@Input({ required: true }) public isVisible: boolean;
4242
@Input({ required: true }) public loggedAccount: AccountFragment;
43-
@Input({ required: true }) public featureFlags: AppConfigFeatureFlags;
43+
@Input({ required: true }) public featureFlags: AppUIConfigFeatureFlags;
4444
@Input({ required: true }) public loginMethods: LoginMethod[];
4545

4646
@Output() public onSelectedDataset = new EventEmitter<DatasetAutocompleteItem>();

src/assets/runtime-config-single-tenant.json

-13
This file was deleted.

src/assets/runtime-config.json

-7
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@
22
"apiServerGqlUrl": "http://localhost:8080/graphql",
33
"apiServerHttpUrl": "http://localhost:8080",
44
"githubClientId": "361a3b4fda86d0234d2f",
5-
"ingestUploadFileLimitMb": 50,
6-
"featureFlags": {
7-
"enableLogout": true,
8-
"enableScheduling": true,
9-
"enableDatasetEnvVarsManagement": true,
10-
"enableTermsOfService": true
11-
},
125
"grafanaLogs": {
136
"taskDetailsUrl": " https://grafana.sha.stg.internal.kamu.dev/explore?schemaVersion=1&panes=%7B%22LYy%22%3A%7B%22datasource%22%3A%22365dd1cc-3781-43c1-86a1-a3f78c6ab420%22%2C%22queries%22%3A%5B%7B%22refId%22%3A%22A%22%2C%22expr%22%3A%22%7Bjob%3D%5C%22europort%2Fkamu-api-server%5C%22%7D+%7C+json+root_span%2C+task_id%3D%5C%22log.spans%5B0%5D.task_id%5C%22%2C+target%3D%5C%22log.target%5C%22%2C+message%3D%5C%22log.fields.message%5C%22+%7C+task_id+%3D+%60{{taskId}}%60+%7C%3D+%60%60%22%2C%22queryType%22%3A%22range%22%2C%22datasource%22%3A%7B%22type%22%3A%22loki%22%2C%22uid%22%3A%22365dd1cc-3781-43c1-86a1-a3f78c6ab420%22%7D%2C%22editorMode%22%3A%22builder%22%7D%5D%2C%22range%22%3A%7B%22from%22%3A%22{{fromTime}}%22%2C%22to%22%3A%22{{toTime}}%22%7D%7D%7D&orgId=1",
147
"flowHistoryUrl": ""

0 commit comments

Comments
 (0)