Initial enterprise landing page (#2529)
* First draft * Combined into one box * Must use enum string vals * Added JS unit tests * Avoid unneeded quotes
This commit is contained in:
Родитель
ce7a5b5fed
Коммит
3d8042bc58
|
@ -81,3 +81,4 @@ import './elements/chromedash-roadmap-milestone-card';
|
|||
import './elements/chromedash-roadmap-page';
|
||||
import './elements/chromedash-userlist';
|
||||
import './elements/chromedash-x-meter';
|
||||
import './elements/chromedash-enterprise-page';
|
||||
|
|
|
@ -177,6 +177,12 @@ class ChromedashApp extends LitElement {
|
|||
page('/metrics/css/timeline/animated', () => page.redirect('/metrics/css/animated'));
|
||||
page('/metrics/feature/timeline/popularity', () =>
|
||||
page.redirect('/metrics/feature/popularity'));
|
||||
page('/enterprise', (ctx) => {
|
||||
this.pageComponent = document.createElement('chromedash-enterprise-page');
|
||||
this.pageComponent.user = this.user;
|
||||
this.contextLink = ctx.path;
|
||||
this.currentPage = ctx.path;
|
||||
});
|
||||
page.start();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import {html} from 'lit';
|
||||
import {ChromedashAllFeaturesPage} from './chromedash-all-features-page';
|
||||
|
||||
|
||||
export class ChromedashEnterprisePage extends ChromedashAllFeaturesPage {
|
||||
renderBox(query) {
|
||||
return html`
|
||||
<chromedash-feature-table
|
||||
query=${query}
|
||||
?signedIn=${Boolean(this.user)}
|
||||
?canEdit=${this.user && this.user.can_edit_all}
|
||||
?canApprove=${this.user && this.user.can_approve}
|
||||
.starredFeatures=${this.starredFeatures}
|
||||
@star-toggle-event=${this.handleStarToggle}
|
||||
@open-approvals-event=${this.handleOpenApprovals}
|
||||
num=100 alwaysOfferPagination columns="normal">
|
||||
</chromedash-feature-table>
|
||||
`;
|
||||
}
|
||||
|
||||
renderEnterpriseFeatures() {
|
||||
return this.renderBox(
|
||||
'feature_type="New Feature or removal affecting enterprises" ' +
|
||||
'OR breaking_change=true');
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<h2>Enterprise features and breaking changes</h2>
|
||||
${this.renderEnterpriseFeatures()}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('chromedash-enterprise-page', ChromedashEnterprisePage);
|
|
@ -0,0 +1,72 @@
|
|||
import {html} from 'lit';
|
||||
import {assert, fixture} from '@open-wc/testing';
|
||||
import {ChromedashEnterprisePage} from './chromedash-enterprise-page';
|
||||
import './chromedash-toast';
|
||||
import '../js-src/cs-client';
|
||||
import sinon from 'sinon';
|
||||
|
||||
describe('chromedash-enterprise-page', () => {
|
||||
/* window.csClient and <chromedash-toast> are initialized at spa.html
|
||||
* which are not available here, so we initialize them before each test.
|
||||
* We also stub out the API calls here so that they return test data. */
|
||||
beforeEach(async () => {
|
||||
await fixture(html`<chromedash-toast></chromedash-toast>`);
|
||||
window.csClient = new ChromeStatusClient('fake_token', 1);
|
||||
sinon.stub(window.csClient, 'getStars');
|
||||
sinon.stub(window.csClient, 'searchFeatures');
|
||||
window.csClient.getStars.returns(Promise.resolve([123456]));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.csClient.getStars.restore();
|
||||
window.csClient.searchFeatures.restore();
|
||||
});
|
||||
|
||||
it('render with no data', async () => {
|
||||
const invalidFeaturePromise = Promise.reject(new Error('Got error response from server'));
|
||||
window.csClient.searchFeatures.returns(invalidFeaturePromise);
|
||||
const component = await fixture(
|
||||
html`<chromedash-enterprise-page></chromedash-enterprise-page>`);
|
||||
assert.exists(component);
|
||||
assert.instanceOf(component, ChromedashEnterprisePage);
|
||||
|
||||
// error response would trigger the toast to show message
|
||||
const toastEl = document.querySelector('chromedash-toast');
|
||||
const toastMsgSpan = toastEl.shadowRoot.querySelector('span#msg');
|
||||
assert.include(toastMsgSpan.innerHTML,
|
||||
'Some errors occurred. Please refresh the page or try again later.');
|
||||
});
|
||||
|
||||
it('render with fake data', async () => {
|
||||
const validFeaturePromise = Promise.resolve({
|
||||
total_count: 1,
|
||||
features: [{
|
||||
id: 123456,
|
||||
name: 'feature one',
|
||||
}],
|
||||
});
|
||||
const user = {
|
||||
can_approve: false,
|
||||
can_create_feature: true,
|
||||
can_edit_all: true,
|
||||
is_admin: false,
|
||||
email: 'example@gmail.com',
|
||||
editable_features: [],
|
||||
};
|
||||
window.csClient.searchFeatures.returns(validFeaturePromise);
|
||||
const component = await fixture(
|
||||
html`<chromedash-enterprise-page
|
||||
.user=${user}>
|
||||
</chromedash-enterprise-page>`);
|
||||
assert.exists(component);
|
||||
assert.instanceOf(component, ChromedashEnterprisePage);
|
||||
|
||||
// feature table exists
|
||||
const featureTableEl = component.shadowRoot.querySelector('chromedash-feature-table');
|
||||
assert.exists(featureTableEl);
|
||||
|
||||
// title exists
|
||||
const titleEl = component.shadowRoot.querySelector('h2');
|
||||
assert.include(titleEl.innerHTML, 'Enterprise features and breaking changes');
|
||||
});
|
||||
});
|
|
@ -212,6 +212,7 @@ QUERIABLE_FIELDS: dict[str, Property] = {
|
|||
|
||||
'browsers.chrome.bug': FeatureEntry.bug_url,
|
||||
'launch_bug_url': FeatureEntry.launch_bug_url,
|
||||
'breaking_change': FeatureEntry.breaking_change,
|
||||
|
||||
'browsers.chrome.status': FeatureEntry.impl_status_chrome,
|
||||
'browsers.chrome.flag_name': FeatureEntry.flag_name,
|
||||
|
|
1
main.py
1
main.py
|
@ -163,6 +163,7 @@ spa_page_routes = [
|
|||
Route('/metrics/feature/timeline/popularity'),
|
||||
Route('/metrics/feature/timeline/popularity/<int:bucket_id>'),
|
||||
Route('/settings', defaults={'require_signin': True}),
|
||||
Route('/enterprise'),
|
||||
]
|
||||
|
||||
spa_page_post_routes: list[Route] = [
|
||||
|
|
Загрузка…
Ссылка в новой задаче