Skip to content

Commit 39e9649

Browse files
authored
Release 3.39.2
2 parents db04fdd + 0334e70 commit 39e9649

23 files changed

+493
-145
lines changed

package-lock.json

Lines changed: 22 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"@fortawesome/free-regular-svg-icons": "^6.6.0",
4343
"@fortawesome/free-solid-svg-icons": "^6.6.0",
4444
"@ngneat/until-destroy": "^10.0.0",
45-
"@sentry/browser": "^8.20.0",
45+
"@sentry/angular": "^8.20.0",
4646
"angulartics2": "^14.0.0",
4747
"assert": "^2.1.0",
4848
"crypto-es": "^2.1.0",

src/app/app.module.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,15 @@
1717

1818
import { BrowserModule } from "@angular/platform-browser";
1919
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
20-
import { ErrorHandler, Inject, LOCALE_ID, NgModule } from "@angular/core";
20+
import {
21+
APP_INITIALIZER,
22+
ErrorHandler,
23+
Inject,
24+
LOCALE_ID,
25+
NgModule,
26+
} from "@angular/core";
2127
import { HttpClientModule } from "@angular/common/http";
28+
import * as Sentry from "@sentry/angular";
2229

2330
import { AppComponent } from "./app.component";
2431
import { allRoutes } from "./app.routing";
@@ -31,7 +38,6 @@ import {
3138
SwRegistrationOptions,
3239
} from "@angular/service-worker";
3340
import { environment } from "../environments/environment";
34-
import { LoggingErrorHandler } from "./core/logging/logging-error-handler";
3541
import { AnalyticsService } from "./core/analytics/analytics.service";
3642
import { ConfigurableEnumModule } from "./core/basic-datatypes/configurable-enum/configurable-enum.module";
3743
import { MatPaginatorIntl } from "@angular/material/paginator";
@@ -75,7 +81,7 @@ import { HistoricalDataModule } from "./features/historical-data/historical-data
7581
import { MatchingEntitiesModule } from "./features/matching-entities/matching-entities.module";
7682
import { ProgressDashboardWidgetModule } from "./features/dashboard-widgets/progress-dashboard-widget/progress-dashboard-widget.module";
7783
import { ReportingModule } from "./features/reporting/reporting.module";
78-
import { RouterModule } from "@angular/router";
84+
import { Router, RouterModule } from "@angular/router";
7985
import { TodosModule } from "./features/todos/todos.module";
8086
import moment from "moment";
8187
import { getLocaleFirstDayOfWeek } from "@angular/common";
@@ -141,7 +147,22 @@ import { AdminModule } from "./core/admin/admin.module";
141147
MatDialogModule,
142148
],
143149
providers: [
144-
{ provide: ErrorHandler, useClass: LoggingErrorHandler },
150+
/* Sentry setup */
151+
{
152+
provide: ErrorHandler,
153+
useValue: Sentry.createErrorHandler(),
154+
},
155+
{
156+
provide: Sentry.TraceService,
157+
deps: [Router],
158+
},
159+
{
160+
provide: APP_INITIALIZER,
161+
useFactory: () => () => {},
162+
deps: [Sentry.TraceService],
163+
multi: true,
164+
},
165+
145166
{ provide: MatPaginatorIntl, useValue: TranslatableMatPaginator() },
146167
{ provide: ComponentRegistry, useValue: componentRegistry },
147168
{ provide: EntityRegistry, useValue: entityRegistry },
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { ConfigurableEnumValue } from "./configurable-enum.interface";
2+
import { ConfigurableEnum } from "./configurable-enum";
3+
4+
describe("ConfigurableEnum", () => {
5+
let sampleValues: ConfigurableEnumValue[];
6+
let testEnum: ConfigurableEnum;
7+
8+
beforeEach(async () => {
9+
sampleValues = [
10+
{ id: "1", label: "one" },
11+
{ id: "2", label: "two" },
12+
];
13+
testEnum = new ConfigurableEnum("test-enum");
14+
testEnum.values = JSON.parse(JSON.stringify(sampleValues));
15+
});
16+
17+
it("should create", () => {
18+
expect(testEnum).toBeTruthy();
19+
});
20+
21+
it("should add option from value object", () => {
22+
const newOption: ConfigurableEnumValue = {
23+
id: "3",
24+
label: "three",
25+
color: "red",
26+
};
27+
const returnedOption = testEnum.addOption(newOption);
28+
expect(returnedOption).toEqual(newOption);
29+
expect(testEnum.values).toContain(newOption);
30+
expect(testEnum.values.length).toBe(sampleValues.length + 1);
31+
});
32+
33+
it("should add option from string", () => {
34+
const newOption: string = "three";
35+
const returnedOption = testEnum.addOption(newOption);
36+
expect(returnedOption.label).toEqual(newOption);
37+
expect(testEnum.values).toContain(
38+
jasmine.objectContaining({ id: "THREE", label: "three" }),
39+
);
40+
expect(testEnum.values.length).toBe(sampleValues.length + 1);
41+
});
42+
43+
it("should not add option for empty values", () => {
44+
testEnum.addOption("");
45+
testEnum.addOption(undefined);
46+
expect(testEnum.values).toEqual(sampleValues);
47+
});
48+
49+
it("should not add option for duplicate label", () => {
50+
expect(() => testEnum.addOption(sampleValues[0].label)).toThrowError();
51+
expect(testEnum.values).toEqual(sampleValues);
52+
});
53+
54+
it("should adapt generated id if duplicate", () => {
55+
const newOption: string = "1"; // already exists as id in sampleValues (but with different label)
56+
const returnedOption = testEnum.addOption(newOption);
57+
58+
expect(returnedOption.label).toEqual(newOption);
59+
expect(returnedOption.id).toEqual("1_");
60+
expect(testEnum.values).toContain(returnedOption);
61+
expect(testEnum.values.length).toBe(sampleValues.length + 1);
62+
});
63+
});

src/app/core/basic-datatypes/configurable-enum/configurable-enum.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,73 @@ import { Entity } from "../../entity/model/entity";
22
import { DatabaseEntity } from "../../entity/database-entity.decorator";
33
import { ConfigurableEnumValue } from "./configurable-enum.interface";
44
import { DatabaseField } from "../../entity/database-field.decorator";
5+
import { Logging } from "../../logging/logging.service";
56

67
@DatabaseEntity("ConfigurableEnum")
78
export class ConfigurableEnum extends Entity {
89
@DatabaseField() values: ConfigurableEnumValue[] = [];
10+
911
constructor(id?: string, values: ConfigurableEnumValue[] = []) {
1012
super(id);
1113
this.values = values;
1214
}
15+
16+
/**
17+
* Add a new valid option to the enum values, if it is not a duplicate or invalid.
18+
* Returns the newly added option upon success.
19+
* @param newOptionInput String or option object to be added
20+
*/
21+
addOption(
22+
newOptionInput: ConfigurableEnumValue | string,
23+
): ConfigurableEnumValue | undefined {
24+
const option: ConfigurableEnumValue =
25+
typeof newOptionInput === "string"
26+
? this.convertStringToOption(newOptionInput)
27+
: newOptionInput;
28+
29+
if (!option || !(option?.id && option?.label)) {
30+
Logging.debug(
31+
"Trying to add invalid enum option",
32+
newOptionInput,
33+
option,
34+
);
35+
return;
36+
}
37+
38+
// check for duplicates
39+
if (this.values.some((v) => v.label === option.label)) {
40+
throw new DuplicateEnumOptionException(newOptionInput);
41+
}
42+
if (this.values.some((v) => v.id === option.id)) {
43+
option.id = option.id + "_";
44+
}
45+
46+
this.values.push(option);
47+
return option;
48+
}
49+
50+
private convertStringToOption(
51+
newOption: string,
52+
): ConfigurableEnumValue | undefined {
53+
newOption = newOption.trim();
54+
if (newOption.length === 0) {
55+
return;
56+
}
57+
58+
return {
59+
id: newOption.toUpperCase(),
60+
label: newOption,
61+
};
62+
}
63+
}
64+
65+
/**
66+
* Error thrown when trying to add an option that already exists in the enum values.
67+
*/
68+
export class DuplicateEnumOptionException extends Error {
69+
constructor(newOptionInput) {
70+
super("Enum Option already exists");
71+
72+
this["newOptionInput"] = newOptionInput;
73+
}
1374
}

src/app/core/basic-datatypes/configurable-enum/configure-enum-popup/configure-enum-popup.component.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { MatButtonModule } from "@angular/material/button";
2323
import { ConfirmationDialogService } from "../../../common-components/confirmation-dialog/confirmation-dialog.service";
2424
import { EntityRegistry } from "../../../entity/database-entity.decorator";
2525
import { Entity } from "../../../entity/model/entity";
26+
import { OkButton } from "../../../common-components/confirmation-dialog/confirmation-dialog/confirmation-dialog.component";
2627

2728
@Component({
2829
selector: "app-configure-enum-popup",
@@ -126,11 +127,18 @@ export class ConfigureEnumPopupComponent {
126127
);
127128
}
128129

129-
createNewOption() {
130-
this.enumEntity.values.push({
131-
id: this.newOptionInput,
132-
label: this.newOptionInput,
133-
});
130+
async createNewOption() {
131+
try {
132+
this.enumEntity.addOption(this.newOptionInput);
133+
} catch (error) {
134+
await this.confirmationService.getConfirmation(
135+
$localize`Failed to create new option`,
136+
$localize`Couldn't create this new option. Please check if the value already exists.`,
137+
OkButton,
138+
);
139+
return;
140+
}
141+
134142
this.newOptionInput = "";
135143
}
136144
}

src/app/core/basic-datatypes/configurable-enum/enum-dropdown/enum-dropdown.component.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@ describe("EnumDropdownComponent", () => {
9797
const res = await component.createNewOption("second");
9898

9999
expect(confirmationSpy).toHaveBeenCalled();
100-
expect(res).toEqual({ id: "second", label: "second" });
100+
expect(res).toEqual({ id: "SECOND", label: "second" });
101101
expect(enumEntity.values).toEqual([
102102
{ id: "1", label: "first" },
103-
{ id: "second", label: "second" },
103+
{ id: "SECOND", label: "second" },
104104
]);
105105
expect(saveSpy).toHaveBeenCalledWith(enumEntity);
106106
});

src/app/core/basic-datatypes/configurable-enum/enum-dropdown/enum-dropdown.component.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
1515
import { ErrorHintComponent } from "../../../common-components/error-hint/error-hint.component";
1616
import { MatButtonModule } from "@angular/material/button";
1717
import { ConfirmationDialogService } from "../../../common-components/confirmation-dialog/confirmation-dialog.service";
18+
import { OkButton } from "../../../common-components/confirmation-dialog/confirmation-dialog/confirmation-dialog.component";
1819

1920
@Component({
2021
selector: "app-enum-dropdown",
@@ -80,18 +81,35 @@ export class EnumDropdownComponent implements OnChanges {
8081
}
8182

8283
private async addNewOption(name: string) {
84+
const prevValues = JSON.stringify(this.enumEntity.values);
85+
let addedOption: ConfigurableEnumValue;
86+
87+
try {
88+
addedOption = this.enumEntity.addOption(name);
89+
} catch (error) {
90+
await this.confirmation.getConfirmation(
91+
$localize`Failed to create new option`,
92+
$localize`Couldn't create this new option. Please check if the value already exists.`,
93+
OkButton,
94+
);
95+
return undefined;
96+
}
97+
98+
if (!addedOption) {
99+
return undefined;
100+
}
101+
83102
const userConfirmed = await this.confirmation.getConfirmation(
84103
$localize`Create new option`,
85-
$localize`Do you want to create the new option "${name}"?`,
104+
$localize`Do you want to create the new option "${addedOption.label}"?`,
86105
);
87106
if (!userConfirmed) {
107+
this.enumEntity.values = JSON.parse(prevValues);
88108
return undefined;
89109
}
90110

91-
const option = { id: name, label: name };
92-
this.enumEntity.values.push(option);
93111
await this.entityMapper.save(this.enumEntity);
94-
return option;
112+
return addedOption;
95113
}
96114

97115
openSettings(event: Event) {

src/app/core/database/pouch-database.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export class PouchDatabase extends Database {
133133
try {
134134
result = await PouchDB.fetch(remoteUrl, opts);
135135
} catch (err) {
136+
Logging.debug("navigator.onLine", navigator.onLine);
136137
Logging.warn("Failed to fetch from DB", err);
137138
}
138139

@@ -143,14 +144,18 @@ export class PouchDatabase extends Database {
143144
this.authService.addAuthHeader(opts.headers);
144145
result = await PouchDB.fetch(remoteUrl, opts);
145146
} catch (err) {
147+
Logging.debug("navigator.onLine", navigator.onLine);
146148
Logging.warn("Failed to fetch from DB", err);
147149
}
148150
}
149151

150152
if (!result || result.status >= 500) {
153+
Logging.debug("Actual DB Fetch response", result);
154+
Logging.debug("navigator.onLine", navigator.onLine);
151155
throw new DatabaseException({
152156
error: "Failed to fetch from DB",
153-
actualResponse: result,
157+
actualResponse: JSON.stringify(result.headers),
158+
actualResponseBody: await result?.text(),
154159
});
155160
}
156161
return result;

src/app/core/logging/logging-error-handler.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)