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'; 17import { SpFlagHtml } from './SpFlag.html'; 18import { LitSelectV } from '../../base-ui/select/LitSelectV'; 19import { SysCallMap } from './trace/base/SysCallUtils'; 20 21const NUM = '000000'; 22//vsync二级下拉选框对应的value和content 23const VSYNC_CONTENT = [ 24 { value: 'H:VsyncGenerator', content: 'VsyncGeneratior' }, 25 { value: 'H:rs_SendVsync', content: 'Vsync-rs' }, 26 { value: 'H:app_SendVsync', content: 'Vsync-app' } 27]; 28//cat二级下拉选框对应的value和content 29const CAT_CONTENT = [ 30 { value: 'business', content: 'Business first' }, 31 { value: 'thread', content: 'Thread first' } 32]; 33//hang二级下拉选框对应的value和content 34const HANG_CONTENT = [ 35 { value: `33${NUM}`, content: 'Instant' }, 36 { value: `100${NUM}`, content: 'Circumstantial' }, 37 { value: `250${NUM}`, content: 'Micro' }, 38 { value: `500${NUM}`, content: 'Severe' } 39]; 40 41//整合默认值 42const CONFIG_STATE: unknown = { 43 'VSync': ['vsyncValue', 'VsyncGeneratior'], 44 'Start&Finish Trace Category': ['catValue', 'Business first'], 45 'Hangs Detection': ['hangValue', 'Instant'], 46}; 47 48@element('sp-flags') 49export class SpFlags extends BaseElement { 50 private bodyEl: HTMLElement | undefined | null; 51 private xiaoLubanEl: Element | null | undefined; 52 private systemCallSelect: LitSelectV | undefined | null; 53 private systemCallInput: HTMLInputElement | undefined | null; 54 private systemCallEventId: number[] = []; 55 private systemCallSwitch: HTMLSelectElement | undefined | null; 56 57 58 connectedCallback(): void { 59 this.systemCallSelect?.addEventListener('blur', this.systemCallSelectBlurHandler); 60 } 61 62 disconnectedCallback(): void { 63 super.disconnectedCallback(); 64 this.systemCallSelect?.removeEventListener('blur', this.systemCallSelectBlurHandler); 65 } 66 67 initElements(): void { 68 let parentElement = this.parentNode as HTMLElement; 69 parentElement.style.overflow = 'hidden'; 70 this.bodyEl = this.shadowRoot?.querySelector('.body'); 71 this.initConfigList(); 72 this.systemCallSelect = this.shadowRoot?.querySelector<LitSelectV>("lit-select-v[title='SystemCall']"); 73 this.systemCallSwitch = this.shadowRoot?.querySelector("select[title='System Calls']"); 74 this.systemCallInput = this.systemCallSelect!.shadowRoot?.querySelector('input') as HTMLInputElement; 75 this.updateSystemCallSelect(); 76 } 77 78 private updateSystemCallSelect(): void { 79 const selectedArr = FlagsConfig.getSystemcallEventId('SystemParsing'); 80 let checkAll = true; 81 systemCallConfigList[0].selectArray = Array.from(SysCallMap.entries()) 82 .map(([id, name]) => { 83 if (!selectedArr.includes(id)) { 84 checkAll = false; 85 } 86 return `${name}`; 87 }); 88 this.systemCallSelect?.dataSource(systemCallConfigList[0].selectArray, 'ALL-SystemCall'); 89 this.systemCallSelect?.setIgnoreValues(['ALL-SystemCall']); 90 if (this.systemCallSwitch?.title === 'System Calls' && this.systemCallSwitch.selectedOptions[0].value === 'Enabled') { 91 this.systemCallSelect?.removeAttribute('disabled'); 92 const arr = checkAll ? ['ALL-SystemCall' ] : []; 93 FlagsConfig.getSystemcallEventId('SystemParsing').forEach(it => arr.push(SysCallMap.get(it) || '')); 94 this.systemCallSelect?.setSelectedOptions(arr); 95 } else { 96 this.systemCallSelect?.setAttribute('disabled', 'disabled'); 97 this.systemCallSelect?.setSelectedOptions([]); 98 } 99 } 100 101 private systemCallSelectBlurHandler = () => { 102 let systemCallSelectOptions = this.systemCallSelect!.shadowRoot?.querySelectorAll('.option'); 103 this.systemCallEventId = []; 104 systemCallSelectOptions!.forEach((option) => { 105 if (option.hasAttribute('selected')) { 106 const systemCallEventItem = Array.from(SysCallMap.entries()) 107 .find(([id, name]) => name === option.getAttribute('value')); 108 if (systemCallEventItem) { 109 this.handleSystemCallEventId(systemCallEventItem[0]); 110 } 111 } 112 }); 113 FlagsConfig.updateSystemcallEventId(this.systemCallEventId, 'SystemParsing'); 114 return this.systemCallEventId; 115 }; 116 117 private handleSystemCallEventId = (systemCallEventId: number): void => { 118 this.systemCallEventId.push(systemCallEventId); 119 }; 120 121 initHtml(): string { 122 return SpFlagHtml; 123 } 124 125 private createConfigDiv(): HTMLDivElement { 126 let configDiv = document.createElement('div'); 127 configDiv.className = 'flag-widget'; 128 return configDiv; 129 } 130 //控制按钮设置为'Disabled'时,我们需要给一个默认值 131 private createCustomDiv(config: FlagConfigItem, configDiv: HTMLDivElement): void { 132 let configHadDiv = document.createElement('div'); 133 configHadDiv.className = 'flag-head-div'; 134 let titleLabel = document.createElement('label'); 135 titleLabel.textContent = config.title; 136 titleLabel.className = 'flag-title-label'; 137 let configSelect = document.createElement('select'); 138 configSelect.className = 'flag-select'; 139 configSelect.setAttribute('title', config.title); 140 config.switchOptions.forEach((optionItem) => { 141 let configOption = document.createElement('option'); 142 configOption.value = optionItem.option; 143 configOption.textContent = optionItem.option; 144 if (optionItem.selected) { 145 configOption.selected = true; 146 } 147 configSelect.appendChild(configOption); 148 }); 149 // 页面刷新时,选项并未改变,小鲁班也应当展示 150 this.xiaoLubanEl = document.querySelector('sp-application')?.shadowRoot?.querySelector('#sp-bubbles') 151 ?.shadowRoot?.querySelector('#xiao-luban-help'); 152 if (configSelect.title === 'AI' && configSelect.selectedOptions[0].value === 'Enabled') { 153 this.xiaoLubanEl?.setAttribute('enabled', ''); 154 } 155 configSelect.addEventListener('change', () => { 156 this.flagSelectListener(configSelect); 157 if (configSelect.title === 'AI') { 158 let userIdInput: HTMLInputElement | null | undefined = this.shadowRoot?.querySelector('#user_id_input'); 159 if (configSelect.selectedOptions[0].value === 'Enabled') { 160 if (userIdInput?.value === '') { 161 userIdInput.style.border = '1px solid red'; 162 } 163 this.xiaoLubanEl?.setAttribute('enabled', ''); 164 } else { 165 userIdInput!.style.border = '1px solid #ccc'; 166 this.xiaoLubanEl?.removeAttribute('enabled'); 167 } 168 } 169 if (configSelect.title === 'System Calls') { 170 if (configSelect.selectedOptions[0].value === 'Enabled') { 171 this.systemCallSelect?.removeAttribute('disabled'); 172 } else { 173 this.systemCallSelect?.setAttribute('disabled', 'disabled'); 174 this.systemCallEventId = []; 175 FlagsConfig.updateSystemcallEventId([], 'SystemParsing'); 176 this.systemCallSelect?.setSelectedOptions([]); 177 } 178 } 179 }); 180 let userIdInput: HTMLInputElement | null | undefined = this.shadowRoot?.querySelector('#user_id_input'); 181 if (configSelect.title === 'AI' && configSelect.selectedOptions[0].value === 'Enabled' && userIdInput?.value === '') { 182 userIdInput.style.border = '1px solid red'; 183 } 184 let description = document.createElement('div'); 185 description.className = 'flag-des-div'; 186 description.textContent = config.describeContent; 187 configHadDiv.appendChild(titleLabel); 188 configHadDiv.appendChild(configSelect); 189 configDiv.appendChild(configHadDiv); 190 configDiv.appendChild(description); 191 } 192 //监听flag-select的状态选择 193 private flagSelectListener(configSelect: HTMLSelectElement): void { 194 // @ts-ignore 195 let title = configSelect.getAttribute('title'); 196 //@ts-ignore 197 let listSelect = this.shadowRoot?.querySelector(`#${CONFIG_STATE[title]?.[0]}`); 198 // @ts-ignore 199 FlagsConfig.updateFlagsConfig(title!, configSelect.selectedOptions[0].value); 200 //@ts-ignore 201 if (listSelect) { 202 // @ts-ignore 203 if (configSelect.selectedOptions[0].value === 'Enabled') { 204 listSelect?.removeAttribute('disabled'); 205 } else { 206 listSelect?.childNodes.forEach((child: ChildNode) => { 207 let selectEl = child as HTMLOptionElement; 208 //@ts-ignore 209 if (child.textContent === CONFIG_STATE[title]?.[1]) { 210 selectEl.selected = true; 211 //@ts-ignore 212 FlagsConfig.updateFlagsConfig(CONFIG_STATE[title]?.[0], selectEl.value); 213 } else { 214 selectEl.selected = false; 215 } 216 }); 217 listSelect?.setAttribute('disabled', 'disabled'); 218 } 219 } 220 } 221 222 //初始化Flag对应的内容 223 private initConfigList(): void { 224 let allConfig = FlagsConfig.getAllFlagConfig(); 225 allConfig.forEach((config) => { 226 let configDiv = this.createConfigDiv(); 227 this.createCustomDiv(config, configDiv); 228 if (config.title === 'AnimationAnalysis') { 229 let configFooterDiv = document.createElement('div'); 230 configFooterDiv.className = 'config_footer'; 231 let deviceWidthLabelEl = document.createElement('label'); 232 deviceWidthLabelEl.className = 'device_label'; 233 deviceWidthLabelEl.textContent = 'PhysicalWidth :'; 234 let deviceWidthEl = document.createElement('input'); 235 deviceWidthEl.value = <string>config.addInfo!.physicalWidth; 236 deviceWidthEl.addEventListener('keyup', () => { 237 deviceWidthEl.value = deviceWidthEl.value.replace(/\D/g, ''); 238 }); 239 deviceWidthEl.addEventListener('blur', () => { 240 if (deviceWidthEl.value !== '') { 241 FlagsConfig.updateFlagsConfig('physicalWidth', Number(deviceWidthEl.value)); 242 } 243 }); 244 deviceWidthEl.className = 'device_input'; 245 let deviceHeightLabelEl = document.createElement('label'); 246 deviceHeightLabelEl.textContent = 'PhysicalHeight :'; 247 deviceHeightLabelEl.className = 'device_label'; 248 let deviceHeightEl = document.createElement('input'); 249 deviceHeightEl.className = 'device_input'; 250 deviceHeightEl.value = <string>config.addInfo!.physicalHeight; 251 deviceHeightEl.addEventListener('keyup', () => { 252 deviceHeightEl.value = deviceHeightEl.value.replace(/\D/g, ''); 253 }); 254 deviceHeightEl.addEventListener('blur', () => { 255 if (deviceWidthEl.value !== '') { 256 FlagsConfig.updateFlagsConfig('physicalHeight', Number(deviceHeightEl.value)); 257 } 258 }); 259 configFooterDiv.appendChild(deviceWidthLabelEl); 260 configFooterDiv.appendChild(deviceWidthEl); 261 configFooterDiv.appendChild(deviceHeightLabelEl); 262 configFooterDiv.appendChild(deviceHeightEl); 263 configDiv.appendChild(configFooterDiv); 264 } 265 //@ts-ignore 266 let configKey = CONFIG_STATE[config.title]?.[0]; 267 if (config.title === 'VSync') {//初始化Vsync 268 let configFooterDiv = this.createPersonOption(VSYNC_CONTENT, configKey, config); 269 configDiv.appendChild(configFooterDiv); 270 } 271 272 if (config.title === 'Start&Finish Trace Category') {//初始化Start&Finish Trace Category 273 let configFooterDiv = this.createPersonOption(CAT_CONTENT, configKey, config); 274 configDiv.appendChild(configFooterDiv); 275 } 276 277 if (config.title === 'Hangs Detection') {//初始化Hangs Detection 278 let configFooterDiv = this.createPersonOption(HANG_CONTENT, configKey, config); 279 configDiv.appendChild(configFooterDiv); 280 } 281 if (config.title === 'AI') { 282 let configFooterDiv = document.createElement('div'); 283 configFooterDiv.className = 'config_footer'; 284 let userIdLabelEl = document.createElement('label'); 285 userIdLabelEl.className = 'device_label'; 286 userIdLabelEl.textContent = 'User Id: '; 287 let userIdInputEl = document.createElement('input'); 288 userIdInputEl.value = <string>config.addInfo!.userId; 289 userIdInputEl.addEventListener('blur', () => { 290 if (userIdInputEl.value !== '') { 291 userIdInputEl.style.border = '1px solid #ccc'; 292 FlagsConfig.updateFlagsConfig('userId', userIdInputEl.value); 293 } else { 294 userIdInputEl.style.border = '1px solid red'; 295 } 296 }); 297 userIdInputEl.className = 'device_input'; 298 userIdInputEl.id = 'user_id_input'; 299 configFooterDiv.appendChild(userIdLabelEl); 300 configFooterDiv.appendChild(userIdInputEl); 301 configDiv.appendChild(configFooterDiv); 302 } 303 if (config.title === 'System Calls') { 304 let configFooterDiv = document.createElement('div'); 305 configFooterDiv.className = 'config_footer'; 306 let systemCallConfigEl = document.createElement('div'); 307 systemCallConfigEl.className = 'system-call-config'; 308 systemCallConfigList.forEach((config) => { 309 let systemCallConfigDiv = document.createElement('div'); 310 if (config.hidden) { 311 systemCallConfigDiv.className = 'systemCall-config-div hidden'; 312 } else { 313 systemCallConfigDiv.className = 'systemCall-config-div'; 314 } 315 switch (config.type) { 316 case 'select-multiple': 317 this.configTypeBySelectMultiple(config, systemCallConfigDiv); 318 break; 319 default: 320 break; 321 } 322 systemCallConfigEl.appendChild(systemCallConfigDiv); 323 }) 324 configFooterDiv.appendChild(systemCallConfigEl); 325 configDiv.appendChild(configFooterDiv); 326 } 327 this.bodyEl!.appendChild(configDiv); 328 }); 329 } 330 331 private configTypeBySelectMultiple(config: unknown, systemCallConfigDiv: HTMLDivElement): void { 332 let html = ''; 333 //@ts-ignore 334 let placeholder = config.selectArray[0]; 335 html += `<lit-select-v default-value='' rounded='' class='systemCall-config-select config' 336mode='multiple' canInsert='' title='${ 337 //@ts-ignore 338 config.title 339 }' rounded placement = 'bottom' placeholder='${placeholder}'>`; 340 //@ts-ignore 341 config.selectArray.forEach((value: string) => { 342 html += `<lit-select-option value='${value}'>${value}</lit-select-option>`; 343 }); 344 html += '</lit-select-v>'; 345 systemCallConfigDiv.innerHTML = systemCallConfigDiv.innerHTML + html; 346 } 347 348 private createPersonOption(list: unknown, key: string, config: unknown): HTMLDivElement { 349 let configFooterDiv = document.createElement('div'); 350 configFooterDiv.className = 'config_footer'; 351 let lableEl = document.createElement('lable'); 352 lableEl.className = 'list_lable'; 353 let typeEl = document.createElement('select'); 354 typeEl.setAttribute('id', key); 355 typeEl.className = 'flag-select'; 356 //根据给出的list遍历添加option下来选框 357 //@ts-ignore 358 for (const settings of list) { 359 let option = document.createElement('option'); 360 option.value = settings.value; 361 option.textContent = settings.content; 362 //初始化二级按钮状态 363 //@ts-ignore 364 if (option.value === config.addInfo?.[key]) { 365 option.selected = true; 366 FlagsConfig.updateFlagsConfig(key, option.value); 367 } 368 typeEl.appendChild(option); 369 } 370 typeEl.addEventListener('change', function () { 371 let selectValue = this.selectedOptions[0].value; 372 FlagsConfig.updateFlagsConfig(key, selectValue); 373 }); 374 let flagsItem = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY); 375 let flagsItemJson = JSON.parse(flagsItem!); 376 //@ts-ignore 377 let vsync = flagsItemJson[config.title]; 378 if (vsync === 'Enabled') { 379 typeEl.removeAttribute('disabled'); 380 } else { 381 typeEl.setAttribute('disabled', 'disabled'); 382 //@ts-ignore 383 FlagsConfig.updateFlagsConfig(key, config.addInfo?.[key]); 384 } 385 configFooterDiv.appendChild(lableEl); 386 configFooterDiv.appendChild(typeEl); 387 return configFooterDiv; 388 } 389} 390 391export type Params = { 392 [key: string]: unknown; 393}; 394 395export class FlagsConfig { 396 static FLAGS_CONFIG_KEY = 'FlagsConfig'; 397 static SYSTEM_PRASE = 'SystemParsing'; 398 static DEFAULT_CONFIG: Array<FlagConfigItem> = [ 399 { 400 title: 'TaskPool', 401 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 402 describeContent: 'Analyze TaskPool templates', 403 }, 404 { 405 title: 'AnimationAnalysis', 406 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 407 describeContent: 'Analyze Animation effect templates', 408 addInfo: { physicalWidth: 0, physicalHeight: 0 }, 409 }, 410 { 411 title: 'AppStartup', 412 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 413 describeContent: 'App Startup templates', 414 }, 415 { 416 title: 'SchedulingAnalysis', 417 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 418 describeContent: 'Scheduling analysis templates', 419 }, 420 { 421 title: 'BinderRunnable', 422 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 423 describeContent: 'support Cpu State Binder-Runnable', 424 }, 425 { 426 title: 'FfrtConvert', 427 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 428 describeContent: 'Ffrt Convert templates', 429 }, 430 { 431 title: 'HMKernel', 432 switchOptions: [{ option: 'Enabled', selected: true }, { option: 'Disabled' }], 433 describeContent: '', 434 }, 435 { 436 title: 'VSync', 437 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 438 describeContent: 'VSync Signal drawing', 439 addInfo: { vsyncValue: VSYNC_CONTENT[0].value }, 440 }, 441 { 442 title: 'Hangs Detection', 443 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 444 describeContent: 'hangs type:Instant(33ms~100ms),Circumstantial(100ms~250ms),Micro(250ms~500ms),Severe(>=500ms)', 445 addInfo: { hangValue: HANG_CONTENT[0].value }, 446 }, 447 { 448 title: 'LTPO', 449 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 450 describeContent: 'Lost Frame and HitchTime templates', 451 }, 452 { 453 title: 'Start&Finish Trace Category', 454 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 455 describeContent: 'Asynchronous trace aggregation', 456 addInfo: { catValue: CAT_CONTENT[0].value }, 457 }, 458 { 459 title: 'UserPluginsRow', 460 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 461 describeContent: 'User Upload Plugin To Draw', 462 }, 463 { 464 title: 'CPU by Irq', 465 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 466 describeContent: 'The real CPU after being split by irq and softirq', 467 }, 468 { 469 title: 'RawTraceCutStartTs', 470 switchOptions: [{ option: 'Enabled', selected: true }, { option: 'Disabled' }], 471 describeContent: 'Raw Trace Cut By StartTs, StartTs = Max(Cpu1 StartTs, Cpu2 StartTs, ..., CpuN StartTs)', 472 }, 473 { 474 title: 'AI', 475 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 476 describeContent: 'Start AI', 477 addInfo: { userId: '' }, 478 }, 479 { 480 title: 'System Calls', 481 switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], 482 describeContent: 'Start System Call Parsing', 483 addInfo: { userId: '' }, 484 } 485 ]; 486 487 static getAllFlagConfig(): Array<FlagConfigItem> { 488 let flagsConfigStr = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY); 489 if (flagsConfigStr === null) { 490 let flagConfigObj: Params = {}; 491 FlagsConfig.DEFAULT_CONFIG.forEach((config) => { 492 let selectedOption = config.switchOptions.filter((option) => { 493 return option.selected; 494 }); 495 let value = config.switchOptions[0].option; 496 if (selectedOption[0] !== undefined) { 497 value = selectedOption[0].option; 498 } 499 flagConfigObj[config.title] = value; 500 if (config.addInfo) { 501 for (const [key, value] of Object.entries(config.addInfo)) { 502 flagConfigObj[key] = value; 503 } 504 } 505 }); 506 window.localStorage.setItem(FlagsConfig.FLAGS_CONFIG_KEY, JSON.stringify(flagConfigObj)); 507 return FlagsConfig.DEFAULT_CONFIG; 508 } else { 509 let flagsConfig = JSON.parse(flagsConfigStr); 510 FlagsConfig.DEFAULT_CONFIG.forEach((config) => { 511 let cfg = flagsConfig[config.title]; 512 if (cfg) { 513 config.switchOptions.forEach((option) => { 514 if (option.option === cfg) { 515 option.selected = true; 516 } else { 517 option.selected = false; 518 } 519 }); 520 } 521 if (config.addInfo) { 522 for (const [key, value] of Object.entries(config.addInfo)) { 523 let cfg = flagsConfig[key]; 524 if (cfg) { 525 config.addInfo[key] = cfg; 526 } 527 } 528 } 529 }); 530 } 531 return FlagsConfig.DEFAULT_CONFIG; 532 } 533 534 static getSpTraceStreamParseConfig(): string { 535 let parseConfig = {}; 536 FlagsConfig.getAllFlagConfig().forEach((configItem) => { 537 let selectedOption = configItem.switchOptions.filter((option) => { 538 return option.selected; 539 }); 540 // @ts-ignore 541 parseConfig[configItem.title] = selectedOption[0].option === 'Enabled' ? 1 : 0; 542 // @ts-ignore 543 if (configItem.title === 'System Calls') { 544 // @ts-ignore 545 parseConfig[configItem.title] = selectedOption[0].option === 'Enabled' ? FlagsConfig.getSystemcallEventId('SystemParsing').join(';') : ''; 546 } 547 }); 548 return JSON.stringify({ config: parseConfig }); 549 } 550 551 static getFlagsConfig(flagName: string): Params | undefined { 552 let flagConfigObj: Params = {}; 553 let configItem = FlagsConfig.getAllFlagConfig().find((config) => { 554 return config.title === flagName; 555 }); 556 if (configItem) { 557 let selectedOption = configItem.switchOptions.filter((option) => { 558 return option.selected; 559 }); 560 let value = configItem.switchOptions[0].option; 561 if (selectedOption[0] !== undefined) { 562 value = selectedOption[0].option; 563 } 564 flagConfigObj[configItem.title] = value; 565 if (configItem.addInfo) { 566 for (const [key, value] of Object.entries(configItem.addInfo)) { 567 flagConfigObj[key] = value; 568 } 569 } 570 return flagConfigObj; 571 } else { 572 return configItem; 573 } 574 } 575 576 static getFlagsConfigEnableStatus(flagName: string): boolean { 577 let config = FlagsConfig.getFlagsConfig(flagName); 578 let enable: boolean = false; 579 if (config && config[flagName]) { 580 enable = config[flagName] === 'Enabled'; 581 } 582 return enable; 583 } 584 //获取Cat的二级下拉选框所选的内容 585 static getSecondarySelectValue(value: string): string { 586 let list = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY); 587 let listJson = JSON.parse(list!); 588 let catSelectValue = listJson[value]; 589 return catSelectValue; 590 } 591 592 static updateFlagsConfig(key: string, value: unknown): void { 593 let flagsConfigStr = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY); 594 let flagConfigObj: Params = {}; 595 if (flagsConfigStr !== null) { 596 flagConfigObj = JSON.parse(flagsConfigStr); 597 } 598 flagConfigObj[key] = value; 599 window.localStorage.setItem(FlagsConfig.FLAGS_CONFIG_KEY, JSON.stringify(flagConfigObj)); 600 } 601 602 603 static getSystemcallEventId(value: string): number[] { 604 let list = window.localStorage.getItem(FlagsConfig.SYSTEM_PRASE); 605 return JSON.parse(list!) || []; 606 } 607 608 static updateSystemcallEventId(systemCallEventId: number[], value: unknown): void { 609 let systemCallEventIdArray:number[] = []; 610 if (systemCallEventId !== null) { 611 systemCallEventIdArray = systemCallEventId; 612 } 613 window.localStorage.setItem(FlagsConfig.SYSTEM_PRASE, JSON.stringify(systemCallEventIdArray)); 614 } 615} 616 617export interface FlagConfigItem { 618 title: string; 619 switchOptions: OptionItem[]; 620 describeContent: string; 621 addInfo?: Params; 622} 623 624export interface OptionItem { 625 option: string; 626 selected?: boolean; 627} 628 629const systemCallConfigList = [ 630 { 631 title: 'SystemCall', 632 des: '', 633 hidden: true, 634 type: 'select-multiple', 635 selectArray: [''], 636 }] 637