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 { getThreadPoolTraceBufferCacheKey } from './database/SqlLite'; 17 18export enum TraceMode { 19 NORMAL, 20 LONG_TRACE, 21 DISTRIBUTED, 22} 23 24export const applicationHtml: string = ` 25 <style> 26 :host{ 27 28 } 29 .dark{ 30 --dark-background: #272C34; 31 --dark-background1: #424851; 32 --dark-background2: #262f3c; 33 --dark-background3: #292D33; 34 --dark-background4: #323841; 35 --dark-background5: #333840; 36 --dark-background6: rgba(82,145,255,0.2); 37 --dark-background7: #494d52; 38 --dark-background8: #5291FF; 39 --dark-color: rgba(255,255,255,0.6); 40 --dark-color1: rgba(255,255,255,0.86); 41 --dark-color2: rgba(255,255,255,0.9); 42 --dark-border: #474F59; 43 --dark-color3:#4694C2; 44 --dark-color4:#5AADA0; 45 --dark-border1: #454E5A; 46 --bark-expansion:#0076FF; 47 --bark-prompt:#9e9e9e; 48 --dark-icon:#adafb3; 49 --dark-img: url('img/dark_pic.png'); 50 background: #272C34; 51 color: #FFFFFF; 52 } 53 .root{ 54 display: grid; 55 grid-template-rows: min-content 1fr; 56 grid-template-columns: min-content 1fr; 57 grid-template-areas: 'm s' 58 'm b'; 59 height: 100vh; 60 width: 100vw; 61 } 62 .filedrag::after { 63 content: 'Drop the trace file to open it'; 64 position: fixed; 65 z-index: 2001; 66 top: 0; 67 left: 0; 68 right: 0; 69 bottom: 0; 70 border: 5px dashed var(--dark-color1,#404854); 71 text-align: center; 72 font-size: 3rem; 73 line-height: 100vh; 74 background: rgba(255, 255, 255, 0.5); 75 } 76 .menu{ 77 grid-area: m; 78 /*transition: all 0.2s;*/ 79 box-shadow: 4px 0px 20px rgba(0,0,0,0.05); 80 z-index: 2000; 81 } 82 .search-vessel{ 83 z-index: 999; 84 position: relative; 85 cursor: default; 86 } 87 .progress{ 88 bottom: 0; 89 position: absolute; 90 height: 1px; 91 left: 0; 92 right: 0; 93 } 94 95 :host(:not([search])) .search-vessel { 96 display: none; 97 } 98 :host(:not([search])) .search-vessel .search { 99 background-color: var(--dark-background5,#F6F6F6); 100 } 101 .search{ 102 grid-area: s; 103 background-color: var(--dark-background,#FFFFFF); 104 height: 48px; 105 display: flex; 106 justify-content: center; 107 align-items: center; 108 109 } 110 .search .search-bg{ 111 background-color: var(--dark-background5,#fff); 112 border-radius: 40px; 113 padding: 3px 20px; 114 display: flex; 115 justify-content: center; 116 align-items: center; 117 border: 1px solid var(--dark-border,#c5c5c5); 118 } 119 lit-search input{ 120 outline: none; 121 border: 0px; 122 background-color: transparent; 123 font-size: inherit; 124 color: var(--dark-color,#666666); 125 width: 30vw; 126 height: auto; 127 vertical-align:middle; 128 line-height:inherit; 129 height:inherit; 130 padding: 6px 6px 6px 6px}; 131 max-height: inherit; 132 box-sizing: border-box; 133 134 } 135 ::placeholder { /* CSS 3 標準 */ 136 color: #b5b7ba; 137 font-size: 1em; 138 } 139 lit-search input::placeholder { 140 color: #b5b7ba; 141 font-size: 1em; 142 } 143 .content{ 144 grid-area: b; 145 background-color: #ffffff; 146 height: 100%; 147 overflow: auto; 148 position:relative; 149 } 150 .sheet{ 151 152 } 153 .sidebar-button{ 154 position: absolute; 155 top: 0; 156 left: 0; 157 background-color: var(--dark-background1,#FFFFFF); 158 height: 100%; 159 border-radius: 0 5px 5px 0; 160 width: 48px; 161 display: flex; 162 align-content: center; 163 justify-content: center; 164 cursor: pointer; 165 } 166 :host{ 167 font-size: inherit; 168 display: inline-block; 169 transition: .3s; 170 } 171 :host([spin]){ 172 animation: rotate 1.75s linear infinite; 173 } 174 @keyframes rotate { 175 to{ 176 transform: rotate(360deg); 177 } 178 } 179 .icon{ 180 display: block; 181 width: 1em; 182 height: 1em; 183 margin: auto; 184 fill: currentColor; 185 overflow: hidden; 186 font-size: 20px; 187 color: #1E4EEA; 188 } 189 :host([chart_filter]) .chart-filter { 190 display: grid; 191 grid-template-rows: min-content min-content min-content max-content auto; 192 overflow-y: clip; 193 height: 99%; 194 visibility: visible; 195 position: absolute; 196 width: 40%; 197 right: 0; 198 z-index: 1001; 199 top: 0; 200 } 201 :host([custom-color]) .custom-color { 202 display: grid; 203 grid-template-rows: min-content min-content min-content max-content auto; 204 overflow-y: auto; 205 height: 100%; 206 visibility: visible; 207 position: absolute; 208 width: 50%; 209 right: 0; 210 z-index: 1002; 211 top: 0; 212 } 213 .filter-config { 214 opacity: 1; 215 visibility: hidden; 216 } 217 .filter-config:hover { 218 opacity: 0.7; 219 } 220 .page-button[prohibit] { 221 cursor: none; 222 } 223 .page-button { 224 background: #D8D8D8; 225 border-radius: 12px; 226 width: 24px; 227 height: 24px; 228 margin-right: 12px; 229 display: flex; 230 justify-content: center; 231 align-items: center; 232 } 233 #preview-button:hover { 234 cursor: pointer; 235 background: #0A59F7; 236 color: #FFFFFF; 237 opacity: 1; 238 } 239 #next-button:hover { 240 cursor: pointer; 241 background: #0A59F7; 242 color: #FFFFFF; 243 opacity: 1; 244 } 245 .pagination:hover { 246 cursor: pointer; 247 background: #0A59F7; 248 color: #FFFFFF; 249 opacity: 1; 250 } 251 .confirm-button:hover { 252 cursor: pointer; 253 background: #0A59F7; 254 color: #FFFFFF; 255 opacity: 1; 256 } 257 .pagination { 258 background: #D8D8D8; 259 color: #000000; 260 border-radius: 12px; 261 width: 24px; 262 height: 24px; 263 margin-right: 12px; 264 display: flex; 265 justify-content: center; 266 align-items: center; 267 font-family: Helvetica; 268 font-size: 12px; 269 text-align: center; 270 line-height: 20px; 271 font-weight: 400; 272 opacity: 0.6; 273 } 274 .pagination[selected] { 275 background: #0A59F7; 276 color: #FFFFFF; 277 opacity: 1; 278 } 279 .page-jump-font { 280 opacity: 0.6; 281 font-family: Helvetica; 282 font-size: 12px; 283 color: #000000; 284 text-align: center; 285 line-height: 20px; 286 font-weight: 400; 287 } 288 .page-input { 289 background: #D8D8D8; 290 border-radius: 10px; 291 width: 40px; 292 height: 24px; 293 justify-content: center; 294 align-items: center; 295 text-align: center; 296 margin-right: 8px; 297 border: none; 298 } 299 .confirm-button { 300 font-family: Helvetica; 301 font-size: 12px; 302 color: #0A59F7; 303 text-align: center; 304 font-weight: 400; 305 border: 1px solid #0A59F7; 306 border-radius: 10px; 307 width: 64px; 308 height: 24px; 309 line-height: 24px; 310 } 311 .long_trace_page { 312 justify-content: center; 313 width: -webkit-fill-available; 314 margin-right: 5.2em; 315 align-items: center; 316 display: none; 317 } 318 .content-center-option { 319 justify-content: center; 320 width: -webkit-fill-available; 321 margin-right: 5.2em; 322 align-items: center; 323 width: auto; 324 } 325 .page-number-list { 326 display: flex; 327 } 328 329 #sp-ai-analysis { 330 top:0px; 331 right:0px; 332 position:absolute; 333 z-index:9999; 334 min-width:430px; 335 max-width:75%; 336 width:430px; 337 height:740px; 338 box-shadow:3px 0px 14px #000; 339 border-radius:8px; 340 background-color:#fff; 341 padding:10px 10px 10px 5px; 342 user-select:none; 343 box-sizing:border-box; 344 visibility:hidden; 345 } 346 </style> 347 <div class="root" style="position: relative;"> 348 <sp-bubble-ai style="visibility: visible; top:50%;right:2px;position: absolute;z-index: 1000" id="sp-bubbles"></sp-bubble-ai> 349 <sp-advertisement style="bottom:2px;right:2px;position: absolute;z-index: 10086" id= "sp-advertisement"></sp-advertisement> 350 <lit-main-menu id="main-menu" class="menu" data=''></lit-main-menu> 351 <sp-keyboard style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 8888" id="sp-keyboard"> 352 </sp-keyboard> 353 <div class="search-vessel"> 354 <div class="search" style="position: relative;"> 355 <div class="sidebar-button" style="width: 0"> 356 <svg class="icon" id="icon" aria-hidden="true" viewBox="0 0 1024 1024"> 357 <use id="use" xlink:href="./base-ui/icon.svg#icon-menu"></use> 358 </svg> 359 </div> 360 <div class = "content-left-option" style="text-align: left; 361 position: absolute;left: 5px ; cursor: pointer;top: 15px"> 362 <div title="Import Key Path" id="import-key-path" style="display: none ;text-align: left;cursor: pointer;"> 363 <input id="import-config" style="display: none;pointer-events: none" type="file" accept=".json" > 364 <label style="width: 20px;height: 20px;cursor: pointer;" for="import-config"> 365 <lit-icon id="import-btn" name="copy-csv" style="pointer-events: none" size="20"> 366 </lit-icon> 367 </label> 368 </div> 369 <lit-icon id="close-key-path" name="close" title="Close Key Path" color='#fff' size="20" style="display: none;text-align: left;cursor: pointer;"> 370 </lit-icon> 371 </div> 372 <lit-search id="lit-search"></lit-search> 373 <lit-search id="lit-record-search"></lit-search> 374 <div class="content-center-option" style="display: "> 375 <div class="long_trace_page" style="display: none;"> 376 <div class="page-button" id="preview-button"> 377 <img title="preview" src="img/preview.png"/> 378 </div> 379 <div class="page-number-list"></div> 380 <div class="page-button" id="next-button" style="margin-right: 8px;"> 381 <img title="next" src="img/next.png"/> 382 </div> 383 <div class="page-jump-font" style="margin-right: 8px;">To</div> 384 <input class="page-input" /> 385 <div class="confirm-button">Confirm</div> 386 </div> 387 </div> 388 </div> 389 <div class = "content-right-option" style="display: flex;flex-flow: nowrap;text-align: right;position: absolute;right: 1.2em;cursor: pointer;top: 17px""> 390 <img class="ai_analysis" title="Display Template" src="img/ai-analysis.png" style="margin-left: 0.8em;width:16px;height:16px"> 391 <lit-icon class="export-record" title="Download Mark Trace" name="download" size="16" style="margin-left: 0.8em;"></lit-icon> 392 <img class="cut-trace-file" title="Cut Trace File" src="img/menu-cut.svg" style="margin-left: 0.8em;"> 393 <img class="filter-config" title="Display Template" src="img/config_filter.png" style="margin-left: 0.8em;"> 394 </div> 395 <lit-progress-bar class="progress"></lit-progress-bar> 396 </div> 397 <div id="app-content" class="content"> 398 <sp-welcome style="visibility:visible;top:0px;left:0px;position:absolute;z-index: 100" id="sp-welcome"> 399 </sp-welcome> 400 <sp-ai-analysis id="sp-ai-analysis"> 401 </sp-ai-analysis> 402 <sp-system-trace style="visibility:hidden;z-index: 101;" id="sp-system-trace"> 403 </sp-system-trace> 404 <sp-record-trace style="overflow:auto;width:100%;height:100%;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 102" id="sp-record-trace"> 405 </sp-record-trace> 406 <sp-record-trace record_template='' style="overflow:auto;width:100%;height:100%;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 102" id="sp-record-template"> 407 </sp-record-trace> 408 <sp-scheduling-analysis style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;" id="sp-scheduling-analysis"></sp-scheduling-analysis> 409 <sp-metrics style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 105" id="sp-metrics"> 410 </sp-metrics> 411 <sp-query-sql style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 106" id="sp-query-sql"> 412 </sp-query-sql> 413 <sp-info-and-stats style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 107" id="sp-info-and-stats"> 414 </sp-info-and-stats> 415 <sp-convert-trace style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 107" id="sp-convert-trace"> 416 </sp-convert-trace> 417 <sp-help style="width:100%;height:100%;overflow:hidden;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 103" id="sp-help"> 418 </sp-help> 419 <sp-flags style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 104" id="sp-flags"> 420 </sp-flags> 421 <sp-third-party style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 104" id="sp-third-party"> 422 </sp-third-party> 423 <trace-row-config class="chart-filter" style="height:100%;top:0px;right:0;bottom:0px;position:absolute;z-index: 1001"></trace-row-config> 424 <custom-theme-color class="custom-color" style="height:100%;top:0px;right:0;bottom:0px;position:absolute;z-index: 1001"></custom-theme-color> 425 </div> 426 </div> 427 `; 428 429export function readTraceFileBuffer(): Promise<ArrayBuffer | undefined> { 430 return new Promise((resolve) => { 431 caches.match(getThreadPoolTraceBufferCacheKey('1')).then((res) => { 432 if (res) { 433 res.arrayBuffer().then((buffer) => { 434 resolve(buffer); 435 }); 436 } else { 437 resolve(undefined); 438 } 439 }); 440 }); 441} 442 443export function clearTraceFileCache(): void { 444 caches.keys().then((keys) => { 445 keys.forEach((key) => { 446 if (key === getThreadPoolTraceBufferCacheKey('1')) { 447 caches.delete(key).then(); 448 } else if (key.includes('/') && key.includes('-')) { 449 let splits = key.split('/'); 450 let keyStr = splits[splits.length - 1]; 451 let time = keyStr.split('-')[0]; 452 let fileDate = new Date(parseInt(time)); 453 if (fileDate.toLocaleDateString() !== new Date().toLocaleDateString()) { 454 //如果不是当天的缓存则删去缓存文件 455 caches.delete(key).then(); 456 } 457 } else { 458 caches.delete(key).then(); 459 } 460 }); 461 }); 462} 463 464export function postLog(filename: string, fileSize: string): void { 465 fetch(`https://${window.location.host.split(':')[0]}:${window.location.port}/logger`, { 466 method: 'POST', 467 headers: { 468 'Content-Type': 'application/json', 469 }, 470 body: JSON.stringify({ 471 fileName: filename, 472 fileSize: fileSize, 473 }), 474 }) 475 .then((response) => response.json()) 476 .then((data) => { }) 477 .catch((error) => { }); 478} 479 480export function indexedDataToBufferData(sourceData: unknown): ArrayBuffer { 481 let uintArrayLength = 0; 482 //@ts-ignore 483 let uintDataList = sourceData.map((item: unknown) => { 484 //@ts-ignore 485 let currentBufData = new Uint8Array(item.buf); 486 uintArrayLength += currentBufData.length; 487 return currentBufData; 488 }); 489 let resultArrayBuffer = new ArrayBuffer(uintArrayLength); 490 let resultUintArray = new Uint8Array(resultArrayBuffer); 491 let offset = 0; 492 uintDataList.forEach((currentArray: Uint8Array) => { 493 resultUintArray.set(currentArray, offset); 494 offset += currentArray.length; 495 }); 496 return resultArrayBuffer; 497} 498 499export function findFreeSizeAlgorithm(numbers: Array<number>, freeSize: number): Array<number> { 500 let closestSize = 0; 501 let currentSize = 0; 502 let finalIndex: Array<number> = []; 503 let currentSelectIndex: Array<number> = []; 504 505 function reBackFind(index: number): void { 506 if (index === numbers.length) { 507 const sumDifference = Math.abs(currentSize - freeSize); 508 if (currentSize <= freeSize && sumDifference < Math.abs(closestSize - freeSize)) { 509 closestSize = currentSize; 510 finalIndex = [...currentSelectIndex]; 511 } 512 return; 513 } 514 currentSize += numbers[index]; 515 currentSelectIndex.push(index); 516 reBackFind(index + 1); 517 currentSize -= numbers[index]; 518 currentSelectIndex.pop(); 519 reBackFind(index + 1); 520 } 521 522 reBackFind(0); 523 return finalIndex; 524} 525 526export function getCurrentDataTime(): string[] { 527 let current = new Date(); 528 let year = '' + current.getFullYear(); 529 let month = ('0' + (current.getMonth() + 1)).slice(-2); 530 let day = ('0' + current.getDate()).slice(-2); 531 let hours = ('0' + current.getHours()).slice(-2); 532 let minutes = ('0' + current.getMinutes()).slice(-2); 533 let seconds = ('0' + current.getSeconds()).slice(-2); 534 return [year, month, day, hours, minutes, seconds]; 535} 536