Deployed e560baa2d to master with MkDocs 1.1.2 and mike 1.0.0

This commit is contained in:
GitHub Action committed 2021-04-19 15:53:35 +00:00
1 parent 9d9348a4ff
commit 8dd3c37633
266 files changed
+7875 -4052

No files matched your search

@@ -603,6 +603,18 @@
</li>
<li class="md-nav__item">
<a href="../protocol-handlers/" class="md-nav__link">
Protocol Handlers
</a>
</li>
</ul>
</nav>
</li>
@@ -603,6 +603,18 @@
</li>
<li class="md-nav__item">
<a href="../protocol-handlers/" class="md-nav__link">
Protocol Handlers
</a>
</li>
</ul>
</nav>
</li>
+20 -4
View File
@@ -666,6 +666,18 @@
</li>
<li class="md-nav__item">
<a href="../protocol-handlers/" class="md-nav__link">
Protocol Handlers
</a>
</li>
</ul>
</nav>
</li>
@@ -935,14 +947,16 @@
<span class="c1"># ? Which package manager to use? yarn</span>
<span class="c1"># ? symlink created extension folder to ~/.k8slens/extensions (mac/linux) or :Users\&lt;user&gt;\.k8slens\extensions (windows)? Yes</span>
</code></pre></div>
<p>Next, you'll need to have webpack watch the <code>my-first-lens-ext</code> folder. Start webpack by entering:</p>
<p>Next, you'll need to have webpack watch the <code>my-first-lens-ext</code> folder.
Start webpack by entering:</p>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span> my-first-lens-ext
npm start <span class="c1"># start the webpack server in watch mode</span>
</code></pre></div>
<p>Open Lens and you will see a <strong>Hello World</strong> item in the left-side menu under <strong>Custom Resources</strong>:</p>
<p><img alt="Hello World" src="../images/hello-world.png" /></p>
<h2 id="developing-the-extension">Developing the Extension<a class="headerlink" href="#developing-the-extension" title="Permanent link">#</a></h2>
<p>Next, you'll try changing the way the new menu item appears in the UI. You'll change it from "Hello World" to "Hello Lens".</p>
<p>Next, you'll try changing the way the new menu item appears in the UI.
You'll change it from "Hello World" to "Hello Lens".</p>
<p>Open <code>my-first-lens-ext/renderer.tsx</code> and change the value of <code>title</code> from <code>"Hello World"</code> to <code>"Hello Lens"</code>:</p>
<div class="highlight"><pre><span></span><code><span class="nx">clusterPageMenus</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">{</span>
@@ -954,13 +968,15 @@ npm start <span class="c1"># start the webpack server in watch mode</span>
<span class="p">}</span>
<span class="p">]</span>
</code></pre></div>
<p>Reload Lens and you will see that the menu item text has changed to "Hello Lens." To reload Lens, enter <code>CMD+R</code> on Mac and <code>Ctrl+R</code> on Windows/Linux.</p>
<p>Reload Lens and you will see that the menu item text has changed to "Hello Lens".
To reload Lens, enter <code>CMD+R</code> on Mac and <code>Ctrl+R</code> on Windows/Linux.</p>
<p><img alt="Hello World" src="../images/hello-lens.png" /></p>
<h2 id="debugging-the-extension">Debugging the Extension<a class="headerlink" href="#debugging-the-extension" title="Permanent link">#</a></h2>
<p>To debug your extension, please see our instructions on <a href="../../testing-and-publishing/testing/">Testing Extensions</a>.</p>
<h2 id="next-steps">Next Steps<a class="headerlink" href="#next-steps" title="Permanent link">#</a></h2>
<p>To dive deeper, consider looking at <a href="../../capabilities/common-capabilities/">Common Capabilities</a>, <a href="../../capabilities/styling/">Styling</a>, or <a href="../anatomy/">Extension Anatomy</a>.</p>
<p>If you find problems with the Lens Extension Generator, or have feature requests, you are welcome to raise an <a href="https://github.com/lensapp/generator-lens-ext/issues">issue</a>. You can find the Lens contribution guidelines <a href="../../../contributing/">here</a>.</p>
<p>If you find problems with the Lens Extension Generator, or have feature requests, you are welcome to raise an <a href="https://github.com/lensapp/generator-lens-ext/issues">issue</a>.
You can find the Lens contribution guidelines <a href="../../../contributing/">here</a>.</p>
<p>The Generator source code is hosted at <a href="https://github.com/lensapp/generator-lens-ext">Github</a>.</p>
+15 -1
View File
@@ -652,6 +652,18 @@
</li>
<li class="md-nav__item">
<a href="protocol-handlers/" class="md-nav__link">
Protocol Handlers
</a>
</li>
</ul>
</nav>
</li>
@@ -891,7 +903,9 @@
<h1 id="extension-guides">Extension Guides<a class="headerlink" href="#extension-guides" title="Permanent link">#</a></h1>
<p>This section explains how to use specific Lens Extension APIs. It includes detailed guides and code samples. For introductory information about the Lens Extension API, please see <a href="../get-started/your-first-extension/">Your First Extension</a>.</p>
<p>This section explains how to use specific Lens Extension APIs.
It includes detailed guides and code samples.
For introductory information about the Lens Extension API, please see <a href="../get-started/your-first-extension/">Your First Extension</a>.</p>
<p>Each guide or code sample includes the following:</p>
<ul>
<li>Clearly commented source code.</li>
@@ -603,6 +603,18 @@
</li>
<li class="md-nav__item">
<a href="../protocol-handlers/" class="md-nav__link">
Protocol Handlers
</a>
</li>
</ul>
</nav>
</li>
@@ -876,20 +888,25 @@
<h1 id="kubeobjectlistlayout-sample">KubeObjectListLayout Sample<a class="headerlink" href="#kubeobjectlistlayout-sample" title="Permanent link">#</a></h1>
<p>In this guide we will learn how to list Kubernetes CRD objects on the cluster dashboard. You can see the complete source code for this guide <a href="https://github.com/lensapp/lens-extension-samples/tree/master/custom-resource-page">here</a>.</p>
<p>In this guide we will learn how to list Kubernetes CRD objects on the cluster dashboard.
You can see the complete source code for this guide <a href="https://github.com/lensapp/lens-extension-samples/tree/master/custom-resource-page">here</a>.</p>
<p><img alt="" src="../images/certificates-crd-list.png" /></p>
<p>Next, we will go the implementation through in steps. To achieve our goal, we need to:</p>
<p>Next, we will go the implementation through in steps.
To achieve our goal, we need to:</p>
<ol>
<li><a href="#register-objects-for-clustepages-and-clusterpagemenus">Register ClustePage and ClusterPageMenu objects</a></li>
<li><a href="#register-objects-for-clustepages-and-clusterpagemenus">Register ClusterPage and ClusterPageMenu objects</a></li>
<li><a href="#list-certificate-objects-on-the-cluster-page">List Certificate Objects on the Cluster Page</a></li>
<li><a href="#customize-details-panel">Customize Details Panel</a></li>
</ol>
<h2 id="register-clusterpage-and-clusterpagemenu-objects">Register <code>clusterPage</code> and <code>clusterPageMenu</code> Objects<a class="headerlink" href="#register-clusterpage-and-clusterpagemenu-objects" title="Permanent link">#</a></h2>
<p>First thing we need to do with our extension is to register new menu item in the cluster menu and create a cluster page that is opened when clicking the menu item. We will do this in our extension class <code>CrdSampleExtension</code> that is derived <code>LensRendererExtension</code> class:</p>
<p>First thing we need to do with our extension is to register new menu item in the cluster menu and create a cluster page that is opened when clicking the menu item.
We will do this in our extension class <code>CrdSampleExtension</code> that is derived <code>LensRendererExtension</code> class:</p>
<div class="highlight"><pre><span></span><code><span class="k">export</span> <span class="k">default</span> <span class="kd">class</span> <span class="nx">CrdSampleExtension</span> <span class="k">extends</span> <span class="nx">LensRendererExtension</span> <span class="p">{</span>
<span class="p">}</span>
</code></pre></div>
<p>To register menu item in the cluster menu we need to register <code>PageMenuRegistration</code> object. This object will register a menu item with "Certificates" text. It will also use <code>CertificateIcon</code> component to render an icon and navigate to cluster page that is having <code>certificates</code> page id.</p>
<p>To register menu item in the cluster menu we need to register <code>PageMenuRegistration</code> object.
This object will register a menu item with "Certificates" text.
It will also use <code>CertificateIcon</code> component to render an icon and navigate to cluster page that is having <code>certificates</code> page id.</p>
<div class="highlight"><pre><span></span><code><span class="k">export</span> <span class="kd">function</span> <span class="nx">CertificateIcon</span><span class="p">(</span><span class="nx">props</span>: <span class="kt">Component.IconProps</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="o">&lt;</span><span class="nx">Component</span><span class="p">.</span><span class="nx">Icon</span> <span class="p">{...</span><span class="nx">props</span><span class="p">}</span> <span class="nx">material</span><span class="o">=</span><span class="s2">&quot;security&quot;</span> <span class="nx">tooltip</span><span class="o">=</span><span class="s2">&quot;Certificates&quot;</span><span class="o">/&gt;</span>
<span class="p">}</span>
@@ -921,9 +938,13 @@
<span class="p">}</span>
</code></pre></div>
<h2 id="list-certificate-objects-on-the-cluster-page">List Certificate Objects on the Cluster Page<a class="headerlink" href="#list-certificate-objects-on-the-cluster-page" title="Permanent link">#</a></h2>
<p>In the previous step we defined <code>CertificatePage</code> component to render certificates. In this step we will actually implement that. <code>CertificatePage</code> is a React component that will render <code>Component.KubeObjectListLayout</code> component to list <code>Certificate</code> CRD objects.</p>
<p>In the previous step we defined <code>CertificatePage</code> component to render certificates.
In this step we will actually implement that.
<code>CertificatePage</code> is a React component that will render <code>Component.KubeObjectListLayout</code> component to list <code>Certificate</code> CRD objects.</p>
<h3 id="get-crd-objects">Get CRD objects<a class="headerlink" href="#get-crd-objects" title="Permanent link">#</a></h3>
<p>In order to list CRD objects, we need first fetch those from Kubernetes API. Lens Extensions API provides easy mechanism to do this. We just need to define <code>Certificate</code> class derived from <code>K8sApi.KubeObject</code>, <code>CertificatesApi</code>derived from <code>K8sApi.KubeApi</code> and <code>CertificatesStore</code> derived from <code>K8sApi.KubeObjectStore</code>.</p>
<p>In order to list CRD objects, we need first fetch those from Kubernetes API.
Lens Extensions API provides easy mechanism to do this.
We just need to define <code>Certificate</code> class derived from <code>K8sApi.KubeObject</code>, <code>CertificatesApi</code>derived from <code>K8sApi.KubeApi</code> and <code>CertificatesStore</code> derived from <code>K8sApi.KubeObjectStore</code>.</p>
<p><code>Certificate</code> class defines properties found in the CRD object:</p>
<div class="highlight"><pre><span></span><code><span class="k">export</span> <span class="kd">class</span> <span class="nx">Certificate</span> <span class="k">extends</span> <span class="nx">K8sApi</span><span class="p">.</span><span class="nx">KubeObject</span> <span class="p">{</span>
<span class="k">static</span> <span class="nx">kind</span> <span class="o">=</span> <span class="s2">&quot;Certificate&quot;</span>
@@ -984,7 +1005,8 @@
<div class="highlight"><pre><span></span><code><span class="nx">K8sApi</span><span class="p">.</span><span class="nx">apiManager</span><span class="p">.</span><span class="nx">registerStore</span><span class="p">(</span><span class="nx">certificatesStore</span><span class="p">);</span>
</code></pre></div>
<h3 id="create-certificatepage-component">Create CertificatePage component<a class="headerlink" href="#create-certificatepage-component" title="Permanent link">#</a></h3>
<p>Now we have created mechanism to manage <code>Certificate</code> objects in Kubernetes API. Then we need to fetch those and render them in the UI.</p>
<p>Now we have created mechanism to manage <code>Certificate</code> objects in Kubernetes API.
Then we need to fetch those and render them in the UI.</p>
<p>First we define <code>CertificatePage</code> class that extends <code>React.Component</code>.</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">LensRendererExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s2">&quot;react&quot;</span><span class="p">;</span>
@@ -995,7 +1017,11 @@
<span class="p">}</span>
</code></pre></div>
<p>Next we will implement <code>render</code> method that will display certificates in a list. To do that, we just need to add <code>Component.KubeObjectListLayout</code> component inside <code>Component.TabLayout</code> component in render method. To define which objects the list is showing, we need to pass <code>certificateStore</code> object to <code>Component.KubeObjectListLayout</code> in <code>store</code> property. <code>Component.KubeObjectListLayout</code> will fetch automacially items from the given store when component is mounted. Also, we can define needed sorting callbacks and search filters for the list:</p>
<p>Next we will implement <code>render</code> method that will display certificates in a list.
To do that, we just need to add <code>Component.KubeObjectListLayout</code> component inside <code>Component.TabLayout</code> component in render method.
To define which objects the list is showing, we need to pass <code>certificateStore</code> object to <code>Component.KubeObjectListLayout</code> in <code>store</code> property.
<code>Component.KubeObjectListLayout</code> will fetch automatically items from the given store when component is mounted.
Also, we can define needed sorting callbacks and search filters for the list:</p>
<div class="highlight"><pre><span></span><code><span class="kd">enum</span> <span class="nx">sortBy</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="s2">&quot;name&quot;</span><span class="p">,</span>
<span class="nx">namespace</span> <span class="o">=</span> <span class="s2">&quot;namespace&quot;</span><span class="p">,</span>
@@ -1036,8 +1062,10 @@
<span class="p">}</span>
</code></pre></div>
<h3 id="customize-details-panel">Customize Details panel<a class="headerlink" href="#customize-details-panel" title="Permanent link">#</a></h3>
<p>We have learned now, how to list CRD objects in a list view. Next, we will learn how to customize details panel that will be opened when the object is clicked in the list.</p>
<p>First, we need to register our custom component to render details for the specific Kubernetes custom resource, in our case <code>Certificate</code>. We will do this again in <code>CrdSampleExtension</code> class:</p>
<p>We have learned now, how to list CRD objects in a list view.
Next, we will learn how to customize details panel that will be opened when the object is clicked in the list.</p>
<p>First, we need to register our custom component to render details for the specific Kubernetes custom resource, in our case <code>Certificate</code>.
We will do this again in <code>CrdSampleExtension</code> class:</p>
<div class="highlight"><pre><span></span><code><span class="k">export</span> <span class="k">default</span> <span class="kd">class</span> <span class="nx">CrdSampleExtension</span> <span class="k">extends</span> <span class="nx">LensRendererExtension</span> <span class="p">{</span>
<span class="c1">//...</span>
@@ -1050,7 +1078,10 @@
<span class="p">}]</span>
<span class="p">}</span>
</code></pre></div>
<p>Here we defined that <code>CertificateDetails</code> component will render the resource details. So, next we need to implement that component. Lens will inject <code>Certificate</code> object into our component so we just need to render some information out of it. We can use <code>Component.DrawerItem</code> component from Lens Extensions API to give the same look and feel as Lens is using elsewhere:</p>
<p>Here we defined that <code>CertificateDetails</code> component will render the resource details.
So, next we need to implement that component.
Lens will inject <code>Certificate</code> object into our component so we just need to render some information out of it.
We can use <code>Component.DrawerItem</code> component from Lens Extensions API to give the same look and feel as Lens is using elsewhere:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">K8sApi</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s2">&quot;react&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">Certificate</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;../certificate&quot;</span><span class="p">;</span>
@@ -1094,7 +1125,8 @@
<span class="p">}</span>
</code></pre></div>
<h2 id="summary">Summary<a class="headerlink" href="#summary" title="Permanent link">#</a></h2>
<p>Like we can see above, it's very easy to add custom pages and fetch Kubernetes resources by using Extensions API. Please see the <a href="https://github.com/lensapp/lens-extension-samples/tree/master/custom-resource-page">complete source code</a> to test it out.</p>
<p>Like we can see above, it's very easy to add custom pages and fetch Kubernetes resources by using Extensions API.
Please see the <a href="https://github.com/lensapp/lens-extension-samples/tree/master/custom-resource-page">complete source code</a> to test it out.</p>
@@ -665,6 +665,18 @@
</li>
<li class="md-nav__item">
<a href="../protocol-handlers/" class="md-nav__link">
Protocol Handlers
</a>
</li>
</ul>
</nav>
</li>
@@ -917,7 +929,9 @@
<h1 id="main-extension">Main Extension<a class="headerlink" href="#main-extension" title="Permanent link">#</a></h1>
<p>The Main Extension API is the interface to Lens's main process. Lens runs in both main and renderer processes. The Main Extension API allows you to access, configure, and customize Lens data, add custom application menu items, and run custom code in Lens's main process.</p>
<p>The Main Extension API is the interface to Lens's main process.
Lens runs in both main and renderer processes.
The Main Extension API allows you to access, configure, and customize Lens data, add custom application menu items, and run custom code in Lens's main process.</p>
<h2 id="lensmainextension-class"><code>LensMainExtension</code> Class<a class="headerlink" href="#lensmainextension-class" title="Permanent link">#</a></h2>
<h3 id="onactivate-and-ondeactivate-methods"><code>onActivate()</code> and <code>onDeactivate()</code> Methods<a class="headerlink" href="#onactivate-and-ondeactivate-methods" title="Permanent link">#</a></h3>
<p>To create a main extension simply extend the <code>LensMainExtension</code> class:</p>
@@ -933,14 +947,21 @@
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Two methods enable you to run custom code: <code>onActivate()</code> and <code>onDeactivate()</code>. Enabling your extension calls <code>onActivate()</code> and disabling your extension calls <code>onDeactivate()</code>. You can initiate custom code by implementing <code>onActivate()</code>. Implementing <code>onDeactivate()</code> gives you the opportunity to clean up after your extension.</p>
<p>Two methods enable you to run custom code: <code>onActivate()</code> and <code>onDeactivate()</code>.
Enabling your extension calls <code>onActivate()</code> and disabling your extension calls <code>onDeactivate()</code>.
You can initiate custom code by implementing <code>onActivate()</code>.
Implementing <code>onDeactivate()</code> gives you the opportunity to clean up after your extension.</p>
<p>Disable extensions from the Lens Extensions page:</p>
<ol>
<li>Navigate to <strong>File</strong> &gt; <strong>Extensions</strong> in the top menu bar. (On Mac, it is <strong>Lens</strong> &gt; <strong>Extensions</strong>.)</li>
<li>Navigate to <strong>File</strong> &gt; <strong>Extensions</strong> in the top menu bar.
(On Mac, it is <strong>Lens</strong> &gt; <strong>Extensions</strong>.)</li>
<li>Click <strong>Disable</strong> on the extension you want to disable.</li>
</ol>
<p>The example above logs messages when the extension is enabled and disabled. To see standard output from the main process there must be a console connected to it. Achieve this by starting Lens from the command prompt.</p>
<p>The following example is a little more interesting. It accesses some Lens state data, and it periodically logs the name of the cluster that is currently active in Lens.</p>
<p>The example above logs messages when the extension is enabled and disabled.
To see standard output from the main process there must be a console connected to it.
Achieve this by starting Lens from the command prompt.</p>
<p>The following example is a little more interesting.
It accesses some Lens state data, and it periodically logs the name of the cluster that is currently active in Lens.</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensMainExtension</span><span class="p">,</span> <span class="nx">Store</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">clusterStore</span> <span class="o">=</span> <span class="nx">Store</span><span class="p">.</span><span class="nx">clusterStore</span>
@@ -968,7 +989,9 @@
</code></pre></div>
<p>For more details on accessing Lens state data, please see the <a href="../stores">Stores</a> guide.</p>
<h3 id="appmenus"><code>appMenus</code><a class="headerlink" href="#appmenus" title="Permanent link">#</a></h3>
<p>The Main Extension API allows you to customize the UI application menu. Note that this is the only UI feature that the Main Extension API allows you to customize. The following example demonstrates adding an item to the <strong>Help</strong> menu.</p>
<p>The Main Extension API allows you to customize the UI application menu.
Note that this is the only UI feature that the Main Extension API allows you to customize.
The following example demonstrates adding an item to the <strong>Help</strong> menu.</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensMainExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">export</span> <span class="k">default</span> <span class="kd">class</span> <span class="nx">SamplePageMainExtension</span> <span class="k">extends</span> <span class="nx">LensMainExtension</span> <span class="p">{</span>
@@ -983,11 +1006,18 @@
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
<p><code>appMenus</code> is an array of objects that satisfy the <code>MenuRegistration</code> interface. <code>MenuRegistration</code> extends React's <code>MenuItemConstructorOptions</code> interface. The properties of the appMenus array objects are defined as follows:</p>
<p><code>appMenus</code> is an array of objects that satisfy the <code>MenuRegistration</code> interface.
<code>MenuRegistration</code> extends React's <code>MenuItemConstructorOptions</code> interface.
The properties of the appMenus array objects are defined as follows:</p>
<ul>
<li><code>parentId</code> is the name of the menu where your new menu item will be listed. Valid values include: <code>"file"</code>, <code>"edit"</code>, <code>"view"</code>, and <code>"help"</code>. <code>"lens"</code> is valid on Mac only.</li>
<li><code>parentId</code> is the name of the menu where your new menu item will be listed.
Valid values include: <code>"file"</code>, <code>"edit"</code>, <code>"view"</code>, and <code>"help"</code>.
<code>"lens"</code> is valid on Mac only.</li>
<li><code>label</code> is the name of your menu item.</li>
<li><code>click()</code> is called when the menu item is selected. In this example, we simply log a message. However, you would typically have this navigate to a specific page or perform another operation. Note that pages are associated with the <a href="../renderer-extension/"><code>LensRendererExtension</code></a> class and can be defined in the process of extending it. </li>
<li><code>click()</code> is called when the menu item is selected.
In this example, we simply log a message.
However, you would typically have this navigate to a specific page or perform another operation.
Note that pages are associated with the <a href="../renderer-extension/"><code>LensRendererExtension</code></a> class and can be defined in the process of extending it.</li>
</ul>
@@ -19,7 +19,7 @@
<title>Lens Protocol Handlers - Lens Documentation</title>
<title>Protocol Handlers - Lens Documentation</title>
@@ -106,7 +106,7 @@
<div class="md-header-nav__topic">
<span class="md-ellipsis">
Lens Protocol Handlers
Protocol Handlers
</span>
</div>
@@ -345,10 +345,12 @@
<li class="md-nav__item md-nav__item--nested">
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-7" type="checkbox" id="nav-7">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-7" type="checkbox" id="nav-7" checked>
<label class="md-nav__link" for="nav-7">
Extension Development
@@ -514,10 +516,12 @@
<li class="md-nav__item md-nav__item--nested">
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-7-4" type="checkbox" id="nav-7-4">
<input class="md-nav__toggle md-toggle" data-md-toggle="nav-7-4" type="checkbox" id="nav-7-4" checked>
<label class="md-nav__link" for="nav-7-4">
Extension Guides
@@ -603,6 +607,70 @@
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Protocol Handlers
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
Protocol Handlers
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#registering-a-protocol-handler" class="md-nav__link">
Registering A Protocol Handler
</a>
</li>
<li class="md-nav__item">
<a href="#deregistering-a-protocol-handler" class="md-nav__link">
Deregistering A Protocol Handler
</a>
</li>
<li class="md-nav__item">
<a href="#routing-algorithm" class="md-nav__link">
Routing Algorithm
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
@@ -925,6 +993,41 @@ This way the <code>"/"</code> (root) <code>pathSchema</code> acts as a sort of c
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid" aria-label="Footer">
<a href="../working-with-mobx/" class="md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-footer-nav__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</div>
<div class="md-footer-nav__title">
<div class="md-ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Working with MobX
</div>
</div>
</a>
<a href="../../testing-and-publishing/testing/" class="md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-footer-nav__title">
<div class="md-ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Testing Extensions
</div>
</div>
<div class="md-footer-nav__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z"/></svg>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
@@ -721,6 +721,18 @@
</li>
<li class="md-nav__item">
<a href="../protocol-handlers/" class="md-nav__link">
Protocol Handlers
</a>
</li>
</ul>
</nav>
</li>
@@ -1029,7 +1041,9 @@
<h1 id="renderer-extension">Renderer Extension<a class="headerlink" href="#renderer-extension" title="Permanent link">#</a></h1>
<p>The Renderer Extension API is the interface to Lens's renderer process. Lens runs in both the main and renderer processes. The Renderer Extension API allows you to access, configure, and customize Lens data, add custom Lens UI elements, and run custom code in Lens's renderer process.</p>
<p>The Renderer Extension API is the interface to Lens's renderer process.
Lens runs in both the main and renderer processes.
The Renderer Extension API allows you to access, configure, and customize Lens data, add custom Lens UI elements, and run custom code in Lens's renderer process.</p>
<p>The custom Lens UI elements that you can add include:</p>
<ul>
<li><a href="#clusterpages">Cluster pages</a></li>
@@ -1058,18 +1072,25 @@
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Two methods enable you to run custom code: <code>onActivate()</code> and <code>onDeactivate()</code>. Enabling your extension calls <code>onActivate()</code> and disabling your extension calls <code>onDeactivate()</code>. You can initiate custom code by implementing <code>onActivate()</code>. Implementing <code>onDeactivate()</code> gives you the opportunity to clean up after your extension.</p>
<p>Two methods enable you to run custom code: <code>onActivate()</code> and <code>onDeactivate()</code>.
Enabling your extension calls <code>onActivate()</code> and disabling your extension calls <code>onDeactivate()</code>.
You can initiate custom code by implementing <code>onActivate()</code>.
Implementing <code>onDeactivate()</code> gives you the opportunity to clean up after your extension.</p>
<div class="admonition info">
<p class="admonition-title">Info</p>
<p>Disable extensions from the Lens Extensions page:</p>
<ol>
<li>Navigate to <strong>File</strong> &gt; <strong>Extensions</strong> in the top menu bar. (On Mac, it is <strong>Lens</strong> &gt; <strong>Extensions</strong>.)</li>
<li>Navigate to <strong>File</strong> &gt; <strong>Extensions</strong> in the top menu bar.
(On Mac, it is <strong>Lens</strong> &gt; <strong>Extensions</strong>.)</li>
<li>Click <strong>Disable</strong> on the extension you want to disable.</li>
</ol>
</div>
<p>The example above logs messages when the extension is enabled and disabled.</p>
<h3 id="clusterpages"><code>clusterPages</code><a class="headerlink" href="#clusterpages" title="Permanent link">#</a></h3>
<p>Cluster pages appear in the cluster dashboard. Use cluster pages to display information about or add functionality to the active cluster. It is also possible to include custom details from other clusters. Use your extension to access Kubernetes resources in the active cluster with <a href="../stores#clusterstore"><code>clusterStore</code></a>.</p>
<p>Cluster pages appear in the cluster dashboard.
Use cluster pages to display information about or add functionality to the active cluster.
It is also possible to include custom details from other clusters.
Use your extension to access Kubernetes resources in the active cluster with <a href="../stores#clusterstore"><code>clusterStore</code></a>.</p>
<p>Add a cluster page definition to a <code>LensRendererExtension</code> subclass with the following example:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">ExampleIcon</span><span class="p">,</span> <span class="nx">ExamplePage</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;./page&quot;</span>
@@ -1086,11 +1107,13 @@
<span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
<p><code>clusterPages</code> is an array of objects that satisfy the <code>PageRegistration</code> interface. The properties of the <code>clusterPages</code> array objects are defined as follows:</p>
<p><code>clusterPages</code> is an array of objects that satisfy the <code>PageRegistration</code> interface.
The properties of the <code>clusterPages</code> array objects are defined as follows:</p>
<ul>
<li><code>id</code> is a string that identifies the page.</li>
<li><code>components</code> matches the <code>PageComponents</code> interface for which there is one field, <code>Page</code>.</li>
<li><code>Page</code> is of type <code>React.ComponentType&lt;any&gt;</code>. It offers flexibility in defining the appearance and behavior of your page.</li>
<li><code>Page</code> is of type <code>React.ComponentType&lt;any&gt;</code>.
It offers flexibility in defining the appearance and behavior of your page.</li>
</ul>
<p><code>ExamplePage</code> in the example above can be defined in <code>page.tsx</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
@@ -1106,8 +1129,11 @@
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Note that the <code>ExamplePage</code> class defines the <code>extension</code> property. This allows the <code>ExampleExtension</code> object to be passed in the cluster page definition in the React style. This way, <code>ExamplePage</code> can access all <code>ExampleExtension</code> subclass data.</p>
<p>The above example shows how to create a cluster page, but not how to make that page available to the Lens user. Use <code>clusterPageMenus</code>, covered in the next section, to add cluster pages to the Lens UI.</p>
<p>Note that the <code>ExamplePage</code> class defines the <code>extension</code> property.
This allows the <code>ExampleExtension</code> object to be passed in the cluster page definition in the React style.
This way, <code>ExamplePage</code> can access all <code>ExampleExtension</code> subclass data.</p>
<p>The above example shows how to create a cluster page, but not how to make that page available to the Lens user.
Use <code>clusterPageMenus</code>, covered in the next section, to add cluster pages to the Lens UI.</p>
<h3 id="clusterpagemenus"><code>clusterPageMenus</code><a class="headerlink" href="#clusterpagemenus" title="Permanent link">#</a></h3>
<p><code>clusterPageMenus</code> allows you to add cluster page menu items to the secondary left nav.</p>
<p>By expanding on the above example, you can add a cluster page menu item to the <code>ExampleExtension</code> definition:</p>
@@ -1136,14 +1162,17 @@
<span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
<p><code>clusterPageMenus</code> is an array of objects that satisfy the <code>ClusterPageMenuRegistration</code> interface. This element defines how the cluster page menu item will appear and what it will do when you click it. The properties of the <code>clusterPageMenus</code> array objects are defined as follows:</p>
<p><code>clusterPageMenus</code> is an array of objects that satisfy the <code>ClusterPageMenuRegistration</code> interface.
This element defines how the cluster page menu item will appear and what it will do when you click it.
The properties of the <code>clusterPageMenus</code> array objects are defined as follows:</p>
<ul>
<li><code>target</code> links to the relevant cluster page using <code>pageId</code>.</li>
<li><code>pageId</code> takes the value of the relevant cluster page's <code>id</code> property.</li>
<li><code>title</code> sets the name of the cluster page menu item that will appear in the left side menu.</li>
<li><code>components</code> is used to set an icon that appears to the left of the <code>title</code> text in the left side menu.</li>
</ul>
<p>The above example creates a menu item that reads <strong>Hello World</strong>. When users click <strong>Hello World</strong>, the cluster dashboard will show the contents of <code>Example Page</code>.</p>
<p>The above example creates a menu item that reads <strong>Hello World</strong>.
When users click <strong>Hello World</strong>, the cluster dashboard will show the contents of <code>Example Page</code>.</p>
<p>This example requires the definition of another React-based component, <code>ExampleIcon</code>, which has been added to <code>page.tsx</code>, as follows:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span><span class="p">,</span> <span class="nx">Component</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s2">&quot;react&quot;</span>
@@ -1162,12 +1191,15 @@
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Lens includes various built-in components available for extension developers to use. One of these is the <code>Component.Icon</code>, introduced in <code>ExampleIcon</code>, which you can use to access any of the <a href="https://material.io/resources/icons/">icons</a> available at <a href="https://material.io">Material Design</a>. The properties that <code>Component.Icon</code> uses are defined as follows:</p>
<p>Lens includes various built-in components available for extension developers to use.
One of these is the <code>Component.Icon</code>, introduced in <code>ExampleIcon</code>, which you can use to access any of the <a href="https://material.io/resources/icons/">icons</a> available at <a href="https://material.io">Material Design</a>.
The properties that <code>Component.Icon</code> uses are defined as follows:</p>
<ul>
<li><code>material</code> takes the name of the icon you want to use.</li>
<li><code>tooltip</code> sets the text you want to appear when a user hovers over the icon.</li>
</ul>
<p><code>clusterPageMenus</code> can also be used to define sub menu items, so that you can create groups of cluster pages. The following example groups two sub menu items under one parent menu item:</p>
<p><code>clusterPageMenus</code> can also be used to define sub menu items, so that you can create groups of cluster pages.
The following example groups two sub menu items under one parent menu item:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">ExampleIcon</span><span class="p">,</span> <span class="nx">ExamplePage</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;./page&quot;</span>
<span class="k">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s2">&quot;react&quot;</span>
@@ -1228,8 +1260,11 @@ The remaining two cluster page menu objects define the contents of the submenu.
A cluster page menu object is defined to be a submenu item by setting the <code>parentId</code> field to the id of the parent of a foldout submenu, <code>"example"</code> in this case.</p>
<p>This is what the example will look like, including how the menu item will appear in the secondary left nav:</p>
<h3 id="globalpages"><code>globalPages</code><a class="headerlink" href="#globalpages" title="Permanent link">#</a></h3>
<p>Global pages are independent of the cluster dashboard and can fill the entire Lens UI. Their primary use is to display information and provide functionality across clusters, including customized data and functionality unique to your extension.</p>
<p>Typically, you would use a <a href="#globalpagemenus">global page menu</a> located in the left nav to trigger a global page. You can also trigger a global page with a <a href="../main-extension#appmenus">custom app menu selection</a> from a Main Extension or a <a href="#statusbaritems">custom status bar item</a>. Unlike cluster pages, users can trigger global pages even when there is no active cluster.</p>
<p>Global pages are independent of the cluster dashboard and can fill the entire Lens UI.
Their primary use is to display information and provide functionality across clusters, including customized data and functionality unique to your extension.</p>
<p>Typically, you would use a <a href="#globalpagemenus">global page menu</a> located in the left nav to trigger a global page.
You can also trigger a global page with a <a href="../main-extension#appmenus">custom app menu selection</a> from a Main Extension or a <a href="#statusbaritems">custom status bar item</a>.
Unlike cluster pages, users can trigger global pages even when there is no active cluster.</p>
<p>The following example defines a <code>LensRendererExtension</code> subclass with a single global page definition:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@k8slens/extensions&#39;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">HelpPage</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;./page&#39;</span><span class="p">;</span>
@@ -1246,11 +1281,13 @@ A cluster page menu object is defined to be a submenu item by setting the <code>
<span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
<p><code>globalPages</code> is an array of objects that satisfy the <code>PageRegistration</code> interface. The properties of the <code>globalPages</code> array objects are defined as follows:</p>
<p><code>globalPages</code> is an array of objects that satisfy the <code>PageRegistration</code> interface.
The properties of the <code>globalPages</code> array objects are defined as follows:</p>
<ul>
<li><code>id</code> is a string that identifies the page.</li>
<li><code>components</code> matches the <code>PageComponents</code> interface for which there is one field, <code>Page</code>.</li>
<li><code>Page</code> is of type <code>React.ComponentType&lt;any&gt;</code>. It offers flexibility in defining the appearance and behavior of your page.</li>
<li><code>Page</code> is of type <code>React.ComponentType&lt;any&gt;</code>.
It offers flexibility in defining the appearance and behavior of your page.</li>
</ul>
<p><code>HelpPage</code> in the example above can be defined in <code>page.tsx</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
@@ -1266,8 +1303,11 @@ A cluster page menu object is defined to be a submenu item by setting the <code>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Note that the <code>HelpPage</code> class defines the <code>extension</code> property. This allows the <code>HelpExtension</code> object to be passed in the global page definition in the React-style. This way, <code>HelpPage</code> can access all <code>HelpExtension</code> subclass data.</p>
<p>This example code shows how to create a global page, but not how to make that page available to the Lens user. Global pages can be made available in the following ways:</p>
<p>Note that the <code>HelpPage</code> class defines the <code>extension</code> property.
This allows the <code>HelpExtension</code> object to be passed in the global page definition in the React-style.
This way, <code>HelpPage</code> can access all <code>HelpExtension</code> subclass data.</p>
<p>This example code shows how to create a global page, but not how to make that page available to the Lens user.
Global pages can be made available in the following ways:</p>
<ul>
<li>To add global pages to the top menu bar, see <a href="../main-extension#appmenus"><code>appMenus</code></a> in the Main Extension guide.</li>
<li>To add global pages as an interactive element in the blue status bar along the bottom of the Lens UI, see <a href="#statusbaritems"><code>statusBarItems</code></a>.</li>
@@ -1301,15 +1341,19 @@ A cluster page menu object is defined to be a submenu item by setting the <code>
<span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
<p><code>globalPageMenus</code> is an array of objects that satisfy the <code>PageMenuRegistration</code> interface. This element defines how the global page menu item will appear and what it will do when you click it. The properties of the <code>globalPageMenus</code> array objects are defined as follows:</p>
<p><code>globalPageMenus</code> is an array of objects that satisfy the <code>PageMenuRegistration</code> interface.
This element defines how the global page menu item will appear and what it will do when you click it.
The properties of the <code>globalPageMenus</code> array objects are defined as follows:</p>
<ul>
<li><code>target</code> links to the relevant global page using <code>pageId</code>.</li>
<li><code>pageId</code> takes the value of the relevant global page's <code>id</code> property.</li>
<li><code>title</code> sets the name of the global page menu item that will display as a tooltip in the left nav.</li>
<li><code>components</code> is used to set an icon that appears in the left nav.</li>
</ul>
<p>The above example creates a "Help" icon menu item. When users click the icon, the Lens UI will display the contents of <code>ExamplePage</code>.</p>
<p>This example requires the definition of another React-based component, <code>HelpIcon</code>. Update <code>page.tsx</code> from the example above with the <code>HelpIcon</code> definition, as follows:</p>
<p>The above example creates a "Help" icon menu item.
When users click the icon, the Lens UI will display the contents of <code>ExamplePage</code>.</p>
<p>This example requires the definition of another React-based component, <code>HelpIcon</code>.
Update <code>page.tsx</code> from the example above with the <code>HelpIcon</code> definition, as follows:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span><span class="p">,</span> <span class="nx">Component</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s2">&quot;react&quot;</span>
@@ -1327,7 +1371,9 @@ A cluster page menu object is defined to be a submenu item by setting the <code>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Lens includes various built-in components available for extension developers to use. One of these is the <code>Component.Icon</code>, introduced in <code>HelpIcon</code>, which you can use to access any of the <a href="https://material.io/resources/icons/">icons</a> available at <a href="https://material.io">Material Design</a>. The property that <code>Component.Icon</code> uses is defined as follows:</p>
<p>Lens includes various built-in components available for extension developers to use.
One of these is the <code>Component.Icon</code>, introduced in <code>HelpIcon</code>, which you can use to access any of the <a href="https://material.io/resources/icons/">icons</a> available at <a href="https://material.io">Material Design</a>.
The property that <code>Component.Icon</code> uses is defined as follows:</p>
<ul>
<li><code>material</code> takes the name of the icon you want to use.</li>
</ul>
@@ -1400,7 +1446,8 @@ Consider using the following properties with <code>updateStatus()</code>:</p>
<p><code>status.installed</code> should be set to <code>true</code> if the feature is installed, and <code>false</code> otherwise.</p>
</li>
<li>
<p><code>status.canUpgrade</code> is set according to a rule meant to determine whether the feature can be upgraded. This rule can involve <code>status.currentVersion</code> and <code>status.latestVersion</code>, if desired.</p>
<p><code>status.canUpgrade</code> is set according to a rule meant to determine whether the feature can be upgraded.
This rule can involve <code>status.currentVersion</code> and <code>status.latestVersion</code>, if desired.</p>
</li>
</ul>
</li>
@@ -1464,17 +1511,20 @@ The file <code>../resources/example-pod.yml</code> could contain:</p>
<p>The example above implements the four methods as follows:</p>
<ul>
<li>
<p>It implements <code>upgrade()</code> by invoking the <code>install()</code> method. Depending on the feature to be supported by an extension, upgrading may require additional and/or different steps.</p>
<p>It implements <code>upgrade()</code> by invoking the <code>install()</code> method.
Depending on the feature to be supported by an extension, upgrading may require additional and/or different steps.</p>
</li>
<li>
<p>It implements <code>uninstall()</code> by utilizing the <a href="../../api/">Kubernetes API</a> which Lens provides to delete the <code>example-pod</code> applied by the <code>install()</code> method.</p>
</li>
<li>
<p>It implements <code>updateStatus()</code> by using the <a href="../../api/">Kubernetes API</a> which Lens provides to determine whether the <code>example-pod</code> is installed, what version is associated with it, and whether it can be upgraded. The implementation determines what the status is for a specific cluster feature.</p>
<p>It implements <code>updateStatus()</code> by using the <a href="../../api/">Kubernetes API</a> which Lens provides to determine whether the <code>example-pod</code> is installed, what version is associated with it, and whether it can be upgraded.
The implementation determines what the status is for a specific cluster feature.</p>
</li>
</ul>
<h3 id="apppreferences"><code>appPreferences</code><a class="headerlink" href="#apppreferences" title="Permanent link">#</a></h3>
<p>The Lens <strong>Preferences</strong> page is a built-in global page. You can use Lens extensions to add custom preferences to the Preferences page, providing a single location for users to configure global options.</p>
<p>The Lens <strong>Preferences</strong> page is a built-in global page.
You can use Lens extensions to add custom preferences to the Preferences page, providing a single location for users to configure global options.</p>
<p>The following example demonstrates adding a custom preference:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">ExamplePreferenceHint</span><span class="p">,</span> <span class="nx">ExamplePreferenceInput</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;./src/example-preference&quot;</span><span class="p">;</span>
@@ -1496,7 +1546,8 @@ The file <code>../resources/example-pod.yml</code> could contain:</p>
<span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
<p><code>appPreferences</code> is an array of objects that satisfies the <code>AppPreferenceRegistration</code> interface. The properties of the <code>appPreferences</code> array objects are defined as follows:</p>
<p><code>appPreferences</code> is an array of objects that satisfies the <code>AppPreferenceRegistration</code> interface.
The properties of the <code>appPreferences</code> array objects are defined as follows:</p>
<ul>
<li><code>title</code> sets the heading text displayed on the Preferences page.</li>
<li><code>components</code> specifies two <code>React.Component</code> objects that define the interface for the preference.<ul>
@@ -1509,7 +1560,8 @@ The file <code>../resources/example-pod.yml</code> could contain:</p>
<p class="admonition-title">Note</p>
<p>Note that the input and the hint can be comprised of more sophisticated elements, according to the needs of the extension.</p>
</div>
<p><code>ExamplePreferenceInput</code> expects its React props to be set to an <code>ExamplePreferenceProps</code> instance. This is how <code>ExampleRendererExtension</code> handles the state of the preference input.
<p><code>ExamplePreferenceInput</code> expects its React props to be set to an <code>ExamplePreferenceProps</code> instance.
This is how <code>ExampleRendererExtension</code> handles the state of the preference input.
<code>ExampleRendererExtension</code> has a <code>preference</code> field, which you will add to <code>ExamplePreferenceInput</code>.</p>
<p>In this example <code>ExamplePreferenceInput</code>, <code>ExamplePreferenceHint</code>, and <code>ExamplePreferenceProps</code> are defined in <code>./src/example-preference.tsx</code> as follows:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Component</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
@@ -1551,14 +1603,25 @@ The file <code>../resources/example-pod.yml</code> could contain:</p>
<li><code>value</code> is initially set to <code>preference.enabled</code>.</li>
<li><code>onChange</code> is a function that responds when the state of the checkbox changes.</li>
</ul>
<p><code>ExamplePreferenceInput</code> is defined with the <code>ExamplePreferenceProps</code> React props. This is an object with the single <code>enabled</code> property. It is used to indicate the state of the preference, and it is bound to the checkbox state in <code>onChange</code>.</p>
<p><code>ExamplePreferenceInput</code> is defined with the <code>ExamplePreferenceProps</code> React props.
This is an object with the single <code>enabled</code> property.
It is used to indicate the state of the preference, and it is bound to the checkbox state in <code>onChange</code>.</p>
<p><code>ExamplePreferenceHint</code> is a simple text span.</p>
<p>The above example introduces the decorators <code>observable</code> and <code>observer</code> from the <a href="https://mobx.js.org/README.html"><code>mobx</code></a> and <a href="https://github.com/mobxjs/mobx-react#mobx-react"><code>mobx-react</code></a> packages. <code>mobx</code> simplifies state management. Without it, this example would not visually update the checkbox properly when the user activates it. <a href="../working-with-mobx">Lens uses <code>mobx</code></a> extensively for state management of its own UI elements. We recommend that extensions rely on it, as well.
<p>The above example introduces the decorators <code>observable</code> and <code>observer</code> from the <a href="https://mobx.js.org/README.html"><code>mobx</code></a> and <a href="https://github.com/mobxjs/mobx-react#mobx-react"><code>mobx-react</code></a> packages.
<code>mobx</code> simplifies state management.
Without it, this example would not visually update the checkbox properly when the user activates it.
<a href="../working-with-mobx">Lens uses <code>mobx</code></a> extensively for state management of its own UI elements.
We recommend that extensions rely on it, as well.
Alternatively, you can use React's state management, though <code>mobx</code> is typically simpler to use.</p>
<p>Note that you can manage an extension's state data using an <code>ExtensionStore</code> object, which conveniently handles persistence and synchronization. To simplify this guide, the example above defines a <code>preference</code> field in the <code>ExampleRendererExtension</code> class definition to hold the extension's state. However, we recommend that you manage your extension's state data using <a href="../stores#extensionstore"><code>ExtensionStore</code></a>.</p>
<p>Note that you can manage an extension's state data using an <code>ExtensionStore</code> object, which conveniently handles persistence and synchronization.
To simplify this guide, the example above defines a <code>preference</code> field in the <code>ExampleRendererExtension</code> class definition to hold the extension's state.
However, we recommend that you manage your extension's state data using <a href="../stores#extensionstore"><code>ExtensionStore</code></a>.</p>
<h3 id="statusbaritems"><code>statusBarItems</code><a class="headerlink" href="#statusbaritems" title="Permanent link">#</a></h3>
<p>The status bar is the blue strip along the bottom of the Lens UI. <code>statusBarItems</code> are <code>React.ReactNode</code> types. They can be used to display status information, or act as links to global pages as well as external pages.</p>
<p>The following example adds a <code>statusBarItems</code> definition and a <code>globalPages</code> definition to a <code>LensRendererExtension</code> subclass. It configures the status bar item to navigate to the global page upon activation (normally a mouse click):</p>
<p>The status bar is the blue strip along the bottom of the Lens UI.
<code>statusBarItems</code> are <code>React.ReactNode</code> types.
They can be used to display status information, or act as links to global pages as well as external pages.</p>
<p>The following example adds a <code>statusBarItems</code> definition and a <code>globalPages</code> definition to a <code>LensRendererExtension</code> subclass.
It configures the status bar item to navigate to the global page upon activation (normally a mouse click):</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@k8slens/extensions&#39;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">HelpIcon</span><span class="p">,</span> <span class="nx">HelpPage</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;./page&quot;</span>
<span class="k">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
@@ -1592,8 +1655,14 @@ Alternatively, you can use React's state management, though <code>mobx</code> is
</code></pre></div>
<p>The properties of the <code>statusBarItems</code> array objects are defined as follows:</p>
<ul>
<li><code>Item</code> specifies the <code>React.Component</code> that will be shown on the status bar. By default, items are added starting from the right side of the status bar. Due to limited space in the status bar, <code>Item</code> will typically specify only an icon or a short string of text. The example above reuses the <code>HelpIcon</code> from the <a href="#globalpagemenus"><code>globalPageMenus</code> guide</a>.</li>
<li><code>onClick</code> determines what the <code>statusBarItem</code> does when it is clicked. In the example, <code>onClick</code> is set to a function that calls the <code>LensRendererExtension</code> <code>navigate()</code> method. <code>navigate</code> takes the <code>id</code> of the associated global page as a parameter. Thus, clicking the status bar item activates the associated global pages.</li>
<li><code>Item</code> specifies the <code>React.Component</code> that will be shown on the status bar.
By default, items are added starting from the right side of the status bar.
Due to limited space in the status bar, <code>Item</code> will typically specify only an icon or a short string of text.
The example above reuses the <code>HelpIcon</code> from the <a href="#globalpagemenus"><code>globalPageMenus</code> guide</a>.</li>
<li><code>onClick</code> determines what the <code>statusBarItem</code> does when it is clicked.
In the example, <code>onClick</code> is set to a function that calls the <code>LensRendererExtension</code> <code>navigate()</code> method.
<code>navigate</code> takes the <code>id</code> of the associated global page as a parameter.
Thus, clicking the status bar item activates the associated global pages.</li>
</ul>
<h3 id="kubeobjectmenuitems"><code>kubeObjectMenuItems</code><a class="headerlink" href="#kubeobjectmenuitems" title="Permanent link">#</a></h3>
<p>An extension can add custom menu items (<code>kubeObjectMenuItems</code>) for specific Kubernetes resource kinds and apiVersions.
@@ -1618,12 +1687,15 @@ Alternatively, you can use React's state management, though <code>mobx</code> is
<span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
<p><code>kubeObjectMenuItems</code> is an array of objects matching the <code>KubeObjectMenuRegistration</code> interface. The example above adds a menu item for namespaces in the cluster dashboard. The properties of the <code>kubeObjectMenuItems</code> array objects are defined as follows:</p>
<p><code>kubeObjectMenuItems</code> is an array of objects matching the <code>KubeObjectMenuRegistration</code> interface.
The example above adds a menu item for namespaces in the cluster dashboard.
The properties of the <code>kubeObjectMenuItems</code> array objects are defined as follows:</p>
<ul>
<li><code>kind</code> specifies the Kubernetes resource type the menu item will apply to.</li>
<li><code>apiVersion</code> specifies the Kubernetes API version number to use with the resource type.</li>
<li><code>components</code> defines the menu item's appearance and behavior.</li>
<li><code>MenuItem</code> provides a function that returns a <code>React.Component</code> given a set of menu item properties. In this example a <code>NamespaceMenuItem</code> object is returned.</li>
<li><code>MenuItem</code> provides a function that returns a <code>React.Component</code> given a set of menu item properties.
In this example a <code>NamespaceMenuItem</code> object is returned.</li>
</ul>
<p><code>NamespaceMenuItem</code> is defined in <code>./src/namespace-menu-item.tsx</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s2">&quot;react&quot;</span><span class="p">;</span>
@@ -1655,8 +1727,13 @@ Alternatively, you can use React's state management, though <code>mobx</code> is
<span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p><code>NamespaceMenuItem</code> returns a <code>Component.MenuItem</code> which defines the menu item's appearance and its behavior when activated via the <code>onClick</code> property. In the example, <code>getPods()</code> opens a terminal tab and runs <code>kubectl</code> to get a list of pods running in the current namespace.</p>
<p>The name of the namespace is retrieved from <code>props</code> passed into <code>NamespaceMenuItem()</code>. <code>namespace</code> is the <code>props.object</code>, which is of type <code>K8sApi.Namespace</code>. <code>K8sApi.Namespace</code> is the API for accessing namespaces. The current namespace in this example is simply given by <code>namespace.getName()</code>. Thus, <code>kubeObjectMenuItems</code> afford convenient access to the specific resource selected by the user.</p>
<p><code>NamespaceMenuItem</code> returns a <code>Component.MenuItem</code> which defines the menu item's appearance and its behavior when activated via the <code>onClick</code> property.
In the example, <code>getPods()</code> opens a terminal tab and runs <code>kubectl</code> to get a list of pods running in the current namespace.</p>
<p>The name of the namespace is retrieved from <code>props</code> passed into <code>NamespaceMenuItem()</code>.
<code>namespace</code> is the <code>props.object</code>, which is of type <code>K8sApi.Namespace</code>.
<code>K8sApi.Namespace</code> is the API for accessing namespaces.
The current namespace in this example is simply given by <code>namespace.getName()</code>.
Thus, <code>kubeObjectMenuItems</code> afford convenient access to the specific resource selected by the user.</p>
<h3 id="kubeobjectdetailitems"><code>kubeObjectDetailItems</code><a class="headerlink" href="#kubeobjectdetailitems" title="Permanent link">#</a></h3>
<p>An extension can add custom details (<code>kubeObjectDetailItems</code>) for specified Kubernetes resource kinds and apiVersions.
These custom details appear on the details page for a specific resource, such as a Namespace as shown here:</p>
@@ -1679,12 +1756,15 @@ These custom details appear on the details page for a specific resource, such as
<span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
<p><code>kubeObjectDetailItems</code> is an array of objects matching the <code>KubeObjectDetailRegistration</code> interface. This example above adds a detail item for namespaces in the cluster dashboard. The properties of the <code>kubeObjectDetailItems</code> array objects are defined as follows:</p>
<p><code>kubeObjectDetailItems</code> is an array of objects matching the <code>KubeObjectDetailRegistration</code> interface.
This example above adds a detail item for namespaces in the cluster dashboard.
The properties of the <code>kubeObjectDetailItems</code> array objects are defined as follows:</p>
<ul>
<li><code>kind</code> specifies the Kubernetes resource type the detail item will apply to.</li>
<li><code>apiVersion</code> specifies the Kubernetes API version number to use with the resource type.</li>
<li><code>components</code> defines the detail item's appearance and behavior.</li>
<li><code>Details</code> provides a function that returns a <code>React.Component</code> given a set of detail item properties. In this example a <code>NamespaceDetailsItem</code> object is returned.</li>
<li><code>Details</code> provides a function that returns a <code>React.Component</code> given a set of detail item properties.
In this example a <code>NamespaceDetailsItem</code> object is returned.</li>
</ul>
<p><code>NamespaceDetailsItem</code> is defined in <code>./src/namespace-details-item.tsx</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">K8sApi</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
@@ -1774,7 +1854,8 @@ The rest of this example's details are defined in <code>PodsDetailsList</code>,
</code></pre></div>
<p><code>PodsDetailsList</code> produces a simple table showing a list of the pods found in this namespace:</p>
<p><img alt="DetailsWithPods" src="../images/kubeobjectdetailitemwithpods.png" /></p>
<p>Obtain the name, age, and status for each pod using the <code>K8sApi.Pod</code> methods. Construct the table using the <code>Component.Table</code> and related elements.</p>
<p>Obtain the name, age, and status for each pod using the <code>K8sApi.Pod</code> methods.
Construct the table using the <code>Component.Table</code> and related elements.</p>
<p>For each pod the name, age, and status are obtained using the <code>K8sApi.Pod</code> methods.
The table is constructed using the <code>Component.Table</code> and related elements.
See <a href="https://docs.k8slens.dev/master/extensions/api/modules/_renderer_api_components_/"><code>Component</code> documentation</a> for further details.</p>
+42 -9
View File
@@ -645,6 +645,18 @@
</li>
<li class="md-nav__item">
<a href="../protocol-handlers/" class="md-nav__link">
Protocol Handlers
</a>
</li>
</ul>
</nav>
</li>
@@ -885,7 +897,10 @@
</ul>
<p>This guide focuses on the <code>ExtensionStore</code>.</p>
<h2 id="extensionstore">ExtensionStore<a class="headerlink" href="#extensionstore" title="Permanent link">#</a></h2>
<p>Extension developers can create their own store for managing state data by extending the <code>ExtensionStore</code> class. This guide shows how to create a store for the <a href="../renderer-extension#apppreferences"><code>appPreferences</code></a> guide example, which demonstrates how to add a custom preference to the <strong>Preferences</strong> page. The preference is a simple boolean that indicates whether or not something is enabled. However, in the example, the enabled state is not stored anywhere, and it reverts to the default when Lens is restarted.</p>
<p>Extension developers can create their own store for managing state data by extending the <code>ExtensionStore</code> class.
This guide shows how to create a store for the <a href="../renderer-extension#apppreferences"><code>appPreferences</code></a> guide example, which demonstrates how to add a custom preference to the <strong>Preferences</strong> page.
The preference is a simple boolean that indicates whether or not something is enabled.
However, in the example, the enabled state is not stored anywhere, and it reverts to the default when Lens is restarted.</p>
<p>The following example code creates a store for the <code>appPreferences</code> guide example:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Store</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">observable</span><span class="p">,</span> <span class="nx">toJS</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;mobx&quot;</span><span class="p">;</span>
@@ -922,11 +937,27 @@
<span class="k">export</span> <span class="kd">const</span> <span class="nx">examplePreferencesStore</span> <span class="o">=</span> <span class="nx">ExamplePreferencesStore</span><span class="p">.</span><span class="nx">getInstance</span><span class="o">&lt;</span><span class="nx">ExamplePreferencesStore</span><span class="o">&gt;</span><span class="p">();</span>
</code></pre></div>
<p>First, our example defines the extension's data model using the simple <code>ExamplePreferencesModel</code> type. This has a single field, <code>enabled</code>, which represents the preference's state. <code>ExamplePreferencesStore</code> extends <code>Store.ExtensionStore</code>, which is based on the <code>ExamplePreferencesModel</code>. The <code>enabled</code> field is added to the <code>ExamplePreferencesStore</code> class to hold the "live" or current state of the preference. Note the use of the <code>observable</code> decorator on the <code>enabled</code> field. The <a href="../renderer-extension#apppreferences"><code>appPreferences</code></a> guide example uses <a href="https://mobx.js.org/README.html">MobX</a> for the UI state management, ensuring the checkbox updates when it's activated by the user.</p>
<p>Next, our example implements the constructor and two abstract methods. The constructor specifies the name of the store (<code>"example-preferences-store"</code>) and the default (initial) value for the preference state (<code>enabled: false</code>). Lens internals call the <code>fromStore()</code> method when the store loads. It gives the extension the opportunity to retrieve the stored state data values based on the defined data model. The <code>enabled</code> field of the <code>ExamplePreferencesStore</code> is set to the value from the store whenever <code>fromStore()</code> is invoked. The <code>toJSON()</code> method is complementary to <code>fromStore()</code>. It is called when the store is being saved.
<code>toJSON()</code> must provide a JSON serializable object, facilitating its storage in JSON format. The <code>toJS()</code> function from <a href="https://mobx.js.org/README.html"><code>mobx</code></a> is convenient for this purpose, and is used here.</p>
<p>Finally, <code>examplePreferencesStore</code> is created by calling <code>ExamplePreferencesStore.getInstance&lt;ExamplePreferencesStore&gt;()</code>, and exported for use by other parts of the extension. Note that <code>examplePreferencesStore</code> is a singleton. Calling this function again will not create a new store.</p>
<p>The following example code, modified from the <a href="../renderer-extension#apppreferences"><code>appPreferences</code></a> guide demonstrates how to use the extension store. <code>examplePreferencesStore</code> must be loaded in the main process, where loaded stores are automatically saved when exiting Lens. This can be done in <code>./main.ts</code>:</p>
<p>First, our example defines the extension's data model using the simple <code>ExamplePreferencesModel</code> type.
This has a single field, <code>enabled</code>, which represents the preference's state.
<code>ExamplePreferencesStore</code> extends <code>Store.ExtensionStore</code>, which is based on the <code>ExamplePreferencesModel</code>.
The <code>enabled</code> field is added to the <code>ExamplePreferencesStore</code> class to hold the "live" or current state of the preference.
Note the use of the <code>observable</code> decorator on the <code>enabled</code> field.
The <a href="../renderer-extension#apppreferences"><code>appPreferences</code></a> guide example uses <a href="https://mobx.js.org/README.html">MobX</a> for the UI state management, ensuring the checkbox updates when it's activated by the user.</p>
<p>Next, our example implements the constructor and two abstract methods.
The constructor specifies the name of the store (<code>"example-preferences-store"</code>) and the default (initial) value for the preference state (<code>enabled: false</code>).
Lens internals call the <code>fromStore()</code> method when the store loads.
It gives the extension the opportunity to retrieve the stored state data values based on the defined data model.
The <code>enabled</code> field of the <code>ExamplePreferencesStore</code> is set to the value from the store whenever <code>fromStore()</code> is invoked.
The <code>toJSON()</code> method is complementary to <code>fromStore()</code>.
It is called when the store is being saved.
<code>toJSON()</code> must provide a JSON serializable object, facilitating its storage in JSON format.
The <code>toJS()</code> function from <a href="https://mobx.js.org/README.html"><code>mobx</code></a> is convenient for this purpose, and is used here.</p>
<p>Finally, <code>examplePreferencesStore</code> is created by calling <code>ExamplePreferencesStore.getInstance&lt;ExamplePreferencesStore&gt;()</code>, and exported for use by other parts of the extension.
Note that <code>examplePreferencesStore</code> is a singleton.
Calling this function again will not create a new store.</p>
<p>The following example code, modified from the <a href="../renderer-extension#apppreferences"><code>appPreferences</code></a> guide demonstrates how to use the extension store.
<code>examplePreferencesStore</code> must be loaded in the main process, where loaded stores are automatically saved when exiting Lens.
This can be done in <code>./main.ts</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensMainExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">examplePreferencesStore</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;./src/example-preference-store&quot;</span><span class="p">;</span>
@@ -937,7 +968,8 @@
<span class="p">}</span>
</code></pre></div>
<p>Here, <code>examplePreferencesStore</code> loads with <code>examplePreferencesStore.loadExtension(this)</code>, which is conveniently called from the <code>onActivate()</code> method of <code>ExampleMainExtension</code>.
Similarly, <code>examplePreferencesStore</code> must load in the renderer process where the <code>appPreferences</code> are handled. This can be done in <code>./renderer.ts</code>:</p>
Similarly, <code>examplePreferencesStore</code> must load in the renderer process where the <code>appPreferences</code> are handled.
This can be done in <code>./renderer.ts</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">LensRendererExtension</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">ExamplePreferenceHint</span><span class="p">,</span> <span class="nx">ExamplePreferenceInput</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;./src/example-preference&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">examplePreferencesStore</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;./src/example-preference-store&quot;</span><span class="p">;</span>
@@ -960,7 +992,8 @@ Similarly, <code>examplePreferencesStore</code> must load in the renderer proces
<span class="p">];</span>
<span class="p">}</span>
</code></pre></div>
<p>Again, <code>examplePreferencesStore.loadExtension(this)</code> is called to load <code>examplePreferencesStore</code>, this time from the <code>onActivate()</code> method of <code>ExampleRendererExtension</code>. There is no longer the need for the <code>preference</code> field in the <code>ExampleRendererExtension</code> class because the props for <code>ExamplePreferenceInput</code> is now <code>examplePreferencesStore</code>.
<p>Again, <code>examplePreferencesStore.loadExtension(this)</code> is called to load <code>examplePreferencesStore</code>, this time from the <code>onActivate()</code> method of <code>ExampleRendererExtension</code>.
There is no longer the need for the <code>preference</code> field in the <code>ExampleRendererExtension</code> class because the props for <code>ExamplePreferenceInput</code> is now <code>examplePreferencesStore</code>.
<code>ExamplePreferenceInput</code> is defined in <code>./src/example-preference.tsx</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span> <span class="p">{</span> <span class="nx">Component</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;@k8slens/extensions&quot;</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">observer</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&quot;mobx-react&quot;</span><span class="p">;</span>
@@ -996,7 +1029,7 @@ Similarly, <code>examplePreferencesStore</code> must load in the renderer proces
<span class="p">}</span>
</code></pre></div>
<p>The only change here is that <code>ExamplePreferenceProps</code> defines its <code>preference</code> field as an <code>ExamplePreferencesStore</code> type.
Everything else works as before, except that now the <code>enabled</code> state persists across Lens restarts because it is managed by the
Everything else works as before, except that now the <code>enabled</code> state persists across Lens restarts because it is managed by the
<code>examplePreferencesStore</code>.</p>
@@ -652,6 +652,18 @@
</li>
<li class="md-nav__item">
<a href="../protocol-handlers/" class="md-nav__link">
Protocol Handlers
</a>
</li>
</ul>
</nav>
</li>
@@ -944,13 +956,13 @@ The result is a more declarative state management style, rather than React's nat
</a>
<a href="../../testing-and-publishing/testing/" class="md-footer-nav__link md-footer-nav__link--next" rel="next">
<a href="../protocol-handlers/" class="md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-footer-nav__title">
<div class="md-ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Testing Extensions
Protocol Handlers
</div>
</div>
<div class="md-footer-nav__button md-icon">