blob: 8159e010edf0d90b6fa019553e129bb29c06399f [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {LitElement, html, css} from 'lit-element';
6import qs from 'qs';
7import {connectStore} from 'reducers/base.js';
8import * as sitewide from 'reducers/sitewide.js';
9import {SHARED_STYLES} from 'shared/shared-styles.js';
10
11/**
12 * Class for displaying a single flipper.
13 * @extends {LitElement}
14 */
15export default class MrFlipper extends connectStore(LitElement) {
16 /** @override */
17 static get properties() {
18 return {
19 currentIndex: {type: Number},
20 totalCount: {type: Number},
21 prevUrl: {type: String},
22 nextUrl: {type: String},
23 listUrl: {type: String},
24 queryParams: {type: Object},
25 };
26 }
27
28 /** @override */
29 constructor() {
30 super();
31 this.currentIndex = null;
32 this.totalCount = null;
33 this.prevUrl = null;
34 this.nextUrl = null;
35 this.listUrl = null;
36
37 this.queryParams = {};
38 }
39
40 /** @override */
41 stateChanged(state) {
42 this.queryParams = sitewide.queryParams(state);
43 }
44
45 /** @override */
46 updated(changedProperties) {
47 if (changedProperties.has('queryParams')) {
48 this.fetchFlipperData(qs.stringify(this.queryParams));
49 }
50 }
51
52 // Eventually this should be replaced with pRPC.
53 fetchFlipperData(query) {
54 const options = {
55 credentials: 'include',
56 method: 'GET',
57 };
58 fetch(`detail/flipper?${query}`, options).then(
59 (response) => response.text(),
60 ).then(
61 (responseBody) => {
62 let responseData;
63 try {
64 // Strip XSSI prefix from response.
65 responseData = JSON.parse(responseBody.substr(5));
66 } catch (e) {
67 console.error(`Error parsing JSON response for flipper: ${e}`);
68 return;
69 }
70 this._populateResponseData(responseData);
71 },
72 );
73 }
74
75 _populateResponseData(data) {
76 this.totalCount = data.total_count;
77 this.currentIndex = data.cur_index;
78 this.prevUrl = data.prev_url;
79 this.nextUrl = data.next_url;
80 this.listUrl = data.list_url;
81 }
82
83 /** @override */
84 static get styles() {
85 return [
86 SHARED_STYLES,
87 css`
88 :host {
89 display: flex;
90 justify-content: center;
91 flex-direction: column;
92 }
93 /* Use visibility instead of display:hidden for hiding in order to
94 * avoid popping when elements are made visible. */
95 .row a[hidden], .counts[hidden] {
96 visibility: hidden;
97 }
98 .counts[hidden] {
99 display: block;
100 }
101 .row a {
102 display: block;
103 padding: 0.25em 0;
104 }
105 .row a, .row div {
106 flex: 1;
107 white-space: nowrap;
108 padding: 0 2px;
109 }
110 .row .counts {
111 padding: 0 16px;
112 }
113 .row {
114 display: flex;
115 align-items: baseline;
116 text-align: center;
117 flex-direction: row;
118 }
119 @media (max-width: 960px) {
120 :host {
121 display: inline-block;
122 }
123 }
124 `,
125 ];
126 }
127
128 /** @override */
129 render() {
130 return html`
131 <div class="row">
132 <a href="${this.prevUrl}" ?hidden="${!this.prevUrl}" title="Prev" class="prev-url">
133 &lsaquo; Prev
134 </a>
135 <div class="counts" ?hidden=${!this.totalCount}>
136 ${this.currentIndex + 1} of ${this.totalCount}
137 </div>
138 <a href="${this.nextUrl}" ?hidden="${!this.nextUrl}" title="Next" class="next-url">
139 Next &rsaquo;
140 </a>
141 </div>
142 <div class="row">
143 <a href="${this.listUrl}" ?hidden="${!this.listUrl}" title="Back to list" class="list-url">
144 Back to list
145 </a>
146 </div>
147 `;
148 }
149}
150
151window.customElements.define('mr-flipper', MrFlipper);