• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { BaseElement, element } from '../../base-ui/BaseElement';
17
18@element('sp-flags')
19export class SpFlags extends BaseElement {
20  private bodyEl: HTMLElement | undefined | null;
21
22  initElements(): void {
23    let parentElement = this.parentNode as HTMLElement;
24    parentElement.style.overflow = 'hidden';
25    this.bodyEl = this.shadowRoot?.querySelector('.body');
26    this.initConfigList();
27  }
28
29  initHtml(): string {
30    return `
31        ${this.initHtmlStyle()}
32        <div class="sp-flags-vessel">
33         <div class="body">
34           <h3 class="title">Feature flags</h3>
35         </div>
36        </div>
37        `;
38  }
39
40  private initHtmlStyle(): string {
41    return `
42      <style>
43        .sp-flags-vessel {
44          background-color: var(--dark-background5,#F6F6F6);
45          min-height: 100%;
46          display: grid;
47          grid-template-columns: 1fr;
48          grid-template-rows:1fr;
49        }
50        :host{
51          width: 100%;
52          height: 100%;
53          background-color: var(--dark-background5,#F6F6F6);
54          display: block;
55        }
56        .body{
57          width: 85%;
58          margin: 2% 5% 2% 5%;
59          background-color: var(--dark-background3,#FFFFFF);
60          border-radius: 16px 16px 16px 16px;
61          padding-left: 2%;
62          padding-right: 4%;
63        }
64        .title {
65          padding-left: 2%;
66          margin-left: 8%;
67        }
68        .flag-widget {
69          width: 80%;
70          padding: 1% 2% 1% 2%;
71          margin-left: 8%;
72          margin-right: 8%;
73          border-radius: 10px 10px 10px 10px;
74        }
75        .flag-widget:nth-child(2n+1) {
76          background-color: #F5F5F5;
77        }
78        .flag-title-label {
79          margin-right: 10px;
80          flex-grow: 1;
81          text-align: left;
82          opacity: 0.9;
83          font-family: Helvetica-Bold;
84          font-size: 16px;
85          color: #000000;
86          line-height: 28px;
87          font-weight: 700;
88        }
89        .flag-head-div {
90          display: flex;
91          align-items: center;
92        }
93        .flag-des-div {
94          opacity: 0.6;
95          font-family: Helvetica;
96          font-size: 12px;
97          color: var(--dark-color,#000000);
98          text-align: left;
99          line-height: 20px;
100          font-weight: 400;
101          margin-top: 0.1%;
102        }
103        .config_footer {
104          margin-top: 1%;
105        }
106        .flag-select {
107          width: 12rem;
108          border: 1px solid var(--dark-color1,#4D4D4D);
109          border-radius: 16px;
110          opacity: 0.6;
111          font-family: Helvetica;
112          font-size: 12px;
113          color: var(--dark-color1,#000000);
114          text-align: center;
115          line-height: 20px;
116          font-weight: 400;
117          -webkit-appearance: none;
118          background: url(img/down.png) no-repeat 96% center;
119        }
120        .device_label {
121          font-weight: 500;
122          margin-right: 10px;
123          opacity: 0.9;
124          font-family: Helvetica-Bold;
125          font-size: 14px;
126        }
127        .device_input {
128          line-height: 20px;
129          font-weight: 400;
130          margin-right: 2%;
131          border-radius: 16px;
132          border: 1px solid #ccc;
133          padding-left: 10px;
134        }
135        </style>
136    `;
137  }
138
139  private createConfigDiv(): HTMLDivElement {
140    let configDiv = document.createElement('div');
141    configDiv.className = 'flag-widget';
142    return configDiv;
143  }
144
145  private createCustomDiv(config: FlagConfigItem, configDiv: HTMLDivElement): void {
146    let configHadDiv = document.createElement('div');
147    configHadDiv.className = 'flag-head-div';
148    let titleLabel = document.createElement('label');
149    titleLabel.textContent = config.title;
150    titleLabel.className = 'flag-title-label';
151    let configSelect = document.createElement('select');
152    configSelect.className = 'flag-select';
153    configSelect.setAttribute('title', config.title);
154    config.switchOptions.forEach((optionItem) => {
155      let configOption = document.createElement('option');
156      configOption.value = optionItem.option;
157      configOption.textContent = optionItem.option;
158      if (optionItem.selected) {
159        configOption.selected = true;
160      }
161      configSelect.appendChild(configOption);
162    });
163    configSelect.addEventListener('change', () => {
164      let title = configSelect.getAttribute('title');
165      FlagsConfig.updateFlagsConfig(title!, configSelect.selectedOptions[0].value);
166    });
167    let description = document.createElement('div');
168    description.className = 'flag-des-div';
169    description.textContent = config.describeContent;
170    configHadDiv.appendChild(titleLabel);
171    configHadDiv.appendChild(configSelect);
172    configDiv.appendChild(configHadDiv);
173    configDiv.appendChild(description);
174  }
175
176  private initConfigList(): void {
177    let allConfig = FlagsConfig.getAllFlagConfig();
178    allConfig.forEach((config) => {
179      let configDiv = this.createConfigDiv();
180      this.createCustomDiv(config, configDiv);
181      if (config.title === 'AnimationAnalysis') {
182        let configFooterDiv = document.createElement('div');
183        configFooterDiv.className = 'config_footer';
184        let deviceWidthLabelEl = document.createElement('label');
185        deviceWidthLabelEl.className = 'device_label';
186        deviceWidthLabelEl.textContent = 'PhysicalWidth :';
187        let deviceWidthEl = document.createElement('input');
188        deviceWidthEl.value = <string>config.addInfo!.physicalWidth;
189        deviceWidthEl.addEventListener('keyup', () => {
190          deviceWidthEl.value = deviceWidthEl.value.replace(/\D/g, '');
191        });
192        deviceWidthEl.addEventListener('blur', () => {
193          if (deviceWidthEl.value !== '') {
194            FlagsConfig.updateFlagsConfig('physicalWidth', Number(deviceWidthEl.value));
195          }
196        });
197        deviceWidthEl.className = 'device_input';
198        let deviceHeightLabelEl = document.createElement('label');
199        deviceHeightLabelEl.textContent = 'PhysicalHeight :';
200        deviceHeightLabelEl.className = 'device_label';
201        let deviceHeightEl = document.createElement('input');
202        deviceHeightEl.className = 'device_input';
203        deviceHeightEl.value = <string>config.addInfo!.physicalHeight;
204        deviceHeightEl.addEventListener('keyup', () => {
205          deviceHeightEl.value = deviceHeightEl.value.replace(/\D/g, '');
206        });
207        deviceHeightEl.addEventListener('blur', () => {
208          if (deviceWidthEl.value !== '') {
209            FlagsConfig.updateFlagsConfig('physicalHeight', Number(deviceHeightEl.value));
210          }
211        });
212        configFooterDiv.appendChild(deviceWidthLabelEl);
213        configFooterDiv.appendChild(deviceWidthEl);
214        configFooterDiv.appendChild(deviceHeightLabelEl);
215        configFooterDiv.appendChild(deviceHeightEl);
216        configDiv.appendChild(configFooterDiv);
217      }
218      this.bodyEl!.appendChild(configDiv);
219    });
220  }
221}
222
223export type Params = {
224  [key: string]: unknown;
225};
226
227export class FlagsConfig {
228  static FLAGS_CONFIG_KEY = 'FlagsConfig';
229  static DEFAULT_CONFIG: Array<FlagConfigItem> = [
230    {
231      title: 'TaskPool',
232      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
233      describeContent: 'Analyze TaskPool templates',
234    },
235    {
236      title: 'AnimationAnalysis',
237      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
238      describeContent: 'Analyze Animation effect templates',
239      addInfo: { physicalWidth: 0, physicalHeight: 0 },
240    },
241    {
242      title: 'AppStartup',
243      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
244      describeContent: 'App Startup templates',
245    },
246    {
247      title: 'SchedulingAnalysis',
248      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
249      describeContent: 'Scheduling analysis templates',
250    },
251    {
252      title: 'BinderRunnable',
253      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
254      describeContent: 'support Cpu State Binder-Runnable',
255    },
256    {
257      title: 'FfrtConvert',
258      switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }],
259      describeContent: 'Ffrt Convert templates',
260    },
261  ];
262
263  static getAllFlagConfig(): Array<FlagConfigItem> {
264    let flagsConfigStr = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY);
265    if (flagsConfigStr === null) {
266      let flagConfigObj: Params = {};
267      FlagsConfig.DEFAULT_CONFIG.forEach((config) => {
268        let selectedOption = config.switchOptions.filter((option) => {
269          return option.selected;
270        });
271        let value = config.switchOptions[0].option;
272        if (selectedOption[0] !== undefined) {
273          value = selectedOption[0].option;
274        }
275        flagConfigObj[config.title] = value;
276        if (config.addInfo) {
277          for (const [key, value] of Object.entries(config.addInfo)) {
278            flagConfigObj[key] = value;
279          }
280        }
281      });
282      window.localStorage.setItem(FlagsConfig.FLAGS_CONFIG_KEY, JSON.stringify(flagConfigObj));
283      return FlagsConfig.DEFAULT_CONFIG;
284    } else {
285      let flagsConfig = JSON.parse(flagsConfigStr);
286      FlagsConfig.DEFAULT_CONFIG.forEach((config) => {
287        let cfg = flagsConfig[config.title];
288        if (cfg) {
289          config.switchOptions.forEach((option) => {
290            if (option.option === cfg) {
291              option.selected = true;
292            } else {
293              option.selected = false;
294            }
295          });
296        }
297        if (config.addInfo) {
298          for (const [key, value] of Object.entries(config.addInfo)) {
299            let cfg = flagsConfig[key];
300            if (cfg) {
301              config.addInfo[key] = cfg;
302            }
303          }
304        }
305      });
306    }
307    return FlagsConfig.DEFAULT_CONFIG;
308  }
309
310  static getSpTraceStreamParseConfig(): string {
311    let parseConfig = {};
312    FlagsConfig.getAllFlagConfig().forEach((configItem) => {
313      let selectedOption = configItem.switchOptions.filter((option) => {
314        return option.selected;
315      });
316      // @ts-ignore
317      parseConfig[configItem.title] = selectedOption[0].option === 'Enabled' ? 1 : 0;
318    });
319    return JSON.stringify({ config: parseConfig });
320  }
321
322  static getFlagsConfig(flagName: string): Params | undefined {
323    let flagConfigObj: Params = {};
324    let configItem = FlagsConfig.getAllFlagConfig().find((config) => {
325      return config.title === flagName;
326    });
327    if (configItem) {
328      let selectedOption = configItem.switchOptions.filter((option) => {
329        return option.selected;
330      });
331      let value = configItem.switchOptions[0].option;
332      if (selectedOption[0] !== undefined) {
333        value = selectedOption[0].option;
334      }
335      flagConfigObj[configItem.title] = value;
336      if (configItem.addInfo) {
337        for (const [key, value] of Object.entries(configItem.addInfo)) {
338          flagConfigObj[key] = value;
339        }
340      }
341      return flagConfigObj;
342    } else {
343      return configItem;
344    }
345  }
346
347  static getFlagsConfigEnableStatus(flagName: string): boolean {
348    let config = FlagsConfig.getFlagsConfig(flagName);
349    let enable: boolean = false;
350    if (config && config[flagName]) {
351      enable = config[flagName] === 'Enabled';
352    }
353    return enable;
354  }
355
356  static updateFlagsConfig(key: string, value: unknown): void {
357    let flagsConfigStr = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY);
358    let flagConfigObj: Params = {};
359    if (flagsConfigStr !== null) {
360      flagConfigObj = JSON.parse(flagsConfigStr);
361    }
362    flagConfigObj[key] = value;
363    window.localStorage.setItem(FlagsConfig.FLAGS_CONFIG_KEY, JSON.stringify(flagConfigObj));
364  }
365}
366
367export interface FlagConfigItem {
368  title: string;
369  switchOptions: OptionItem[];
370  describeContent: string;
371  addInfo?: Params;
372}
373
374export interface OptionItem {
375  option: string;
376  selected?: boolean;
377}
378