Switch the dashboard view to listening to the view model
Release-Notes: skip
Google-Bug-Id: b/244279450
Change-Id: Ib4d4a81c4249ba259d51064dba1c897e9e88038b
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
index 88bf943..3af856f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
@@ -41,18 +41,22 @@
firePageError,
fireTitleChange,
} from '../../../utils/event-util';
-import {GerritView} from '../../../services/router/router-model';
import {RELOAD_DASHBOARD_INTERVAL_MS} from '../../../constants/constants';
import {ChangeListSection} from '../gr-change-list/gr-change-list';
import {a11yStyles} from '../../../styles/gr-a11y-styles';
import {sharedStyles} from '../../../styles/shared-styles';
-import {LitElement, PropertyValues, html, css} from 'lit';
+import {LitElement, html, css, nothing} from 'lit';
import {customElement, property, state, query} from 'lit/decorators.js';
import {assertIsDefined} from '../../../utils/common-util';
import {Shortcut} from '../../../services/shortcuts/shortcuts-config';
import {ShortcutController} from '../../lit/shortcut-controller';
-import {DashboardViewState} from '../../../models/views/dashboard';
+import {
+ dashboardViewModelToken,
+ DashboardViewState,
+} from '../../../models/views/dashboard';
import {createSearchUrl} from '../../../models/views/search';
+import {subscribe} from '../../lit/subscription-controller';
+import {resolve} from '../../../models/dependency';
const PROJECT_PLACEHOLDER_PATTERN = /\${project}/g;
@@ -79,13 +83,13 @@
@query('#confirmDeleteOverlay') protected confirmDeleteOverlay?: GrOverlay;
@property({type: Object})
- account: AccountDetailInfo | null = null;
+ account?: AccountDetailInfo;
@property({type: Object})
preferences?: PreferencesInput;
- @property({type: Object})
- params?: DashboardViewState;
+ @state()
+ viewState?: DashboardViewState;
// private but used in test
@state() results?: ChangeListSection[];
@@ -103,12 +107,29 @@
private readonly restApiService = getAppContext().restApiService;
+ private readonly userModel = getAppContext().userModel;
+
+ private readonly getViewModel = resolve(this, dashboardViewModelToken);
+
private lastVisibleTimestampMs = 0;
private readonly shortcuts = new ShortcutController(this);
constructor() {
super();
+ subscribe(
+ this,
+ () => this.userModel.account$,
+ x => (this.account = x)
+ );
+ subscribe(
+ this,
+ () => this.getViewModel().state$,
+ x => {
+ this.viewState = x;
+ this.reload();
+ }
+ );
this.addEventListener('reload', () => this.reload());
this.shortcuts.addAbstract(Shortcut.UP_TO_DASHBOARD, () => this.reload());
}
@@ -184,6 +205,7 @@
}
override render() {
+ if (!this.viewState) return nothing;
return html`
${this.renderBanner()} ${this.renderContent()}
<gr-overlay id="confirmDeleteOverlay" with-backdrop>
@@ -271,17 +293,15 @@
private renderUserHeader() {
if (
- !this.params ||
- this.params.view !== GerritView.DASHBOARD ||
- !!this.params.project ||
- !this.params.user ||
- this.params.user === 'self'
+ !!this.viewState?.project ||
+ !this.viewState?.user ||
+ this.viewState?.user === 'self'
) {
return;
}
return html`
- <gr-user-header .userId=${this.params?.user}></gr-user-header>
+ <gr-user-header .userId=${this.viewState?.user}></gr-user-header>
`;
}
@@ -297,12 +317,6 @@
`;
}
- override updated(changedProperties: PropertyValues) {
- if (changedProperties.has('params')) {
- this.paramsChanged();
- }
- }
-
private loadPreferences() {
return this.restApiService.getLoggedIn().then(loggedIn => {
if (loggedIn) {
@@ -354,26 +368,15 @@
return 'Dashboard for ' + user;
}
- private isViewActive(params: DashboardViewState) {
- return params.view === GerritView.DASHBOARD;
- }
-
- // private but used in test
- paramsChanged() {
- return this.reload();
- }
-
/**
* Reloads the element.
*
* private but used in test
*/
reload() {
- if (!this.params || !this.isViewActive(this.params)) {
- return Promise.resolve();
- }
+ if (!this.viewState) return Promise.resolve();
this.loading = true;
- const {project, dashboard, title, user, sections} = this.params;
+ const {project, dashboard, title, user, sections} = this.viewState;
const dashboardPromise: Promise<UserDashboard | undefined> = project
? this.getProjectDashboard(project, dashboard)
: Promise.resolve(
@@ -476,7 +479,7 @@
* And then we want to emphasize the changes where the waiting time is larger.
*/
private maybeSortResults(name: string, results: ChangeInfo[]) {
- const userId = this.account && this.account._account_id;
+ const userId = this.account?._account_id;
const sortedResults = [...results];
if (name === YOUR_TURN.name && userId) {
sortedResults.sort((c1, c2) => {
@@ -544,9 +547,7 @@
*/
maybeShowDraftsBanner() {
this.showDraftsBanner = false;
- if (!(this.params?.user === 'self')) {
- return;
- }
+ if (!(this.viewState?.user === 'self')) return;
if (!this.results) {
throw new Error('this.results must be set. restAPI returned undefined');
@@ -555,16 +556,12 @@
const draftSection = this.results.find(
section => section.query === 'has:draft'
);
- if (!draftSection || !draftSection.results.length) {
- return;
- }
+ if (!draftSection || !draftSection.results.length) return;
const closedChanges = draftSection.results.filter(
change => !changeIsOpen(change)
);
- if (!closedChanges.length) {
- return;
- }
+ if (!closedChanges.length) return;
this.showDraftsBanner = true;
}
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.ts
index 92afae1..7889e20 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.ts
@@ -41,7 +41,6 @@
suite('gr-dashboard-view tests', () => {
let element: GrDashboardView;
- let paramsChangedPromise: Promise<any>;
let getChangesStub: SinonStubbedMember<
RestApiService['getChangesForMultipleQueries']
>;
@@ -54,30 +53,25 @@
registered_on: '2015-03-12 18:32:08.000000000' as Timestamp,
})
);
- stubRestApi('getAccountStatus').returns(Promise.resolve(undefined));
element = await fixture<GrDashboardView>(html`
<gr-dashboard-view></gr-dashboard-view>
`);
await element.updateComplete;
- let resolver: (value?: any) => void;
- paramsChangedPromise = new Promise(resolve => {
- resolver = resolve;
- });
- const paramsChanged = element.paramsChanged.bind(element);
- sinon
- .stub(element, 'paramsChanged')
- .callsFake(() => paramsChanged().then(() => resolver()));
});
test('render', async () => {
- const sections = [
- {name: 'test1', query: 'test1', hideIfEmpty: true},
- {name: 'test2', query: 'test2', hideIfEmpty: true},
- ];
+ element.viewState = {
+ view: GerritView.DASHBOARD,
+ user: 'self',
+ sections: [
+ {name: 'test1', query: 'test1', hideIfEmpty: true},
+ {name: 'test2', query: 'test2', hideIfEmpty: true},
+ ],
+ };
getChangesStub.returns(Promise.resolve([[createChange()]]));
- await element.fetchDashboardChanges({sections}, false);
+ await element.reload();
element.loading = false;
stubFlags('isEnabled').returns(true);
element.requestUpdate();
@@ -125,14 +119,18 @@
suite('bulk actions', () => {
setup(async () => {
- const sections = [
- {name: 'test1', query: 'test1', hideIfEmpty: true},
- {name: 'test2', query: 'test2', hideIfEmpty: true},
- ];
+ element.viewState = {
+ view: GerritView.DASHBOARD,
+ user: 'user',
+ sections: [
+ {name: 'test1', query: 'test1', hideIfEmpty: true},
+ {name: 'test2', query: 'test2', hideIfEmpty: true},
+ ],
+ };
getChangesStub.returns(Promise.resolve([[createChange()]]));
- await element.fetchDashboardChanges({sections}, false);
- element.loading = false;
stubFlags('isEnabled').returns(true);
+ await element.reload();
+ element.loading = false;
element.requestUpdate();
await element.updateComplete;
});
@@ -151,11 +149,6 @@
getChangesStub.restore();
getChangesStub.returns(Promise.resolve([[createChange()]]));
- element.params = {
- view: GerritView.DASHBOARD,
- user: 'notself',
- dashboard: '' as DashboardId,
- };
await element.reload();
await element.updateComplete;
assert.isTrue(checkbox.checked);
@@ -163,9 +156,20 @@
});
suite('drafts banner functionality', () => {
+ setup(async () => {
+ element.viewState = {
+ view: GerritView.DASHBOARD,
+ user: 'self',
+ sections: [
+ {name: 'test1', query: 'test1', hideIfEmpty: true},
+ {name: 'test2', query: 'test2', hideIfEmpty: true},
+ ],
+ };
+ });
+
suite('maybeShowDraftsBanner', () => {
test('not dashboard/self', () => {
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
user: 'notself',
dashboard: '' as DashboardId,
@@ -176,7 +180,7 @@
test('no drafts at all', () => {
element.results = [];
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
user: 'self',
dashboard: '' as DashboardId,
@@ -190,7 +194,7 @@
element.results = [
{countLabel: '', name: '', query: 'has:draft', results: [openChange]},
];
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
user: 'self',
dashboard: '' as DashboardId,
@@ -210,7 +214,7 @@
},
];
assert.isFalse(changeIsOpen(element.results[0].results[0]));
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
user: 'self',
dashboard: '' as DashboardId,
@@ -314,27 +318,10 @@
});
});
- suite('_isViewActive', () => {
- test('nothing happens when user param is falsy', async () => {
- element.params = undefined;
- await element.updateComplete;
- assert.equal(getChangesStub.callCount, 0);
- });
-
- test('content is refreshed when user param is updated', async () => {
- element.params = {
- view: GerritView.DASHBOARD,
- user: 'self',
- dashboard: '' as DashboardId,
- };
- await paramsChangedPromise;
- assert.isTrue(getChangesStub.called);
- });
- });
-
suite('selfOnly sections', () => {
test('viewing self dashboard includes selfOnly sections', async () => {
- element.params = {
+ element.account = undefined;
+ element.viewState = {
view: GerritView.DASHBOARD,
user: 'self',
dashboard: '' as DashboardId,
@@ -343,13 +330,13 @@
{name: '', query: '2', selfOnly: true},
],
};
- await paramsChangedPromise;
+ await element.reload();
assert.isTrue(getChangesStub.calledWith(undefined, ['1', '2']));
});
test('viewing dashboard when logged in includes owner:self query', async () => {
element.account = createAccountDetailWithId(1);
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
user: 'self',
dashboard: '' as DashboardId,
@@ -358,14 +345,14 @@
{name: '', query: '2', selfOnly: true},
],
};
- await paramsChangedPromise;
+ await element.reload();
assert.isTrue(
getChangesStub.calledWith(undefined, ['1', '2', 'owner:self limit:1'])
);
});
test("viewing another user's dashboard omits selfOnly sections", async () => {
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
user: 'user',
dashboard: '' as DashboardId,
@@ -374,13 +361,13 @@
{name: '', query: '2', selfOnly: true},
],
};
- await paramsChangedPromise;
+ await element.reload();
assert.isTrue(getChangesStub.calledWith(undefined, ['1']));
});
});
test('suffixForDashboard is included in getChanges query', async () => {
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
dashboard: '' as DashboardId,
sections: [
@@ -388,7 +375,7 @@
{name: '', query: '2', suffixForDashboard: 'suffix'},
],
};
- await paramsChangedPromise;
+ await element.reload();
assert.isTrue(getChangesStub.calledWith(undefined, ['1', '2 suffix']));
});
@@ -520,6 +507,9 @@
});
test('showNewUserHelp', async () => {
+ element.viewState = {
+ view: GerritView.DASHBOARD,
+ };
element.loading = false;
element.showNewUserHelp = false;
await element.updateComplete;
@@ -547,11 +537,11 @@
});
test('gr-user-header', async () => {
- element.params = undefined;
+ element.viewState = undefined;
await element.updateComplete;
assert.isNotOk(query(element, 'gr-user-header'));
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
dashboard: '' as DashboardId,
user: 'self',
@@ -560,7 +550,7 @@
assert.isNotOk(query(element, 'gr-user-header'));
element.loading = false;
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
dashboard: '' as DashboardId,
user: 'user',
@@ -568,7 +558,7 @@
await element.updateComplete;
assert.isOk(query(element, 'gr-user-header'));
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
dashboard: '' as DashboardId,
project: 'p' as RepoName,
@@ -593,16 +583,16 @@
assert.strictEqual((e as PageErrorEvent).detail.response, response);
promise.resolve();
});
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
dashboard: 'dashboard' as DashboardId,
project: 'project' as RepoName,
user: '',
};
- await Promise.all([paramsChangedPromise, promise]);
+ await Promise.all([element.reload(), promise]);
});
- test('params change triggers dashboardDisplayed()', async () => {
+ test('viewState change triggers dashboardDisplayed()', async () => {
stubRestApi('getDashboard').returns(
Promise.resolve({
id: '' as DashboardId,
@@ -618,13 +608,13 @@
);
getChangesStub.returns(Promise.resolve([]));
const dashboardDisplayedStub = stubReporting('dashboardDisplayed');
- element.params = {
+ element.viewState = {
view: GerritView.DASHBOARD,
dashboard: 'dashboard' as DashboardId,
project: 'project' as RepoName,
user: '',
};
- await paramsChangedPromise;
+ await element.reload();
assert.isTrue(dashboardDisplayedStub.calledOnce);
});
});
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index e8bc5bc..e4e9310 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -447,12 +447,7 @@
private renderDashboardView() {
return cache(
this.view === GerritView.DASHBOARD
- ? html`
- <gr-dashboard-view
- .account=${this.account}
- .params=${this.params}
- ></gr-dashboard-view>
- `
+ ? html`<gr-dashboard-view></gr-dashboard-view>`
: nothing
);
}
diff --git a/polygerrit-ui/app/models/views/dashboard.ts b/polygerrit-ui/app/models/views/dashboard.ts
index 0de6bf8..979debb 100644
--- a/polygerrit-ui/app/models/views/dashboard.ts
+++ b/polygerrit-ui/app/models/views/dashboard.ts
@@ -29,10 +29,6 @@
title?: string;
}
-const DEFAULT_STATE: DashboardViewState = {
- view: GerritView.DASHBOARD,
-};
-
const REPO_TOKEN_PATTERN = /\${(project|repo)}/g;
function sectionsToEncodedParams(
@@ -73,9 +69,9 @@
'dashboard-view-model'
);
-export class DashboardViewModel extends Model<DashboardViewState> {
+export class DashboardViewModel extends Model<DashboardViewState | undefined> {
constructor() {
- super(DEFAULT_STATE);
+ super(undefined);
}
finalize() {}