xref: /aosp_15_r20/external/pigweed/pw_web/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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