1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_web: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker--------- 4*61c4878aSAndroid Build Coastguard Workerpw_web 5*61c4878aSAndroid Build Coastguard Worker--------- 6*61c4878aSAndroid Build Coastguard WorkerPigweed provides an NPM package with modules to build web apps for Pigweed 7*61c4878aSAndroid Build Coastguard Workerdevices. 8*61c4878aSAndroid Build Coastguard Worker 9*61c4878aSAndroid Build Coastguard WorkerGetting Started 10*61c4878aSAndroid Build Coastguard Worker=============== 11*61c4878aSAndroid Build Coastguard Worker 12*61c4878aSAndroid Build Coastguard WorkerEasiest way to get started is to follow the :ref:`Sense tutorial <showcase-sense-tutorial-intro>` 13*61c4878aSAndroid Build Coastguard Workerand flash a Raspberry Pico board. 14*61c4878aSAndroid Build Coastguard Worker 15*61c4878aSAndroid Build Coastguard WorkerOnce you have a device running Pigweed, you can connect to it using just your web browser. 16*61c4878aSAndroid Build Coastguard Worker 17*61c4878aSAndroid Build Coastguard WorkerInstallation 18*61c4878aSAndroid Build Coastguard Worker------------- 19*61c4878aSAndroid Build Coastguard WorkerIf you have a bundler set up, you can install ``pigweedjs`` in your web application by: 20*61c4878aSAndroid Build Coastguard Worker 21*61c4878aSAndroid Build Coastguard Worker.. code-block:: bash 22*61c4878aSAndroid Build Coastguard Worker 23*61c4878aSAndroid Build Coastguard Worker $ npm install --save pigweedjs 24*61c4878aSAndroid Build Coastguard Worker 25*61c4878aSAndroid Build Coastguard Worker 26*61c4878aSAndroid Build Coastguard WorkerAfter installing, you can import modules from ``pigweedjs`` in this way: 27*61c4878aSAndroid Build Coastguard Worker 28*61c4878aSAndroid Build Coastguard Worker.. code-block:: javascript 29*61c4878aSAndroid Build Coastguard Worker 30*61c4878aSAndroid Build Coastguard Worker import { pw_rpc, pw_tokenizer, Device, WebSerial } from 'pigweedjs'; 31*61c4878aSAndroid Build Coastguard Worker 32*61c4878aSAndroid Build Coastguard WorkerImport Directly in HTML 33*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^ 34*61c4878aSAndroid Build Coastguard WorkerIf you don't want to set up a bundler, you can also load Pigweed directly in 35*61c4878aSAndroid Build Coastguard Workeryour HTML page by: 36*61c4878aSAndroid Build Coastguard Worker 37*61c4878aSAndroid Build Coastguard Worker.. code-block:: html 38*61c4878aSAndroid Build Coastguard Worker 39*61c4878aSAndroid Build Coastguard Worker <script src="https://unpkg.com/pigweedjs/dist/index.umd.js"></script> 40*61c4878aSAndroid Build Coastguard Worker <script> 41*61c4878aSAndroid Build Coastguard Worker const { pw_rpc, pw_hdlc, Device, WebSerial } from Pigweed; 42*61c4878aSAndroid Build Coastguard Worker </script> 43*61c4878aSAndroid Build Coastguard Worker 44*61c4878aSAndroid Build Coastguard WorkerModules 45*61c4878aSAndroid Build Coastguard Worker======= 46*61c4878aSAndroid Build Coastguard Worker.. _module-pw_web-device: 47*61c4878aSAndroid Build Coastguard Worker 48*61c4878aSAndroid Build Coastguard WorkerDevice 49*61c4878aSAndroid Build Coastguard Worker------ 50*61c4878aSAndroid Build Coastguard WorkerDevice class is a helper API to connect to a device over serial and call RPCs 51*61c4878aSAndroid Build Coastguard Workereasily. 52*61c4878aSAndroid Build Coastguard Worker 53*61c4878aSAndroid Build Coastguard WorkerTo initialize device, it needs a ``ProtoCollection`` instance. ``pigweedjs`` 54*61c4878aSAndroid Build Coastguard Workerincludes a default one which you can use to get started, you can also generate 55*61c4878aSAndroid Build Coastguard Workerone from your own ``.proto`` files using ``pw_proto_compiler``. 56*61c4878aSAndroid Build Coastguard Worker 57*61c4878aSAndroid Build Coastguard Worker``Device`` goes through all RPC methods in the provided ProtoCollection. For 58*61c4878aSAndroid Build Coastguard Workereach RPC, it reads all the fields in ``Request`` proto and generates a 59*61c4878aSAndroid Build Coastguard WorkerJavaScript function to call that RPC and also a helper method to create a request. 60*61c4878aSAndroid Build Coastguard WorkerIt then makes this function available under ``rpcs.*`` namespaced by its package name. 61*61c4878aSAndroid Build Coastguard Worker 62*61c4878aSAndroid Build Coastguard WorkerDevice has following public API: 63*61c4878aSAndroid Build Coastguard Worker 64*61c4878aSAndroid Build Coastguard Worker- ``constructor(ProtoCollection, WebSerialTransport <optional>, channel <optional>, rpcAddress <optional>)`` 65*61c4878aSAndroid Build Coastguard Worker- ``connect()`` - Shows browser's WebSerial connection dialog and let's user 66*61c4878aSAndroid Build Coastguard Worker make device selection 67*61c4878aSAndroid Build Coastguard Worker- ``rpcs.*`` - Device API enumerates all RPC services and methods present in the 68*61c4878aSAndroid Build Coastguard Worker provided proto collection and makes them available as callable functions under 69*61c4878aSAndroid Build Coastguard Worker ``rpcs``. Example: If provided proto collection includes Pigweed's Echo 70*61c4878aSAndroid Build Coastguard Worker service ie. ``pw.rpc.EchoService.Echo``, it can be triggered by calling 71*61c4878aSAndroid Build Coastguard Worker ``device.rpcs.pw.rpc.EchoService.Echo.call(request)``. The functions return 72*61c4878aSAndroid Build Coastguard Worker a ``Promise`` that resolves an array with status and response. 73*61c4878aSAndroid Build Coastguard Worker 74*61c4878aSAndroid Build Coastguard WorkerUsing Device API with Sense 75*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^ 76*61c4878aSAndroid Build Coastguard WorkerSense project uses ``pw_log_rpc``; an RPC-based logging solution. Sense 77*61c4878aSAndroid Build Coastguard Workeralso uses pw_tokenizer to tokenize strings and save device space. Below is an 78*61c4878aSAndroid Build Coastguard Workerexample that streams logs using the ``Device`` API. 79*61c4878aSAndroid Build Coastguard Worker 80*61c4878aSAndroid Build Coastguard Worker.. code-block:: html 81*61c4878aSAndroid Build Coastguard Worker 82*61c4878aSAndroid Build Coastguard Worker <h1>Hello Pigweed</h1> 83*61c4878aSAndroid Build Coastguard Worker <button onclick="connect()">Connect</button> 84*61c4878aSAndroid Build Coastguard Worker <br /><br /> 85*61c4878aSAndroid Build Coastguard Worker <code></code> 86*61c4878aSAndroid Build Coastguard Worker <script src="https://unpkg.com/pigweedjs/dist/index.umd.js"></script> 87*61c4878aSAndroid Build Coastguard Worker <script src="https://unpkg.com/pigweedjs/dist/protos/collection.umd.js"></script> 88*61c4878aSAndroid Build Coastguard Worker <script> 89*61c4878aSAndroid Build Coastguard Worker const { Device, pw_tokenizer } = Pigweed; 90*61c4878aSAndroid Build Coastguard Worker const { ProtoCollection } = PigweedProtoCollection; 91*61c4878aSAndroid Build Coastguard Worker const tokenDBCsv = `...` // Load token database here 92*61c4878aSAndroid Build Coastguard Worker 93*61c4878aSAndroid Build Coastguard Worker const device = new Device(new ProtoCollection()); 94*61c4878aSAndroid Build Coastguard Worker const detokenizer = new pw_tokenizer.Detokenizer(tokenDBCsv); 95*61c4878aSAndroid Build Coastguard Worker 96*61c4878aSAndroid Build Coastguard Worker async function connect(){ 97*61c4878aSAndroid Build Coastguard Worker await device.connect(); 98*61c4878aSAndroid Build Coastguard Worker const req = device.rpcs.pw.log.Logs.Listen.createRequest() 99*61c4878aSAndroid Build Coastguard Worker const logs = device.rpcs.pw.log.Logs.Listen.call(req); 100*61c4878aSAndroid Build Coastguard Worker for await (const msg of logs){ 101*61c4878aSAndroid Build Coastguard Worker msg.getEntriesList().forEach((entry) => { 102*61c4878aSAndroid Build Coastguard Worker const frame = entry.getMessage(); 103*61c4878aSAndroid Build Coastguard Worker const detokenized = detokenizer.detokenizeUint8Array(frame); 104*61c4878aSAndroid Build Coastguard Worker document.querySelector('code').innerHTML += detokenized + "<br/>"; 105*61c4878aSAndroid Build Coastguard Worker }); 106*61c4878aSAndroid Build Coastguard Worker } 107*61c4878aSAndroid Build Coastguard Worker console.log("Log stream ended with status", logs.call.status); 108*61c4878aSAndroid Build Coastguard Worker } 109*61c4878aSAndroid Build Coastguard Worker </script> 110*61c4878aSAndroid Build Coastguard Worker 111*61c4878aSAndroid Build Coastguard WorkerThe above example requires a token database in CSV format. You can generate one 112*61c4878aSAndroid Build Coastguard Workerfrom the Sense's ``.elf`` file by running: 113*61c4878aSAndroid Build Coastguard Worker 114*61c4878aSAndroid Build Coastguard Worker.. code-block:: bash 115*61c4878aSAndroid Build Coastguard Worker 116*61c4878aSAndroid Build Coastguard Worker $ pw_tokenizer/py/pw_tokenizer/database.py create \ 117*61c4878aSAndroid Build Coastguard Worker --database db.csv bazel-bin/apps/blinky/rp2040_blinky.elf 118*61c4878aSAndroid Build Coastguard Worker 119*61c4878aSAndroid Build Coastguard WorkerYou can then load this CSV in JavaScript using ``fetch()`` or by just copying 120*61c4878aSAndroid Build Coastguard Workerthe contents into the ``tokenDBCsv`` variable in the above example. 121*61c4878aSAndroid Build Coastguard Worker 122*61c4878aSAndroid Build Coastguard WorkerWebSerialTransport 123*61c4878aSAndroid Build Coastguard Worker------------------ 124*61c4878aSAndroid Build Coastguard WorkerTo help with connecting to WebSerial and listening for serial data, a helper 125*61c4878aSAndroid Build Coastguard Workerclass is also included under ``WebSerial.WebSerialTransport``. Here is an 126*61c4878aSAndroid Build Coastguard Workerexample usage: 127*61c4878aSAndroid Build Coastguard Worker 128*61c4878aSAndroid Build Coastguard Worker.. code-block:: javascript 129*61c4878aSAndroid Build Coastguard Worker 130*61c4878aSAndroid Build Coastguard Worker import { WebSerial, pw_hdlc } from 'pigweedjs'; 131*61c4878aSAndroid Build Coastguard Worker 132*61c4878aSAndroid Build Coastguard Worker const transport = new WebSerial.WebSerialTransport(); 133*61c4878aSAndroid Build Coastguard Worker const decoder = new pw_hdlc.Decoder(); 134*61c4878aSAndroid Build Coastguard Worker 135*61c4878aSAndroid Build Coastguard Worker // Present device selection prompt to user 136*61c4878aSAndroid Build Coastguard Worker await transport.connect(); 137*61c4878aSAndroid Build Coastguard Worker 138*61c4878aSAndroid Build Coastguard Worker // Or connect to an existing `SerialPort` 139*61c4878aSAndroid Build Coastguard Worker // await transport.connectPort(port); 140*61c4878aSAndroid Build Coastguard Worker 141*61c4878aSAndroid Build Coastguard Worker // Listen and decode HDLC frames 142*61c4878aSAndroid Build Coastguard Worker transport.chunks.subscribe((item) => { 143*61c4878aSAndroid Build Coastguard Worker const decoded = decoder.process(item); 144*61c4878aSAndroid Build Coastguard Worker for (const frame of decoded) { 145*61c4878aSAndroid Build Coastguard Worker if (frame.address === 1) { 146*61c4878aSAndroid Build Coastguard Worker const decodedLine = new TextDecoder().decode(frame.data); 147*61c4878aSAndroid Build Coastguard Worker console.log(decodedLine); 148*61c4878aSAndroid Build Coastguard Worker } 149*61c4878aSAndroid Build Coastguard Worker } 150*61c4878aSAndroid Build Coastguard Worker }); 151*61c4878aSAndroid Build Coastguard Worker 152*61c4878aSAndroid Build Coastguard Worker // Later, close all streams and close the port. 153*61c4878aSAndroid Build Coastguard Worker transport.disconnect(); 154*61c4878aSAndroid Build Coastguard Worker 155*61c4878aSAndroid Build Coastguard WorkerIndividual Modules 156*61c4878aSAndroid Build Coastguard Worker================== 157*61c4878aSAndroid Build Coastguard WorkerFollowing Pigweed modules are included in the NPM package: 158*61c4878aSAndroid Build Coastguard Worker 159*61c4878aSAndroid Build Coastguard Worker- `pw_hdlc <https://pigweed.dev/pw_hdlc/#typescript>`_ 160*61c4878aSAndroid Build Coastguard Worker- `pw_rpc <https://pigweed.dev/pw_rpc/ts/>`_ 161*61c4878aSAndroid Build Coastguard Worker- `pw_tokenizer <https://pigweed.dev/pw_tokenizer/#typescript>`_ 162*61c4878aSAndroid Build Coastguard Worker- `pw_transfer <https://pigweed.dev/pw_transfer/#typescript>`_ 163*61c4878aSAndroid Build Coastguard Worker 164*61c4878aSAndroid Build Coastguard WorkerLog Viewer Component 165*61c4878aSAndroid Build Coastguard Worker==================== 166*61c4878aSAndroid Build Coastguard WorkerThe NPM package also includes a log viewer component that can be embedded in any 167*61c4878aSAndroid Build Coastguard Workerwebapp. The component works with Pigweed's RPC stack out-of-the-box but also 168*61c4878aSAndroid Build Coastguard Workersupports defining your own log source. See :ref:`module-pw_web-log-viewer` for 169*61c4878aSAndroid Build Coastguard Workercomponent interaction details. 170*61c4878aSAndroid Build Coastguard Worker 171*61c4878aSAndroid Build Coastguard WorkerThe component is composed of the component itself and a log source. Here is a 172*61c4878aSAndroid Build Coastguard Workersimple example app that uses a mock log source: 173*61c4878aSAndroid Build Coastguard Worker 174*61c4878aSAndroid Build Coastguard Worker.. code-block:: html 175*61c4878aSAndroid Build Coastguard Worker 176*61c4878aSAndroid Build Coastguard Worker <div id="log-viewer-container"></div> 177*61c4878aSAndroid Build Coastguard Worker <script src="https://unpkg.com/pigweedjs/dist/logging.umd.js"></script> 178*61c4878aSAndroid Build Coastguard Worker <script> 179*61c4878aSAndroid Build Coastguard Worker 180*61c4878aSAndroid Build Coastguard Worker const { createLogViewer, MockLogSource } = PigweedLogging; 181*61c4878aSAndroid Build Coastguard Worker const logSource = new MockLogSource(); 182*61c4878aSAndroid Build Coastguard Worker const containerEl = document.querySelector( 183*61c4878aSAndroid Build Coastguard Worker '#log-viewer-container' 184*61c4878aSAndroid Build Coastguard Worker ); 185*61c4878aSAndroid Build Coastguard Worker 186*61c4878aSAndroid Build Coastguard Worker let unsubscribe = createLogViewer(logSource, containerEl); 187*61c4878aSAndroid Build Coastguard Worker logSource.start(); // Start producing mock logs 188*61c4878aSAndroid Build Coastguard Worker 189*61c4878aSAndroid Build Coastguard Worker </script> 190*61c4878aSAndroid Build Coastguard Worker 191*61c4878aSAndroid Build Coastguard WorkerThe code above will render a working log viewer that just streams mock 192*61c4878aSAndroid Build Coastguard Workerlog entries. 193*61c4878aSAndroid Build Coastguard Worker 194*61c4878aSAndroid Build Coastguard WorkerIt also comes with an RPC log source with support for detokenization. Here is an 195*61c4878aSAndroid Build Coastguard Workerexample app using that: 196*61c4878aSAndroid Build Coastguard Worker 197*61c4878aSAndroid Build Coastguard Worker.. code-block:: html 198*61c4878aSAndroid Build Coastguard Worker 199*61c4878aSAndroid Build Coastguard Worker <div id="log-viewer-container"></div> 200*61c4878aSAndroid Build Coastguard Worker <script src="https://unpkg.com/pigweedjs/dist/index.umd.js"></script> 201*61c4878aSAndroid Build Coastguard Worker <script src="https://unpkg.com/pigweedjs/dist/protos/collection.umd.js"></script> 202*61c4878aSAndroid Build Coastguard Worker <script src="https://unpkg.com/pigweedjs/dist/logging.umd.js"></script> 203*61c4878aSAndroid Build Coastguard Worker <script> 204*61c4878aSAndroid Build Coastguard Worker 205*61c4878aSAndroid Build Coastguard Worker const { Device, pw_tokenizer } = Pigweed; 206*61c4878aSAndroid Build Coastguard Worker const { ProtoCollection } = PigweedProtoCollection; 207*61c4878aSAndroid Build Coastguard Worker const { createLogViewer, PigweedRPCLogSource } = PigweedLogging; 208*61c4878aSAndroid Build Coastguard Worker 209*61c4878aSAndroid Build Coastguard Worker const device = new Device(new ProtoCollection()); 210*61c4878aSAndroid Build Coastguard Worker const logSource = new PigweedRPCLogSource(device, "CSV TOKEN DB HERE"); 211*61c4878aSAndroid Build Coastguard Worker const containerEl = document.querySelector( 212*61c4878aSAndroid Build Coastguard Worker '#log-viewer-container' 213*61c4878aSAndroid Build Coastguard Worker ); 214*61c4878aSAndroid Build Coastguard Worker 215*61c4878aSAndroid Build Coastguard Worker let unsubscribe = createLogViewer(logSource, containerEl); 216*61c4878aSAndroid Build Coastguard Worker 217*61c4878aSAndroid Build Coastguard Worker </script> 218*61c4878aSAndroid Build Coastguard Worker 219*61c4878aSAndroid Build Coastguard WorkerCustom Log Source 220*61c4878aSAndroid Build Coastguard Worker----------------- 221*61c4878aSAndroid Build Coastguard WorkerYou can define a custom log source that works with the log viewer component by 222*61c4878aSAndroid Build Coastguard Workerjust extending the abstract `LogSource` class and emitting the `logEntry` events 223*61c4878aSAndroid Build Coastguard Workerlike this: 224*61c4878aSAndroid Build Coastguard Worker 225*61c4878aSAndroid Build Coastguard Worker.. code-block:: typescript 226*61c4878aSAndroid Build Coastguard Worker 227*61c4878aSAndroid Build Coastguard Worker import { LogSource, LogEntry, Level } from 'pigweedjs/logging'; 228*61c4878aSAndroid Build Coastguard Worker 229*61c4878aSAndroid Build Coastguard Worker export class MockLogSource extends LogSource { 230*61c4878aSAndroid Build Coastguard Worker constructor(){ 231*61c4878aSAndroid Build Coastguard Worker super(); 232*61c4878aSAndroid Build Coastguard Worker // Do any initializations here 233*61c4878aSAndroid Build Coastguard Worker // ... 234*61c4878aSAndroid Build Coastguard Worker // Then emit logs 235*61c4878aSAndroid Build Coastguard Worker const log1: LogEntry = { 236*61c4878aSAndroid Build Coastguard Worker 237*61c4878aSAndroid Build Coastguard Worker } 238*61c4878aSAndroid Build Coastguard Worker this.publishLogEntry({ 239*61c4878aSAndroid Build Coastguard Worker level: Level.INFO, 240*61c4878aSAndroid Build Coastguard Worker timestamp: new Date(), 241*61c4878aSAndroid Build Coastguard Worker fields: [ 242*61c4878aSAndroid Build Coastguard Worker { key: 'level', value: level } 243*61c4878aSAndroid Build Coastguard Worker { key: 'timestamp', value: new Date().toISOString() }, 244*61c4878aSAndroid Build Coastguard Worker { key: 'source', value: "LEFT SHOE" }, 245*61c4878aSAndroid Build Coastguard Worker { key: 'message', value: "Running mode activated." } 246*61c4878aSAndroid Build Coastguard Worker ] 247*61c4878aSAndroid Build Coastguard Worker }); 248*61c4878aSAndroid Build Coastguard Worker } 249*61c4878aSAndroid Build Coastguard Worker } 250*61c4878aSAndroid Build Coastguard Worker 251*61c4878aSAndroid Build Coastguard WorkerAfter this, you just need to pass your custom log source object 252*61c4878aSAndroid Build Coastguard Workerto `createLogViewer()`. See implementation of 253*61c4878aSAndroid Build Coastguard Worker`PigweedRPCLogSource <https://cs.opensource.google/pigweed/pigweed/+/main:ts/logging_source_rpc.ts>`_ 254*61c4878aSAndroid Build Coastguard Workerfor reference. 255*61c4878aSAndroid Build Coastguard Worker 256*61c4878aSAndroid Build Coastguard WorkerColumn Order 257*61c4878aSAndroid Build Coastguard Worker------------ 258*61c4878aSAndroid Build Coastguard WorkerColumn Order can be defined on initialization with the optional ``columnOrder`` parameter. 259*61c4878aSAndroid Build Coastguard WorkerOnly fields that exist in the Log Source will render as columns in the Log Viewer. 260*61c4878aSAndroid Build Coastguard Worker 261*61c4878aSAndroid Build Coastguard Worker.. code-block:: typescript 262*61c4878aSAndroid Build Coastguard Worker 263*61c4878aSAndroid Build Coastguard Worker createLogViewer(logSource, root, { columnOrder }) 264*61c4878aSAndroid Build Coastguard Worker 265*61c4878aSAndroid Build Coastguard Worker``columnOrder`` accepts an ``string[]`` and defaults to ``[log_source, time, timestamp]`` 266*61c4878aSAndroid Build Coastguard Worker 267*61c4878aSAndroid Build Coastguard Worker.. code-block:: typescript 268*61c4878aSAndroid Build Coastguard Worker 269*61c4878aSAndroid Build Coastguard Worker createLogViewer( 270*61c4878aSAndroid Build Coastguard Worker logSource, 271*61c4878aSAndroid Build Coastguard Worker root, 272*61c4878aSAndroid Build Coastguard Worker { columnOrder: ['log_source', 'time', 'timestamp'] } 273*61c4878aSAndroid Build Coastguard Worker 274*61c4878aSAndroid Build Coastguard Worker ) 275*61c4878aSAndroid Build Coastguard Worker 276*61c4878aSAndroid Build Coastguard WorkerNote, columns will always start with ``level`` and end with ``message``, these fields do not need to be defined. 277*61c4878aSAndroid Build Coastguard WorkerColumns are ordered in the following format: 278*61c4878aSAndroid Build Coastguard Worker 279*61c4878aSAndroid Build Coastguard Worker1. ``level`` 280*61c4878aSAndroid Build Coastguard Worker2. ``columnOrder`` 281*61c4878aSAndroid Build Coastguard Worker3. Fields that exist in Log Source but not listed will be added here. 282*61c4878aSAndroid Build Coastguard Worker4. ``message`` 283*61c4878aSAndroid Build Coastguard Worker 284*61c4878aSAndroid Build Coastguard Worker 285*61c4878aSAndroid Build Coastguard WorkerAccessing and Modifying Log Views 286*61c4878aSAndroid Build Coastguard Worker--------------------------------- 287*61c4878aSAndroid Build Coastguard Worker 288*61c4878aSAndroid Build Coastguard WorkerIt can be challenging to access and manage log views directly through JavaScript or HTML due to the 289*61c4878aSAndroid Build Coastguard Workershadow DOM boundaries generated by custom elements. To facilitate this, the ``Log Viewer`` 290*61c4878aSAndroid Build Coastguard Workercomponent has a public property, ``logViews``, which returns an array containing all child log 291*61c4878aSAndroid Build Coastguard Workerviews. Here is an example that modifies the ``viewTitle`` and ``searchText`` properties of two log 292*61c4878aSAndroid Build Coastguard Workerviews: 293*61c4878aSAndroid Build Coastguard Worker 294*61c4878aSAndroid Build Coastguard Worker.. code-block:: typescript 295*61c4878aSAndroid Build Coastguard Worker 296*61c4878aSAndroid Build Coastguard Worker const logViewer = containerEl.querySelector('log-viewer'); 297*61c4878aSAndroid Build Coastguard Worker const views = logViewer?.logViews; 298*61c4878aSAndroid Build Coastguard Worker 299*61c4878aSAndroid Build Coastguard Worker if (views) { 300*61c4878aSAndroid Build Coastguard Worker views[0].viewTitle = 'Device A Logs'; 301*61c4878aSAndroid Build Coastguard Worker views[0].searchText = 'device:A'; 302*61c4878aSAndroid Build Coastguard Worker 303*61c4878aSAndroid Build Coastguard Worker views[1].viewTitle = 'Device B Logs'; 304*61c4878aSAndroid Build Coastguard Worker views[1].searchText = 'device:B'; 305*61c4878aSAndroid Build Coastguard Worker } 306*61c4878aSAndroid Build Coastguard Worker 307*61c4878aSAndroid Build Coastguard WorkerAlternatively, you can define a state object containing nodes with their respective properties and 308*61c4878aSAndroid Build Coastguard Workerpass this state object to the ``Log Viewer`` during initialization. Here is how you can achieve 309*61c4878aSAndroid Build Coastguard Workerthat: 310*61c4878aSAndroid Build Coastguard Worker 311*61c4878aSAndroid Build Coastguard Worker.. code-block:: typescript 312*61c4878aSAndroid Build Coastguard Worker 313*61c4878aSAndroid Build Coastguard Worker const childNodeA: ViewNode = new ViewNode({ 314*61c4878aSAndroid Build Coastguard Worker type: NodeType.View, 315*61c4878aSAndroid Build Coastguard Worker viewTitle: 'Device A Logs', 316*61c4878aSAndroid Build Coastguard Worker searchText: 'device:A' 317*61c4878aSAndroid Build Coastguard Worker }); 318*61c4878aSAndroid Build Coastguard Worker 319*61c4878aSAndroid Build Coastguard Worker const childNodeB: ViewNode = new ViewNode({ 320*61c4878aSAndroid Build Coastguard Worker type: NodeType.View, 321*61c4878aSAndroid Build Coastguard Worker viewTitle: 'Device B Logs', 322*61c4878aSAndroid Build Coastguard Worker searchText: 'device:B' 323*61c4878aSAndroid Build Coastguard Worker }); 324*61c4878aSAndroid Build Coastguard Worker 325*61c4878aSAndroid Build Coastguard Worker const rootNode: ViewNode = new ViewNode({ 326*61c4878aSAndroid Build Coastguard Worker type: NodeType.Split, 327*61c4878aSAndroid Build Coastguard Worker orientation: Orientation.Vertical, 328*61c4878aSAndroid Build Coastguard Worker children: [childNodeA, childNodeB] 329*61c4878aSAndroid Build Coastguard Worker }); 330*61c4878aSAndroid Build Coastguard Worker 331*61c4878aSAndroid Build Coastguard Worker const options = { state: { rootNode: rootNode } }; 332*61c4878aSAndroid Build Coastguard Worker createLogViewer(logSources, containerEl, options); 333*61c4878aSAndroid Build Coastguard Worker 334*61c4878aSAndroid Build Coastguard WorkerNote that the relevant types and enums should be imported from 335*61c4878aSAndroid Build Coastguard Worker``log-viewer/src/shared/view-node.ts``. 336*61c4878aSAndroid Build Coastguard Worker 337*61c4878aSAndroid Build Coastguard WorkerColor Scheme 338*61c4878aSAndroid Build Coastguard Worker------------ 339*61c4878aSAndroid Build Coastguard WorkerThe log viewer web component provides the ability to set the color scheme 340*61c4878aSAndroid Build Coastguard Workermanually, overriding any default or system preferences. 341*61c4878aSAndroid Build Coastguard Worker 342*61c4878aSAndroid Build Coastguard WorkerTo set the color scheme, first obtain a reference to the ``log-viewer`` element 343*61c4878aSAndroid Build Coastguard Workerin the DOM. A common way to do this is by using ``querySelector()``: 344*61c4878aSAndroid Build Coastguard Worker 345*61c4878aSAndroid Build Coastguard Worker.. code-block:: javascript 346*61c4878aSAndroid Build Coastguard Worker 347*61c4878aSAndroid Build Coastguard Worker const logViewer = document.querySelector('log-viewer'); 348*61c4878aSAndroid Build Coastguard Worker 349*61c4878aSAndroid Build Coastguard WorkerYou can then set the color scheme dynamically by updating the component's 350*61c4878aSAndroid Build Coastguard Worker`colorScheme` property or by setting a value for the `colorscheme` HTML attribute. 351*61c4878aSAndroid Build Coastguard Worker 352*61c4878aSAndroid Build Coastguard Worker.. code-block:: javascript 353*61c4878aSAndroid Build Coastguard Worker 354*61c4878aSAndroid Build Coastguard Worker logViewer.colorScheme = 'dark'; 355*61c4878aSAndroid Build Coastguard Worker 356*61c4878aSAndroid Build Coastguard Worker.. code-block:: javascript 357*61c4878aSAndroid Build Coastguard Worker 358*61c4878aSAndroid Build Coastguard Worker logViewer.setAttribute('colorscheme', 'dark'); 359*61c4878aSAndroid Build Coastguard Worker 360*61c4878aSAndroid Build Coastguard WorkerThe color scheme can be set to ``'dark'``, ``'light'``, or the default ``'auto'`` 361*61c4878aSAndroid Build Coastguard Workerwhich allows the component to adapt to the preferences in the operating system 362*61c4878aSAndroid Build Coastguard Workersettings. 363*61c4878aSAndroid Build Coastguard Worker 364*61c4878aSAndroid Build Coastguard WorkerMaterial Icon Font (Subsetting) 365*61c4878aSAndroid Build Coastguard Worker------------------------------- 366*61c4878aSAndroid Build Coastguard Worker.. inclusive-language: disable 367*61c4878aSAndroid Build Coastguard Worker 368*61c4878aSAndroid Build Coastguard WorkerThe Log Viewer uses a subset of the Material Symbols Rounded icon font fetched via the `Google Fonts API <https://developers.google.com/fonts/docs/css2#forming_api_urls>`_. However, we also provide a subset of this font for offline usage at `GitHub <https://github.com/google/material-design-icons/blob/master/variablefont/MaterialSymbolsRounded%5BFILL%2CGRAD%2Copsz%2Cwght%5D.woff2>`_ 369*61c4878aSAndroid Build Coastguard Workerwith codepoints listed in the `codepoints <https://github.com/google/material-design-icons/blob/master/variablefont/MaterialSymbolsRounded%5BFILL%2CGRAD%2Copsz%2Cwght%5D.codepoints>`_ file. 370*61c4878aSAndroid Build Coastguard Worker 371*61c4878aSAndroid Build Coastguard Worker(It's easiest to look up the codepoints at `fonts.google.com <https://fonts.google.com/icons?selected=Material+Symbols+Rounded>`_ e.g. see 372*61c4878aSAndroid Build Coastguard Workerthe sidebar shows the Codepoint for `"home" <https://fonts.google.com/icons?selected=Material+Symbols+Rounded:home:FILL@0;wght@0;GRAD@0;opsz@NaN>`_ is e88a). 373*61c4878aSAndroid Build Coastguard Worker 374*61c4878aSAndroid Build Coastguard WorkerThe following icons with codepoints are curently used: 375*61c4878aSAndroid Build Coastguard Worker 376*61c4878aSAndroid Build Coastguard Worker* delete_sweep e16c 377*61c4878aSAndroid Build Coastguard Worker* error e000 378*61c4878aSAndroid Build Coastguard Worker* warning f083 379*61c4878aSAndroid Build Coastguard Worker* cancel e5c9 380*61c4878aSAndroid Build Coastguard Worker* bug_report e868 381*61c4878aSAndroid Build Coastguard Worker* info e88e 382*61c4878aSAndroid Build Coastguard Worker* view_column e8ec 383*61c4878aSAndroid Build Coastguard Worker* brightness_alert f5cf 384*61c4878aSAndroid Build Coastguard Worker* wrap_text e25b 385*61c4878aSAndroid Build Coastguard Worker* more_vert e5d4 386*61c4878aSAndroid Build Coastguard Worker* play_arrow e037 387*61c4878aSAndroid Build Coastguard Worker* stop e047 388*61c4878aSAndroid Build Coastguard Worker 389*61c4878aSAndroid Build Coastguard WorkerTo save load time and bandwidth, we provide a pre-made subset of the font with 390*61c4878aSAndroid Build Coastguard Workerjust the codepoints we need, which reduces the font size from 3.74MB to 12KB. 391*61c4878aSAndroid Build Coastguard Worker 392*61c4878aSAndroid Build Coastguard WorkerWe use fonttools (https://github.com/fonttools/fonttools) to create the subset. 393*61c4878aSAndroid Build Coastguard WorkerTo create your own subset, find the codepoints you want to add and: 394*61c4878aSAndroid Build Coastguard Worker 395*61c4878aSAndroid Build Coastguard Worker1. Start a python virtualenv and install fonttools 396*61c4878aSAndroid Build Coastguard Worker 397*61c4878aSAndroid Build Coastguard Worker.. code-block:: bash 398*61c4878aSAndroid Build Coastguard Worker 399*61c4878aSAndroid Build Coastguard Worker virtualenv env 400*61c4878aSAndroid Build Coastguard Worker source env/bin/activate 401*61c4878aSAndroid Build Coastguard Worker pip install fonttools brotli 402*61c4878aSAndroid Build Coastguard Worker 403*61c4878aSAndroid Build Coastguard Worker2. Download the the raw `MaterialSybmolsRounded woff2 file <https://github.com/google/material-design-icons/tree/master/variablefont>`_ 404*61c4878aSAndroid Build Coastguard Worker 405*61c4878aSAndroid Build Coastguard Worker.. code-block:: bash 406*61c4878aSAndroid Build Coastguard Worker 407*61c4878aSAndroid Build Coastguard Worker # line below for example, the url is not stable: e.g. 408*61c4878aSAndroid Build Coastguard Worker curl -L -o MaterialSymbolsRounded.woff2 \ 409*61c4878aSAndroid Build Coastguard Worker "https://github.com/google/material-design-icons/raw/master/variablefont/MaterialSymbolsRounded%5BFILL,GRAD,opsz,wght%5D.woff2" 410*61c4878aSAndroid Build Coastguard Worker 411*61c4878aSAndroid Build Coastguard Worker3. Run fonttools, passing in the unicode codepoints of the necessary glyphs. 412*61c4878aSAndroid Build Coastguard Worker (The points for letters a-z, numbers 0-9 and underscore character are 413*61c4878aSAndroid Build Coastguard Worker necessary for creating ligatures) 414*61c4878aSAndroid Build Coastguard Worker 415*61c4878aSAndroid Build Coastguard Worker.. warning:: Ensure there are no spaces in the list of codepoints. 416*61c4878aSAndroid Build Coastguard Worker.. code-block:: bash 417*61c4878aSAndroid Build Coastguard Worker 418*61c4878aSAndroid Build Coastguard Worker fonttools subset MaterialSymbolsRounded.woff2 \ 419*61c4878aSAndroid Build Coastguard Worker --unicodes=5f-7a,30-39,e16c,e000,e002,e8b2,e5c9,e868,,e88e,e8ec,f083,f5cf,e25b,e5d4,e037,e047 \ 420*61c4878aSAndroid Build Coastguard Worker --no-layout-closure \ 421*61c4878aSAndroid Build Coastguard Worker --output-file=material_symbols_rounded_subset.woff2 \ 422*61c4878aSAndroid Build Coastguard Worker --flavor=woff2 423*61c4878aSAndroid Build Coastguard Worker 424*61c4878aSAndroid Build Coastguard Worker4. Update ``material_symbols_rounded_subset.woff2`` in ``log_viewer/src/assets`` 425*61c4878aSAndroid Build Coastguard Worker with the new subset 426*61c4878aSAndroid Build Coastguard Worker 427*61c4878aSAndroid Build Coastguard Worker.. inclusive-language: enable 428*61c4878aSAndroid Build Coastguard Worker 429*61c4878aSAndroid Build Coastguard WorkerShoelace 430*61c4878aSAndroid Build Coastguard Worker-------- 431*61c4878aSAndroid Build Coastguard WorkerWe currently use Split Panel from the `Shoelace <https://github.com/shoelace-style/shoelace>`_ 432*61c4878aSAndroid Build Coastguard Workerlibrary to enable resizable split views within the log viewer. 433*61c4878aSAndroid Build Coastguard Worker 434*61c4878aSAndroid Build Coastguard WorkerTo provide flexibility in different environments, we've introduced a property ``useShoelaceFeatures`` 435*61c4878aSAndroid Build Coastguard Workerin the ``LogViewer`` component. This flag allows developers to enable or disable the import and 436*61c4878aSAndroid Build Coastguard Workerusage of Shoelace components based on their needs. 437*61c4878aSAndroid Build Coastguard Worker 438*61c4878aSAndroid Build Coastguard WorkerBy default, the ``useShoelaceFeatures`` flag is set to ``true``, meaning Shoelace components will 439*61c4878aSAndroid Build Coastguard Workerbe used and resizable split views are made available. To disable Shoelace components, set this 440*61c4878aSAndroid Build Coastguard Workerproperty to ``false`` as shown below: 441*61c4878aSAndroid Build Coastguard Worker 442*61c4878aSAndroid Build Coastguard Worker.. code-block:: javascript 443*61c4878aSAndroid Build Coastguard Worker 444*61c4878aSAndroid Build Coastguard Worker const logViewer = document.querySelector('log-viewer'); 445*61c4878aSAndroid Build Coastguard Worker logViewer.useShoelaceFeatures = false; 446*61c4878aSAndroid Build Coastguard Worker 447*61c4878aSAndroid Build Coastguard WorkerWhen ``useShoelaceFeatures`` is set to ``false``, the <sl-split-panel> component from Shoelace will 448*61c4878aSAndroid Build Coastguard Workernot be imported or used within the log viewer. 449*61c4878aSAndroid Build Coastguard Worker 450*61c4878aSAndroid Build Coastguard WorkerGuides 451*61c4878aSAndroid Build Coastguard Worker====== 452*61c4878aSAndroid Build Coastguard Worker 453*61c4878aSAndroid Build Coastguard Worker.. toctree:: 454*61c4878aSAndroid Build Coastguard Worker :maxdepth: 1 455*61c4878aSAndroid Build Coastguard Worker 456*61c4878aSAndroid Build Coastguard Worker testing 457*61c4878aSAndroid Build Coastguard Worker log_viewer 458*61c4878aSAndroid Build Coastguard Worker repl 459