Skip to content

Commit a581ac9

Browse files
Fix: Null route segement on navigating on quick list too fast (#1982)
1 parent 55ce8ea commit a581ac9

File tree

15 files changed

+193
-159
lines changed

15 files changed

+193
-159
lines changed

CHANGELOG.md

+29-22
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
1-
# 2.0.0
2-
[All items](https://github.com/Azure/BatchExplorer/milestone/32?closed=1)
3-
4-
### feature:
5-
61

7-
### bug:
2+
# 2.0.1
83

4+
### Bug fixes
5+
* Null route when clicking on node or task that isn't loaded yet [\#1983](https://github.com/Azure/BatchExplorer/issues/1983)
6+
* Open a local template file null expection [\#1980](https://github.com/Azure/BatchExplorer/issues/1980)
7+
* Null pointer exception in job schedule details [\#1978](https://github.com/Azure/BatchExplorer/issues/1978)
8+
* Null currentTab in VTab Component [\#1976](https://github.com/Azure/BatchExplorer/issues/1976)
99

10-
### other:
10+
# 2.0.0
11+
[All items](https://github.com/Azure/BatchExplorer/milestone/32?closed=1)
1112

12-
* CTRL+Click not selecting quick-list items [\#1970](https://github.com/Azure/BatchExplorer/issues/1970)
13-
* In the "Jobs" view, the default job sorting should be by creation date, not name [\#1966](https://github.com/Azure/BatchExplorer/issues/1966)
14-
* Subscription list should be sorted [\#1963](https://github.com/Azure/BatchExplorer/issues/1963)
15-
* Dashboard app package table has URL not name [\#1957](https://github.com/Azure/BatchExplorer/issues/1957)
16-
* Local template open in default editor should not open a copy [\#1944](https://github.com/Azure/BatchExplorer/issues/1944)
13+
### Features:
14+
* Sort jobs by end time and keep last sort order [\#1966](https://github.com/Azure/BatchExplorer/issues/1966)
15+
* Subscription list sorted alphabetically [\#1963](https://github.com/Azure/BatchExplorer/issues/1963)
1716
* Local Template library show full path to file [\#1943](https://github.com/Azure/BatchExplorer/issues/1943)
18-
* Daily cost graph showing corrupt data [\#1933](https://github.com/Azure/BatchExplorer/issues/1933)
19-
* Cant view images from task outputs [\#1928](https://github.com/Azure/BatchExplorer/issues/1928)
20-
* Bugs in Application Packages [\#1926](https://github.com/Azure/BatchExplorer/issues/1926)
21-
* Insider build unable to download (stable) update [\#1919](https://github.com/Azure/BatchExplorer/issues/1919)
22-
* CSS for favorite picker is broken [\#1914](https://github.com/Azure/BatchExplorer/issues/1914)
23-
* Issue with switching azure environment(National cloud) [\#1909](https://github.com/Azure/BatchExplorer/issues/1909)
24-
* Pool quota out of sync with pool list [\#1906](https://github.com/Azure/BatchExplorer/issues/1906)
2517
* Create batch account location picker use provider specific locations [\#1902](https://github.com/Azure/BatchExplorer/issues/1902)
2618
* Add common environment settings support for job [\#1896](https://github.com/Azure/BatchExplorer/issues/1896)
2719
* Local template library only shows .template.json files [\#1894](https://github.com/Azure/BatchExplorer/issues/1894)
@@ -33,18 +25,33 @@
3325
* Add column keyboard navigation for tables for accessibility [\#1878](https://github.com/Azure/BatchExplorer/issues/1878)
3426
* Windows user account interactive mode [\#1868](https://github.com/Azure/BatchExplorer/issues/1868)
3527
* Unify filesystem interfaces [\#1866](https://github.com/Azure/BatchExplorer/issues/1866)
36-
* Switch from bunyan to winston for logging [\#1865](https://github.com/Azure/BatchExplorer/issues/1865)
37-
* New user configuration/settings system [\#1841](https://github.com/Azure/BatchExplorer/issues/1841)
3828
* Support the new type of resource files(Storage container) [\#1839](https://github.com/Azure/BatchExplorer/issues/1839)
3929
* Update Batch api to latest version 2018-12-01.8.0 [\#1838](https://github.com/Azure/BatchExplorer/issues/1838)
4030
* Global app utc vs local time selector [\#1837](https://github.com/Azure/BatchExplorer/issues/1837)
4131
* Switch account monitoring to average now that value are correct [\#1835](https://github.com/Azure/BatchExplorer/issues/1835)
4232
* Migrate from momentjs to luxon [\#1833](https://github.com/Azure/BatchExplorer/issues/1833)
4333
* File group creation disabled if no batch account selected [\#1750](https://github.com/Azure/BatchExplorer/issues/1750)
4434
* Display multi instance settings on the sub task [\#1554](https://github.com/Azure/BatchExplorer/issues/1554)
45-
* Stale pool statistics / graphs [\#1505](https://github.com/Azure/BatchExplorer/issues/1505)
4635
* Batch account favourites should be user specific. [\#250](https://github.com/Azure/BatchExplorer/issues/250)
4736

37+
### Bug fixes:
38+
* CTRL+Click not selecting quick-list items [\#1970](https://github.com/Azure/BatchExplorer/issues/1970)
39+
* Dashboard app package table has URL not name [\#1957](https://github.com/Azure/BatchExplorer/issues/1957)
40+
* Local template open in default editor should not open a copy [\#1944](https://github.com/Azure/BatchExplorer/issues/1944)
41+
* Daily cost graph showing corrupt data [\#1933](https://github.com/Azure/BatchExplorer/issues/1933)
42+
* Cant view images from task outputs [\#1928](https://github.com/Azure/BatchExplorer/issues/1928)
43+
* Bugs in Application Packages [\#1926](https://github.com/Azure/BatchExplorer/issues/1926)
44+
* Insider build unable to download (stable) update [\#1919](https://github.com/Azure/BatchExplorer/issues/1919)
45+
* CSS for favorite picker is broken [\#1914](https://github.com/Azure/BatchExplorer/issues/1914)
46+
* Issue with switching azure environment(National cloud) [\#1909](https://github.com/Azure/BatchExplorer/issues/1909)
47+
* Pool quota out of sync with pool list [\#1906](https://github.com/Azure/BatchExplorer/issues/1906)
48+
* Stale pool statistics / graphs [\#1505](https://github.com/Azure/BatchExplorer/issues/1505)
49+
50+
### Others:
51+
* Switch from bunyan to winston for logging [\#1865](https://github.com/Azure/BatchExplorer/issues/1865)
52+
* New user configuration/settings system [\#1841](https://github.com/Azure/BatchExplorer/issues/1841)
53+
54+
4855

4956
# 0.19.2
5057

package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"name": "Microsoft Corporation",
1616
"email": "[email protected]"
1717
},
18-
"version": "2.0.0",
18+
"version": "2.0.1",
1919
"main": "build/client/main.prod.js",
2020
"scripts": {
2121
"ts": "ts-node --project tsconfig.node.json --files",

src/@batch-flask/core/data/entity-getter/entity-getter.spec.ts

+18-15
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { of } from "rxjs";
33
import { FakeModel, FakeParams } from "../test/fake-model";
44
import { EntityGetter } from "./entity-getter";
55

6+
const fake1 = { id: "1", parentId: "parent-1", state: "active", name: "Fake1" };
7+
const fake2 = { id: "1", parentId: "parent-1", state: "running", name: "Fake1" };
8+
69
const data = [
710
{ id: "1", state: "active", name: "Fake1" },
811
{ id: "1", state: "running", name: "Fake1" },
@@ -25,39 +28,39 @@ describe("EntityGetter", () => {
2528
});
2629

2730
it("It retrieve the item", (done) => {
28-
getter.fetch({ id: "1" }).subscribe((item) => {
29-
expect(item).toEqualImmutable(new FakeModel(data[0]));
31+
getter.fetch({ parentId: "parent-1", id: "1" }).subscribe((item) => {
32+
expect(item.toJS()).toEqual(fake1);
3033
expect(dataSpy).toHaveBeenCalledTimes(1);
31-
expect(dataSpy).toHaveBeenCalledWith({ id: "1" });
34+
expect(dataSpy).toHaveBeenCalledWith({ parentId: "parent-1", id: "1" });
3235
done();
3336
});
3437
});
3538

3639
it("It retrieve the new item if not asked from cache", (done) => {
37-
getter.fetch({ id: "1" }).subscribe((item) => {
38-
expect(item).toEqualImmutable(new FakeModel(data[0]));
40+
getter.fetch({ parentId: "parent-1", id: "1" }).subscribe((item) => {
41+
expect(item.toJS()).toEqual(fake1);
3942
expect(dataSpy).toHaveBeenCalledTimes(1);
40-
expect(dataSpy).toHaveBeenCalledWith({ id: "1" });
43+
expect(dataSpy).toHaveBeenCalledWith({ parentId: "parent-1", id: "1" });
4144

42-
getter.fetch({ id: "1" }).subscribe((item) => {
43-
expect(item).toEqualImmutable(new FakeModel(data[1]));
45+
getter.fetch({ parentId: "parent-1", id: "1" }).subscribe((item) => {
46+
expect(item.toJS()).toEqual(fake2);
4447
expect(dataSpy).toHaveBeenCalledTimes(2);
45-
expect(dataSpy).toHaveBeenCalledWith({ id: "1" });
48+
expect(dataSpy).toHaveBeenCalledWith({ parentId: "parent-1", id: "1" });
4649
done();
4750
});
4851
});
4952
});
5053

5154
it("It retrieve the item from cache if asked too", (done) => {
52-
getter.fetch({ id: "1" }).subscribe((item) => {
53-
expect(item).toEqualImmutable(new FakeModel(data[0]));
55+
getter.fetch({ parentId: "parent-1", id: "1" }).subscribe((item) => {
56+
expect(item.toJS()).toEqual(fake1);
5457
expect(dataSpy).toHaveBeenCalledTimes(1);
55-
expect(dataSpy).toHaveBeenCalledWith({ id: "1" });
58+
expect(dataSpy).toHaveBeenCalledWith({ parentId: "parent-1", id: "1" });
5659

57-
getter.fetch({ id: "1" }, { cached: true }).subscribe((item) => {
58-
expect(item).toEqualImmutable(new FakeModel(data[0]));
60+
getter.fetch({ parentId: "parent-1", id: "1" }, { cached: true }).subscribe((item) => {
61+
expect(item.toJS()).toEqual(fake1);
5962
expect(dataSpy).toHaveBeenCalledTimes(1); // Should not have been called again as its loading from cache
60-
expect(dataSpy).toHaveBeenCalledWith({ id: "1" });
63+
expect(dataSpy).toHaveBeenCalledWith({ parentId: "parent-1", id: "1" });
6164
done();
6265
});
6366
});

src/@batch-flask/core/data/entity-view/entity-view.spec.ts

+29-26
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ import { BasicEntityGetter, DataCache, EntityGetter, EntityView, ServerError } f
33
import { from, throwError } from "rxjs";
44
import { FakeModel, FakeParams } from "../test/fake-model";
55

6+
const fake1 = { id: "1", parentId: "parent-1", state: "active", name: "Fake1" };
7+
const fake2 = { id: "1", parentId: "parent-1", state: "running", name: "Fake1" };
8+
const fake3 = { id: "1", parentId: "parent-1", state: "completed", name: "Fake1" };
9+
610
const data = [
711
{ id: "1", state: "active", name: "Fake1" },
812
{ id: "1", state: "running", name: "Fake1" },
9-
{ id: "1", state: "complated", name: "Fake1" },
13+
{ id: "1", state: "completed", name: "Fake1" },
1014
];
1115

1216
describe("EntityView", () => {
@@ -30,7 +34,7 @@ describe("EntityView", () => {
3034
cache: () => cache,
3135
getter: getter,
3236
});
33-
view.params = { id: "1" };
37+
view.params = { parentId: "parent-1", id: "1" };
3438
});
3539

3640
afterEach(() => {
@@ -43,68 +47,67 @@ describe("EntityView", () => {
4347
view.fetch();
4448
tick();
4549
expect(dataSpy).toHaveBeenCalledTimes(1);
46-
expect(item!.toJS()).toEqual(data[0]);
47-
expect(dataSpy).toHaveBeenCalledWith({ id: "1" });
50+
expect(item!.toJS()).toEqual(fake1);
51+
expect(dataSpy).toHaveBeenCalledWith({ parentId: "parent-1", id: "1" });
4852
}));
4953

5054
it("should use the cached value", fakeAsync(() => {
51-
cache.addItem(new FakeModel({ id: "1", state: "creating", name: "Fake1" }));
55+
cache.addItem(new FakeModel({ id: "1", parentId: "parent-1", state: "creating", name: "Fake1" }));
5256

5357
view.item.subscribe(x => item = x);
5458
view.fetch();
5559
expect(item).not.toBeFalsy();
56-
expect(item!.toJS()).toEqual({ id: "1", state: "creating", name: "Fake1" });
60+
expect(item!.toJS()).toEqual({ id: "1", parentId: "parent-1", state: "creating", name: "Fake1" });
5761

5862
tick(); // This should be the return from the fetched data
59-
expect(item!.toJS()).toEqual(data[0]);
63+
expect(item!.toJS()).toEqual(fake1);
6064
}));
6165

6266
it("Update the data when refreshing", fakeAsync(() => {
6367
view.item.subscribe(x => item = x);
6468
view.fetch();
6569
tick();
66-
expect(item!.toJS()).toEqual(data[0]);
70+
expect(item!.toJS()).toEqual(fake1);
6771

6872
view.refresh();
6973
tick();
70-
expect(item!.toJS()).toEqual(data[1]);
74+
expect(item!.toJS()).toEqual(fake2);
7175

7276
view.refresh();
7377
tick();
74-
expect(item!.toJS()).toEqual(data[2]);
78+
expect(item!.toJS()).toEqual(fake3);
7579
expect(dataSpy).toHaveBeenCalledTimes(3);
7680
}));
7781

7882
it("Update the params", fakeAsync(() => {
7983
view.item.subscribe(x => item = x);
80-
view.params = { id: "2" };
84+
view.params = { parentId: "parent-1", id: "2" };
8185
view.fetch();
8286
tick();
83-
expect(item!.toJS()).toEqual(data[0]);
84-
expect(dataSpy).toHaveBeenCalledWith({ id: "2" });
87+
expect(item!.toJS()).toEqual(fake1);
88+
expect(dataSpy).toHaveBeenCalledWith({ parentId: "parent-1", id: "2" });
8589
}));
8690

8791
it("Update the params", fakeAsync(() => {
8892
view.item.subscribe(x => item = x);
89-
view.params = { id: "2" };
93+
view.params = { parentId: "parent-1", id: "2" };
9094
view.fetch();
9195
tick();
92-
expect(item!.toJS()).toEqual(data[0]);
93-
expect(dataSpy).toHaveBeenCalledWith({ id: "2" });
96+
expect(item!.toJS()).toEqual(fake1);
97+
expect(dataSpy).toHaveBeenCalledWith({parentId: "parent-1", id: "2" });
9498
}));
9599

96100
it("Update the cache should update the item", fakeAsync(() => {
97101
view.item.subscribe(x => item = x);
98102
view.fetch();
99103
tick();
100-
expect(item!.toJS()).toEqual(data[0]);
101-
expect(item).toEqualImmutable(new FakeModel(data[0]));
104+
expect(item!.toJS()).toEqual(fake1);
102105
expect(dataSpy).toHaveBeenCalledTimes(1);
103-
expect(dataSpy).toHaveBeenCalledWith({ id: "1" });
106+
expect(dataSpy).toHaveBeenCalledWith({parentId: "parent-1", id: "1" });
104107

105-
cache.addItem(new FakeModel(data[2]));
108+
cache.addItem(new FakeModel({...data[2], parentId: "parent-1"}));
106109
tick();
107-
expect(item!.toJS()).toEqual(data[2]);
110+
expect(item!.toJS()).toEqual(fake3);
108111
}));
109112

110113
describe("When it return a 404 error", () => {
@@ -115,7 +118,7 @@ describe("EntityView", () => {
115118
item = null;
116119
deleted = null;
117120
const responses = [
118-
from(Promise.resolve(data[0])),
121+
from(Promise.resolve(fake1)),
119122
throwError(new ServerError({ status: 404, message: "404 not found" } as any)),
120123
];
121124
dataSpy = jasmine.createSpy("supplyDataSpy")
@@ -130,7 +133,7 @@ describe("EntityView", () => {
130133
cache: () => cache,
131134
getter: getter,
132135
});
133-
view.params = { id: "1" };
136+
view.params = { parentId: "parent-1", id: "1" };
134137
});
135138

136139
it("should not send to delete if loading for the first time and I get a 404", fakeAsync(() => {
@@ -143,7 +146,7 @@ describe("EntityView", () => {
143146
cache: () => cache,
144147
getter: getter,
145148
});
146-
view.params = { id: "1" };
149+
view.params = { parentId: "parent-1", id: "1" };
147150

148151
view.item.subscribe(x => item = x);
149152
view.deleted.subscribe((x) => deleted = x);
@@ -158,7 +161,7 @@ describe("EntityView", () => {
158161
cache: () => cache,
159162
getter: getter,
160163
});
161-
otherView.params = { id: "1" };
164+
otherView.params = { parentId: "parent-1", id: "1" };
162165

163166
view.item.subscribe(x => item = x);
164167
cache.deleted.subscribe(x => deleted = x);
@@ -184,7 +187,7 @@ describe("EntityView", () => {
184187
// expect(deleted).toBe(null);
185188

186189
// This fetch should return an 404 error
187-
view.params = { id: "2" };
190+
view.params = { parentId: "parent-1", id: "2" };
188191
view.fetch();
189192
tick();
190193

src/@batch-flask/core/data/generic-view.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export abstract class GenericView<TEntity extends Record<any>, TParams, TOptions
6060
protected _newDataStatus = new BehaviorSubject<LoadingStatus>(LoadingStatus.Loading);
6161
protected _error = new BehaviorSubject<ServerError | null>(null);
6262
protected _cacheCleared = new Subject<void>();
63-
protected _params: TParams;
63+
protected _params = new BehaviorSubject<TParams>({} as TParams);
6464
protected _options: TOptions;
6565

6666
private _pollObservable: PollObservable;
@@ -77,7 +77,6 @@ export abstract class GenericView<TEntity extends Record<any>, TParams, TOptions
7777
this.newDataStatus = this._newDataStatus.asObservable();
7878
this.error = this._error.asObservable();
7979
this.isDisposed = new AsyncSubject();
80-
this._params = {} as any;
8180
this._onParamsChanged();
8281
this.status.subscribe((status) => {
8382
if (status === LoadingStatus.Loading) {
@@ -99,12 +98,12 @@ export abstract class GenericView<TEntity extends Record<any>, TParams, TOptions
9998
}
10099

101100
public set params(params: TParams) {
102-
this._params = params;
101+
this._params.next(params);
103102
this._onParamsChanged();
104103
}
105104

106-
public get params() {
107-
return this._params;
105+
public get params(): TParams {
106+
return this._params.value;
108107
}
109108

110109
public setOptions(options: TOptions, clearItems = true) {

0 commit comments

Comments
 (0)