1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

merge master

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen 2020-11-18 14:46:30 +02:00
commit 5b0efe2c86
372 changed files with 37735 additions and 4427 deletions

View File

@ -1,6 +1,5 @@
variables:
YARN_CACHE_FOLDER: $(Pipeline.Workspace)/.yarn
AZURE_CACHE_FOLDER: $(Pipeline.Workspace)/.azure-cache
pr:
- master
- releases/*
@ -29,14 +28,20 @@ jobs:
inputs:
versionSpec: $(node_version)
displayName: Install Node.js
- task: CacheBeta@0
- task: Cache@2
inputs:
key: yarn | $(Agent.OS) | yarn.lock
restoreKeys: |
yarn | "$(Agent.OS)"
yarn
path: $(YARN_CACHE_FOLDER)
cacheHitVar: CACHE_RESTORED
displayName: Cache Yarn packages
- script: make install-deps
- script: make node_modules
displayName: Install dependencies
- script: make build-npm
displayName: Generate npm package
- script: make -j2 build-extensions
displayName: Build bundled extensions
- script: make integration-win
displayName: Run integration tests
- script: make test-extensions
@ -63,21 +68,24 @@ jobs:
inputs:
versionSpec: $(node_version)
displayName: Install Node.js
- task: CacheBeta@0
- task: Cache@2
inputs:
key: cache | $(Agent.OS) | yarn.lock
path: $(AZURE_CACHE_FOLDER)
cacheHitVar: CACHE_RESTORED
key: yarn | $(Agent.OS) | yarn.lock
restoreKeys: |
yarn | "$(Agent.OS)"
yarn
path: $(YARN_CACHE_FOLDER)
displayName: Cache Yarn packages
- bash: |
mkdir -p "$YARN_CACHE_FOLDER"
tar -xzf "$AZURE_CACHE_FOLDER/yarn-cache.tar.gz" -C /
displayName: "Unpack cache"
condition: eq(variables.CACHE_RESTORED, 'true')
- script: make install-deps
- script: make node_modules
displayName: Install dependencies
- script: make build-npm
displayName: Generate npm package
- script: make -j2 build-extensions
displayName: Build bundled extensions
- script: make test
displayName: Run tests
- script: make test-extensions
displayName: Run In-tree Extension tests
- script: make integration-mac
displayName: Run integration tests
- script: make test-extensions
@ -91,10 +99,6 @@ jobs:
CSC_LINK: $(CSC_LINK)
CSC_KEY_PASSWORD: $(CSC_KEY_PASSWORD)
GH_TOKEN: $(GH_TOKEN)
- bash: |
mkdir -p "$AZURE_CACHE_FOLDER"
tar -czf "$AZURE_CACHE_FOLDER/yarn-cache.tar.gz" "$YARN_CACHE_FOLDER"
displayName: Pack cache
- job: Linux
pool:
vmImage: ubuntu-16.04
@ -110,25 +114,26 @@ jobs:
inputs:
versionSpec: $(node_version)
displayName: Install Node.js
- task: CacheBeta@0
- task: Cache@2
inputs:
key: cache | $(Agent.OS) | yarn.lock
path: $(AZURE_CACHE_FOLDER)
cacheHitVar: CACHE_RESTORED
key: yarn | $(Agent.OS) | yarn.lock
restoreKeys: |
yarn | "$(Agent.OS)"
yarn
path: $(YARN_CACHE_FOLDER)
displayName: Cache Yarn packages
- bash: |
mkdir -p "$YARN_CACHE_FOLDER"
tar -xzf "$AZURE_CACHE_FOLDER/yarn-cache.tar.gz" -C /
displayName: "Unpack cache"
condition: eq(variables.CACHE_RESTORED, 'true')
- script: make install-deps
- script: make node_modules
displayName: Install dependencies
- script: make test-extensions
displayName: Run In-tree Extension tests
- script: make lint
displayName: Lint
- script: make build-npm
displayName: Generate npm package
- script: make -j2 build-extensions
displayName: Build bundled extensions
- script: make test
displayName: Run tests
- script: make test-extensions
displayName: Run In-tree Extension tests
- bash: |
sudo apt-get update
sudo apt-get install libgconf-2-4 conntrack -y
@ -160,7 +165,3 @@ jobs:
condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))"
env:
NPM_TOKEN: $(NPM_TOKEN)
- bash: |
mkdir -p "$AZURE_CACHE_FOLDER"
tar -czf "$AZURE_CACHE_FOLDER/yarn-cache.tar.gz" "$YARN_CACHE_FOLDER"
displayName: Pack cache

View File

@ -1,5 +1,5 @@
module.exports = {
ignorePatterns: ["src/extensions/npm/extensions/api.d.ts"],
ignorePatterns: ["src/extensions/npm/extensions/dist/**/*"],
overrides: [
{
files: [

View File

@ -1,17 +0,0 @@
---
area/ui:
- src/renderer/**/*
area/test:
- integration/**/*
- __mocks__/**/*
area/extension:
- extensions/**/*
- src/extensions/**/*
area/documentation:
- README.md
- docs/**/*
area/ci:
- .github/workflows/**/*
- .azure-pipelines.yml
dependencies:
- yarn.lock

View File

@ -1,15 +0,0 @@
---
name: "Pull Request Labeler"
on:
- pull_request
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v2
if: github.repository == 'lensapp/lens'
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: .github/labeler-config.yml

64
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: Publish docs via GitHub Pages
on:
push:
branches:
- master
release:
types:
- published
jobs:
build:
name: Deploy docs
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- name: Set up Python 3.7
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install git+https://${{ secrets.GH_TOKEN }}@github.com/lensapp/mkdocs-material-insiders.git
pip install mike
- name: Checkout Release from lens
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: git config
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Using Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Generate Extensions API Reference using typedocs
run: |
yarn install
yarn typedocs-extensions-api
- name: mkdocs deploy master
if: contains(github.ref, 'refs/heads/master')
run: |
mike deploy --push master
- name: Get the release version
if: contains(github.ref, 'refs/tags/v') # && !github.event.release.prerelease (generate pre-release docs until Lens 4.0.0 is GA, see #1408)
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
- name: mkdocs deploy new release
if: contains(github.ref, 'refs/tags/v') # && !github.event.release.prerelease (generate pre-release docs until Lens 4.0.0 is GA, see #1408)
run: |
mike deploy --push --update-aliases ${{ steps.get_version.outputs.VERSION }} latest
mike set-default --push ${{ steps.get_version.outputs.VERSION }}

View File

@ -0,0 +1,38 @@
name: Delete Documentation Version
on:
workflow_dispatch:
inputs:
version:
description: 'Version string to be deleted (e.g."v0.0.1")'
required: true
jobs:
build:
name: Delete docs Version
runs-on: ubuntu-latest
steps:
- name: Set up Python 3.7
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install git+https://${{ secrets.GH_TOKEN }}@github.com/lensapp/mkdocs-material-insiders.git
pip install mike
- name: Checkout Release from lens
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: git config
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: mkdocs delete version
run: |
mike delete --push ${{ github.event.inputs.version }}

View File

@ -0,0 +1,38 @@
name: Update Default Documentation Version
on:
workflow_dispatch:
inputs:
version:
description: 'Version string to be default (e.g."v0.0.1")'
required: true
jobs:
build:
name: Update default docs Version
runs-on: ubuntu-latest
steps:
- name: Set up Python 3.7
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install git+https://${{ secrets.GH_TOKEN }}@github.com/lensapp/mkdocs-material-insiders.git
pip install mike
- name: Checkout Release from lens
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: git config
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: mkdocs update default version
run: |
mike set-default --push ${{ github.event.inputs.version }}

1
.gitignore vendored
View File

@ -15,3 +15,4 @@ src/extensions/*/*.d.ts
types/extension-api.d.ts
types/extension-renderer-api.d.ts
extensions/*/dist
docs/extensions/api

View File

@ -1,4 +1,7 @@
EXTENSIONS_DIR = ./extensions
extensions = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir})
extension_node_modules = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir}/node_modules)
extension_dists = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir}/dist)
ifeq ($(OS),Windows_NT)
DETECTED_OS := Windows
@ -6,78 +9,126 @@ else
DETECTED_OS := $(shell uname)
endif
.PHONY: init dev build test clean
init: install-deps download-bins compile-dev
echo "Init done"
download-bins:
binaries/client:
yarn download-bins
install-deps:
yarn install --frozen-lockfile
node_modules:
yarn install --frozen-lockfile --verbose
yarn check --verify-tree --integrity
static/build/LensDev.html:
yarn compile:renderer
.PHONY: compile-dev
compile-dev:
yarn compile:main --cache
yarn compile:renderer --cache
dev:
ifeq ("$(wildcard static/build/main.js)","")
make init
endif
.PHONY: dev
dev: node_modules binaries/client build-extensions static/build/LensDev.html
yarn dev
.PHONY: lint
lint:
yarn lint
test: download-bins
.PHONY: test
test: binaries/client
yarn test
.PHONY: integration-linux
integration-linux: build-extension-types build-extensions
yarn build:linux
yarn integration
.PHONY: integration-mac
integration-mac: build-extension-types build-extensions
yarn build:mac
yarn integration
.PHONY: integration-win
integration-win: build-extension-types build-extensions
yarn build:win
yarn integration
.PHONY: test-app
test-app:
yarn test
build: install-deps download-bins build-extensions
.PHONY: build
build: node_modules binaries/client build-extensions
ifeq "$(DETECTED_OS)" "Windows"
yarn dist:win
else
yarn dist
endif
build-extensions:
$(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), $(MAKE) -C $(dir) build;)
$(extension_node_modules):
cd $(@:/node_modules=) && npm install --no-audit --no-fund
test-extensions:
$(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), $(MAKE) -C $(dir) test;)
$(extension_dists): src/extensions/npm/extensions/dist
cd $(@:/dist=) && npm run build
build-npm: build-extension-types
yarn npm:fix-package-version
.PHONY: build-extensions
build-extensions: $(extension_node_modules) $(extension_dists)
build-extension-types:
.PHONY: test-extensions
test-extensions: $(extension_node_modules)
$(foreach dir, $(extensions), (cd $(dir) && npm run test || exit $?);)
.PHONY: copy-extension-themes
copy-extension-themes:
mkdir -p src/extensions/npm/extensions/dist/src/renderer/themes/
cp $(wildcard src/renderer/themes/*.json) src/extensions/npm/extensions/dist/src/renderer/themes/
src/extensions/npm/extensions/__mocks__:
cp -r __mocks__ src/extensions/npm/extensions/
src/extensions/npm/extensions/dist:
yarn compile:extension-types
.PHONY: build-npm
build-npm: build-extension-types copy-extension-themes src/extensions/npm/extensions/__mocks__
yarn npm:fix-package-version
.PHONY: build-extension-types
build-extension-types: src/extensions/npm/extensions/dist
.PHONY: publish-npm
publish-npm: build-npm
npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}"
cd src/extensions/npm/extensions && npm publish --access=public
clean:
.PHONY: clean-extensions
clean-extensions:
ifeq "$(DETECTED_OS)" "Windows"
if exist binaries\client del /s /q binaries\client\*.*
$(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), if exist $(dir)\dist del /s /q $(dir)\dist)
$(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), if exist $(dir)\node_modules del /s /q $(dir)\node_modules)
else
$(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), rm -rf $(dir)/dist)
$(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), rm -rf $(dir)/node_modules)
endif
.PHONY: clean-npm
clean-npm:
ifeq "$(DETECTED_OS)" "Windows"
if exist src\extensions\npm\extensions\dist del /s /q src\extensions\npm\extensions\dist
if exist src\extensions\npm\extensions\__mocks__ del /s /q src\extensions\npm\extensions\__mocks__
if exist src\extensions\npm\extensions\node_modules del /s /q src\extensions\npm\extensions\node_modules
else
rm -rf src/extensions/npm/extensions/dist
rm -rf src/extensions/npm/extensions/__mocks__
rm -rf src/extensions/npm/extensions/node_modules
endif
.PHONY: clean
clean: clean-npm clean-extensions
ifeq "$(DETECTED_OS)" "Windows"
if exist binaries\client del /s /q binaries\client
if exist dist del /s /q dist\*.*
if exist static\build del /s /q static\build\*.*
else
rm -rf binaries/client/*
rm -rf binaries/client
rm -rf dist/*
rm -rf static/build/*
endif

View File

@ -4,20 +4,24 @@
[![Releases](https://img.shields.io/github/downloads/lensapp/lens/total.svg)](https://github.com/lensapp/lens/releases)
[![Chat on Slack](https://img.shields.io/badge/chat-on%20slack-blue.svg?logo=slack&longCache=true&style=flat)](https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI)
Lens is the only IDE youll ever need to take control of your Kubernetes clusters. It is a standalone application for MacOS, Windows and Linux operating systems. It is open source and free.
Worlds most popular Kubernetes IDE provides a simplified, consistent entry point for developers, testers, integrators, and DevOps, to ship code faster at scale. Lens is the only IDE youll ever need to take control of your Kubernetes clusters. It is a standalone application for MacOS, Windows and Linux operating systems. Lens is an open source project and free!
[![Screenshot](.github/screenshot.png)](https://youtu.be/04v2ODsmtIs)
## What makes Lens special?
* Amazing usability and end-user experience
* Multi cluster management: support for hundreds of clusters
* Unified, secure, multi-cluster management on any platform: support for hundreds of clusters
* Standalone application: no need to install anything in-cluster
* Lens installs anywhere, elimanting the need to wrangle credentials
* Real-time cluster state visualization
* Resource utilization charts and trends with history powered by built-in Prometheus
* Terminal access to nodes and containers
* Smart terminal access to nodes and containers
* Clusters can be local (e.g. minikube) or external (e.g. EKS, GKE, AKS)
* Performance optimized to handle massive clusters (tested with a cluster running 25k pods)
* Full support for Kubernetes RBAC
* RBAC security is preserved, as Lens uses the standard Kubernetes API
* Lens Extensions are used to add custom visualizations and functionality to accelerate development workflows for all the technologies and services that integrate with Kubernetes
* Helm package deployment: Browse and deploy Helm charts with one click-Install
## Installation
@ -32,7 +36,6 @@ brew cask install lens
> Prerequisites: Nodejs v12, make, yarn
* `make init` - initial compilation, installing deps, etc.
* `make dev` - builds and starts the app
* `make test` - run tests
@ -40,19 +43,31 @@ brew cask install lens
Allows for faster separate re-runs of some of the more involved processes:
1. `yarn dev:main` compiles electron's main process app part
1. `yarn dev:renderer` compiles electron's renderer app part
1. `yarn dev:extension-types` compile declaration types for `@k8slens/extensions`
1. `yarn dev:main` compiles electron's main process app part
1. `yarn dev:renderer` compiles electron's renderer app part
1. `yarn dev:extension-types` compile declaration types for `@k8slens/extensions`
1. `yarn dev-run` runs app in dev-mode and auto-restart when main process file has changed
## Development (documentation)
Run a local instance of `mkdocs serve` in a docker container for developing the Lens Documentation.
> Prerequisites: docker, yarn
* `yarn mkdocs-serve-local` - local build and serve of mkdocs with auto update enabled
Go to [localhost:8000](http://127.0.0.1:8000)
## Developer's ~~RTFM~~ recommended list:
- [TypeScript](https://www.typescriptlang.org/docs/home.html) (front-end/back-end)
- [TypeScript](https://www.typescriptlang.org/docs/home.html) (front-end/back-end)
- [ReactJS](https://reactjs.org/docs/getting-started.html) (front-end, ui)
- [MobX](https://mobx.js.org/) (app-state-management, back-end/front-end)
- [ElectronJS](https://www.electronjs.org/docs) (chrome/node)
- [NodeJS](https://nodejs.org/dist/latest-v12.x/docs/api/) (api docs)
## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/lensapp/lens.

1
docs/CNAME Normal file
View File

@ -0,0 +1 @@
docs.k8slens.dev

21
docs/README.md Normal file
View File

@ -0,0 +1,21 @@
# Overview
Lens is the most powerful Kubernetes IDE on the market. It is a standalone application, and it is available on macOS, Windows, and Linux. Some of the benefits of using Lens include:
* Confidence that your clusters are properly setup and configured.
* Increased visibility, real time statistics, log streams, and hands-on troubleshooting capabilities.
* The ability to work with your clusters quickly and easily, radically improving productivity and the speed of business.
Watch this introductory video to see Lens in action:
[![Screenshot](img/lens-intro-video-screenshot.png)](https://youtu.be/04v2ODsmtIs)
**Note:** Use CTRL+click (on Windows and Linux) or CMD+click (on MacOS) to open the above in a new tab
## Downloading Lens
[Download Lens](https://github.com/lensapp/lens/releases) for macOS, Windows, or Linux.
## Quick Start
Get up and running quickly by learning to [add clusters](clusters/adding-clusters.md).

View File

@ -0,0 +1,16 @@
# Adding Clusters
Add clusters by clicking the **Add Cluster** button in the left-side menu.
1. Click the **Add Cluster** button (indicated with a '+' icon).
2. Enter the path to your kubeconfig file. You'll need to have a kubeconfig file for the cluster you want to add. You can either browse for the path from the file system or or enter it directly.
Selected [cluster contexts](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#context) are added as a separate item in the left-side cluster menu to allow you to operate easily on multiple clusters and/or contexts.
**NOTE**: Any cluster that you added manually will not be merged into your kubeconfig file.
![Add Cluster](images/add-cluster.png)
For more information on kubeconfig see [Kubernetes docs](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/).
To see your currently-enabled config with `kubectl`, enter `kubectl config view --minify --raw` in your terminal.

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

@ -0,0 +1,12 @@
# Removing Clusters
Remove Lens clusters using the context menu that appears when you right-click the cluster in the left-side menu that you want to remove.
To remove a cluster from your cluster list:
1. Right-click the name of the cluster in the left-side menu that you want to remove.
2. Click **Remove**.
**NOTE**: This will only remove the cluster from your Lens cluster list. It will not affect your actual Kubernetes cluster or its configuration.
![Remove Cluster](images/remove-cluster.png)

75
docs/clusters/settings.md Normal file
View File

@ -0,0 +1,75 @@
# Settings
It is easy to configure Lens Clusters to your liking through its various settings.
1. Right-click the name of the cluster in the left-side menu that you want to open the settings for.
2. Click **Settings**.
![Cluster settings](images/cluster-context-menu.png)
## Status
Overview of the cluster status
### Cluster Status
Cluster status information including the detected distribution, kernel version, API endpoint, and online status
![Cluster settings status](images/cluster-settings-status.png)
## General
General cluster settings
### Cluster Name
The cluster name is inheritated by default from the kubeconfig file. Change the cluster name to another value by updating it here. Note that doing so does not update your kubeconfig file.
### Workspace
This is the Lens workspace that the cluster is associated with. Change workspaces by selecting a different workspace from the dropdown menu. Create a new workspace by clicking **workspace** in "Define cluster workspace" above the dropdown menu. This option will take you the workspaces editor. Create a new workspace and then navigate back to cluster settings.
### Cluster Icon
Lens randomly generates an icon to associate with each newly-created cluster. Use this setting to choose your own icon.
### HTTP Proxy
Some users will need to define an HTTP proxy for communicating with the Kubernetes API. Use this setting to do so.
### Prometheus
Lens can be configured to query a Prometheus server installed in the cluster. Select a query format by choosing either to auto-detect or from the following configurations:
* Lens
* Helm Operator
* Prometheus Operator
* Stacklight
To learn more about custom Prometheus configurations, please refer to this [guide](https://github.com/lensapp/lens/blob/master/troubleshooting/custom-prometheus.md).
### Working Directory
Use this field to set the terminal working directory. The default is `$HOME`.
![Cluster settings general](images/cluster-settings-general.png)
## Features
Additional Lens features that can be installed by the user
### Metrics
Enable timeseries data visualization (Prometheus stack) for your cluster. Install this only if you don't have existing Prometheus stack installed.
### User Mode
User Mode feature enables non-admin users to see namespaces they have access to. This is achieved by configuring RBAC rules so that every authenticated user is granted to list namespaces.
![Cluster settings features](images/cluster-settings-features.png)
## Removal
Use this setting to remove the current cluster.
![Cluster settings removal](images/cluster-settings-removal.png)

View File

@ -0,0 +1,17 @@
# Contributing
There are multiple ways you can contribute to Lens. Even if you are not a developer, you can still contribute. We are always looking for assistance with creating or updating documentation, testing the application, reporting, and troubleshooting issues.
Here are some ways you can contribute!
* [Development](./development.md) Help make Lens better.
* [Maintaining the Project](./maintainers.md) Become a community maintainer and help us maintain the project.
* [Extension Development](../extensions) Add integrations via Lens Extensions.
* [Documentation](./documentation.md) Help improve Lens documentation.
* [Promotion](./promotion.md) Show your support, be an ambassador to Lens, write blogs, and make videos!
If you are an influencer, blogger, or journalist, feel free to [spread the word](./promotion.md)!
## Code of Conduct
This project adheres to the [Contributor Covenant](https://www.contributor-covenant.org/) code of conduct. By participating and contributing to Lens, you are expected to uphold this code. Please report unacceptable behaviour to info@k8slens.dev.

View File

@ -0,0 +1,3 @@
# Development
TBD

View File

@ -0,0 +1,22 @@
# Documentation
We are glad to see you're interested in contributing to the Lens documentation. If this is the first Open Source project you've contributed to, we strongly suggest reading GitHub's excellent guide: [How to Contribute to Open Source](https://opensource.guide/how-to-contribute).
## Finding Documentation Issues to Work On
You can find a list of open documentation-related issues [here](https://github.com/lensapp/lens/issues?q=is%3Aopen+is%3Aissue+label%3Aarea%2Fdocumentation). When you find something you would like to work on:
1. Express your interest to start working on an issue via comments.
2. One of the maintainers will assign the issue for you.
3. You can start working on the issue. When you're done, simply submit a pull request.
## Requirements for Documentation Pull Requests
When you create a new pull request, we expect some requirements to be met.
* Follow this naming convention for Pull Requests:
* When adding new documentation, add `New Documentation:` before the title. E.g. `New Documentation: Getting Started`
* When fixing documentation, add `Fix Documentation:` before the title. E.g. `Fix Documentation: Getting Started`
* When updating documentation, add `Update Documentation:` before the title. E.g. `Update Documentation: Getting Started`
* If your Pull Request closes an issue, you must write `Closes #ISSUE_NUMBER` where the ISSUE_NUMBER is the number in the end of the link url or the relevent issue. This will link your pull request to the issue, and when it is merged, the issue will close.
* For each pull request made, we run tests to check if there are any broken links, the markdown formatting is valid, and the linter is passing.

View File

@ -0,0 +1,17 @@
# Maintainers
We are looking for community maintainers for the Lens project. Maintainers will be added to a special team with write permissions. These permissions consist of opening, closing, tagging, and editing issues and pull requests, as well as creating and deleting non-protected branches.
The responsibilities of a community maintainer are listed below.
## Issues Triage
* **Labeling Issues:** Label issues accordingly.
* **Finding Duplicates:** Finding and closing duplicate issues.
* **Doing First Level Contact:** Getting more information on the issues (like version number or asking for clarification) if needed.
* **Closing Irrelevant Issues:** Closing issues that are determined irrelevant, no longer needed, not relevant to the project and/or don't follow the issues guidelines.
## Help with Contributions
* **Help Manage Pull Requests:** Help the author of the pull request with any problems.
* **Contributing:** Create pull requests to help maintain and drive the project forward.

View File

@ -0,0 +1,27 @@
# Promotion
Help promote Lens! If you are not a developer (or even if you are), you can still contribute to the project a lot by helping us to promote it. As we are a free and open source project, the community is our most important asset. Here are some ways that you can help the project continue to grow.
## Follow, Like, Recommend, Favorite, Vote and Star Us
There are many sites where you can vote, recommend, favorite, and star us.
* [Twitter](https://twitter.com/k8slens) - Like, comment and retweet our posts, and follow us on Twitter.
* [Medium](https://medium.com/k8slens) - Give claps to our articles and follow us on Medium.
* [GitHub](https://github.com/lensapp/lens) - Become a stargazer on GitHub.
* [StackShare](https://stackshare.io/lens) - Indicate you are using Lens and follow us on StackShare.
* [Reddit](https://www.reddit.com/search/?q=lens%20kubernetes&sort=new) - Upvote and be a Lens ambassador by participating in relevant discussions on Reddit.
* [Hacker News](https://hn.algolia.com/?dateRange=all&page=0&prefix=false&query=lens%20kubernetes&sort=byDate&type=story) - Upvote and be a Lens ambassador by participating in relevant discussions on Hacker News.
## Write Blogs or Make Videos About Us
Here are some nice blog posts and videos about our project for you to get some inspiration:
* [Onboard AWS EKS Cluster on Lens(Kubernetes IDE)](https://dev.to/himwad05/onboard-aws-eks-cluster-on-lens-kubernetes-ide-492l)
* [Using Lens to Manage All Your Kubernetes Cluster](https://medium.com/@magicmagnate/using-lens-to-manage-all-your-kubernetes-cluster-c1ef88fdb476)
* [Kontena Lens - Beautiful Kubernetes UI](https://www.youtube.com/watch?v=YGgaiGdYfdI)
* [Gerenciando Kubernetes com Lens e Octant](https://www.youtube.com/watch?v=h9ZqDelJLQQ)
* [Walkthrough of Kubernetes IDE - Lens](https://www.youtube.com/watch?v=602aHZSdEfY)
* [LENS - Interfaz Gráfica para Kubernetes en 1 PASO.](https://www.youtube.com/watch?v=DFMKcR4BqwM)
Psst... If you have created some content around Lens, let us know!

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block analytics %}
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-90E1JB4HW4"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-90E1JB4HW4');
</script>
{% endblock %}

43
docs/extensions/README.md Normal file
View File

@ -0,0 +1,43 @@
# Lens Extension API
Customize and enhance the Lens experience with the Lens Extension API. Use the extension API to create menus or page content. The same extension API was used to create many of Lens's core features.
This documentation describes:
* How to build, run, test, and publish an extension.
* How to take full advantage of the Lens Extension API.
* Where to find [guides](guides/README.md) and [code samples](https://github.com/lensapp/lens-extension-samples) to help get you started.
## What Extensions Can Do
Here are some examples of what you can achieve with the Extension API:
* Add custom components & views in the UI - Extending the Lens Workbench
For an overview of the Lens Extension API, refer to the [Common Capabilities](capabilities/common-capabilities.md) page. [Extension Guides Overview](guides/overview.md) also includes a list of code samples and guides that illustrate various ways of using the Lens Extension API.
## How to Build Extensions
Here is what each section of the Lens Extension API docs can help you with:
* **Getting Started** teaches fundamental concepts for building extensions with the Hello World sample.
* **Extension Capabilities** dissects Lens's Extension API into smaller categories and points you to more detailed topics.
* **Extension Guides** includes guides and code samples that explain specific usages of Lens Extension API.
* **Testing and Publishing** includes in-depth guides on various extension development topics, such as testing and publishing extensions.
* **API Reference** contains exhaustive references for the Lens Extension API, Contribution Points, and many other topics.
## What's New
Just like Lens itself, the extension API updates on a monthly cadence, rolling out new features with every release.
Keep up with Lens and the Lens Extension API by reviewing the [release notes](https://github.com/lensapp/lens/releases).
## Looking for Help
If you have questions for extension development, try asking on the [Lens Dev Slack](http://k8slens.slack.com/). It's a public chatroom for Lens developers, where Lens team members chime in from time to time.
To provide feedback on the documentation or issues with the Lens Extension API, create new issues at [lensapp/lens](https://github.com/lensapp/lens/issues). Please use the labels `area/documentation` and/or `area/extension`.
## Downloading Lens
[Download Lens](https://github.com/lensapp/lens/releases) for macOS, Windows, or Linux.

View File

View File

@ -0,0 +1,130 @@
# Theme Color Reference
You can use theme-based CSS Variables to style an extension according to the active theme.
## Base Colors
- `--blue`: blue color.
- `--magenta`: magenta color.
- `--golden`: gold/yellow color.
- `--halfGray`: gray with some apacity applied.
- `--primary`: Lens brand (blue) color.
- `--colorSuccess`: successfull operations color.
- `--colorOk`: successfull operations (bright version) color.
- `--colorInfo`: informational, in-progress color.
- `--colorError`: critical error color.
- `--colorSoftError`: error color.
- `--colorWarning`: warning color.
- `--colorVague`: soft gray color for notices, hints etc.
- `--colorTerminated`: terminated, closed, stale color.
- `--boxShadow`: semi-transparent box-shadow color.
## Text Colors
- `--textColorPrimary`: foreground text color.
- `--textColorSecondary`: foreground text color for different paragraps, parts of text.
- `--textColorAccent`: foreground text color to highlight its parts.
## Border Colors
- `--borderColor`: border color.
- `--borderFaintColor`: fainted (lighter or darker, which depends on the theme) border color.
## Layout Colors
- `--mainBackground`: main background color for the app.
- `--contentColor`: background color for panels contains some data.
- `--layoutBackground`: background color for layout parts.
- `--layoutTabsBackground`: background color for general tabs.
- `--layoutTabsActiveColor`: foreground color for general tabs.
- `--layoutTabsLineColor`: background color for lines under general tabs.
## Sidebar Colors
- `--sidebarLogoBackground`: background color behind logo in sidebar.
- `--sidebarActiveColor`: foreground color for active menu items in sidebar.
- `--sidebarSubmenuActiveColor`: foreground color for active submenu items in sidebar.
- `--sidebarBackground`: background color for sidebar.
## Button Colors
- `--buttonPrimaryBackground`: button background color for primary actions.
- `--buttonDefaultBackground`: default button background color.
- `--buttonAccentBackground`: accent button background color.
- `--buttonDisabledBackground`: disabled button background color.
## Table Colors
- `--tableBgcStripe`: background color for odd rows in table.
- `--tableBgcSelected`: background color for selected row in table.
- `--tableHeaderBackground`: background color for table header.
- `--tableHeaderBorderWidth`: border width under table header.
- `--tableHeaderBorderColor`: border color for line under table header.
- `--tableHeaderColor`: foreground color for table header.
- `--tableSelectedRowColor`: foreground color for selected row in table.
## Dock Colors
- `--dockHeadBackground`: background color for dock's header.
- `--dockInfoBackground`: background color for dock's info panel.
- `--dockInfoBorderColor`: border color for dock's info panel.
## Helm Chart Colors
- `--helmLogoBackground`: background color for chart logo.
- `--helmImgBackground`: background color for chart image.
- `--helmStableRepo`: background color for stable repo.
- `--helmIncubatorRepo`: background color for incubator repo.
- `--helmDescriptionHr`: Helm chart description separator line color.
- `--helmDescriptionBlockqouteColor`: Helm chart description blockquote color.
- `--helmDescriptionBlockqouteBorder`: Helm chart description blockquote border color.
- `--helmDescriptionBlockquoteBackground`: Helm chart description blockquote background color.
- `--helmDescriptionHeaders`: Helm chart description headers color.
- `--helmDescriptionH6`: Helm chart description header foreground color.
- `--helmDescriptionTdBorder`: Helm chart description table cell border color.
- `--helmDescriptionTrBackground`: Helm chart description table row background color.
- `--helmDescriptionCodeBackground`: Helm chart description code background color.
- `--helmDescriptionPreBackground`: Helm chart description pre background color.
- `--helmDescriptionPreColor`: Helm chart description pre foreground color.
## Terminal Colors
- `--terminalBackground`: Terminal background color.
- `--terminalForeground`: Terminal foreground color.
- `--terminalCursor`: Terminal cursor color.
- `--terminalCursorAccent`: Terminal cursor accent color.
- `--terminalSelection`: Terminal selection background color.
- `--terminalBlack`: Terminal black color.
- `--terminalRed`: Terminal red color.
- `--terminalGreen`: Terminal green color.
- `--terminalYellow`: Terminal yellow color.
- `--terminalBlue`: Terminal blue color.
- `--terminalMagenta`: Terminal magenta color.
- `--terminalCyan`: Terminal cyan color.
- `--terminalWhite`: Terminal white color.
- `--terminalBrightBlack`: Terminal bright black color.
- `--terminalBrightRed`: Terminal bright red color.
- `--terminalBrightGreen`: Terminal bright green color.
- `--terminalBrightYellow`: Terminal bright yellow color.
- `--terminalBrightBlue`: Terminal bright blue color.
- `--terminalBrightMagenta`: Terminal bright magenta color.
- `--terminalBrightCyan`: Terminal bright cyan color.
- `--terminalBrightWhite`: Terminal bright white color.
## Dialog Colors
- `--dialogHeaderBackground`: background color for dialog header.
- `--dialogFooterBackground`: background color for dialog footer.
## Detail Panel (Drawer) Colors
- `--drawerTitleText`: drawer title foreground color.
- `--drawerSubtitleBackground`: drawer subtitle foreground color.
- `--drawerItemNameColor`: foreground color for item name in drawer.
- `--drawerItemValueColor`: foreground color for item value in drawer.
## Misc Colors
- `--logsBackground`: background color for pod logs.
- `--clusterMenuBackground`: background color for cluster menu.
- `--clusterMenuBorderColor`: border color for cluster menu.
- `--clusterSettingsBackground`: background color for cluster settings.
- `--addClusterIconColor`: add cluster button background color.
- `--iconActiveColor`: active cluster icon foreground color.
- `--iconActiveBackground`: active cluster icon background color.
- `--filterAreaBackground`: page filter area (where selected namespaces are lister) background color.
- `--chartStripesColor`: bar chart zebra stripes background color.
- `--chartCapacityColor`: background color for capacity values in bar charts.
- `--pieChartDefaultColor`: default background color for pie chart values.
- `--selectOptionHoveredColor`: foregrond color for selected element in dropdown list.
- `--lineProgressBackground`: background color for progress line.
- `--radioActiveBackground`: background color for active radio buttons.
- `--menuActiveBackground`: background color for active menu items.
In most cases you would only need base, text and some of the layout colors.

View File

@ -0,0 +1,274 @@
# Common Capabilities
Here we will discuss common and important building blocks for your extensions, and explain how you can use them. Almost all extensions use some of these functionalities.
## Main Extension
The main extension runs in the background. It adds app menu items to the Lens UI. In order to see logs from this extension, you need to start Lens from the command line.
### Activate
This extension can register a custom callback that is executed when an extension is activated (started).
``` javascript
import { LensMainExtension } from "@k8slens/extensions"
export default class ExampleMainExtension extends LensMainExtension {
async onActivate() {
console.log("hello world")
}
}
```
### Deactivate
This extension can register a custom callback that is executed when an extension is deactivated (stopped).
``` javascript
import { LensMainExtension } from "@k8slens/extensions"
export default class ExampleMainExtension extends LensMainExtension {
async onDeactivate() {
console.log("bye bye")
}
}
```
### App Menus
This extension can register custom app menus that will be displayed on OS native menus.
Example:
``` typescript
import { LensMainExtension, windowManager } from "@k8slens/extensions"
export default class ExampleMainExtension extends LensMainExtension {
appMenus = [
{
parentId: "help",
label: "Example item",
click() {
windowManager.navigate("https://k8slens.dev");
}
}
]
}
```
## Renderer Extension
The renderer extension runs in a browser context, and is visible in Lens's main window. In order to see logs from this extension you need to check them via **View** > **Toggle Developer Tools** > **Console**.
### Activate
This extension can register a custom callback that is executed when an extension is activated (started).
``` javascript
import { LensRendererExtension } from "@k8slens/extensions"
export default class ExampleExtension extends LensRendererExtension {
async onActivate() {
console.log("hello world")
}
}
```
### Deactivate
This extension can register a custom callback that is executed when an extension is deactivated (stopped).
``` javascript
import { LensRendererExtension } from "@k8slens/extensions"
export default class ExampleMainExtension extends LensRendererExtension {
async onDeactivate() {
console.log("bye bye")
}
}
```
### Global Pages
This extension can register custom global pages (views) to Lens's main window. The global page is a full-screen page that hides all other content from a window.
``` typescript
import React from "react"
import { Component, LensRendererExtension } from "@k8slens/extensions"
import { ExamplePage } from "./src/example-page"
export default class ExampleRendererExtension extends LensRendererExtension {
globalPages = [
{
id: "example",
routePath: "/example",
components: {
Page: ExamplePage,
}
}
]
globalPageMenus = [
{
title: "Example page", // used in icon's tooltip
target: { pageId: "example" }
components: {
Icon: () => <Component.Icon material="arrow"/>,
}
}
]
}
```
### App Preferences
This extension can register custom app preferences. It is responsible for storing a state for custom preferences.
``` typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions"
import { myCustomPreferencesStore } from "./src/my-custom-preferences-store"
import { MyCustomPreferenceHint, MyCustomPreferenceInput } from "./src/my-custom-preference"
export default class ExampleRendererExtension extends LensRendererExtension {
appPreferences = [
{
title: "My Custom Preference",
components: {
Hint: () => <MyCustomPreferenceHint/>,
Input: () => <MyCustomPreferenceInput store={myCustomPreferencesStore}/>
}
}
]
}
```
### Cluster Pages
This extension can register custom cluster pages. These pages are visible in a cluster menu when a cluster is opened.
``` typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions";
import { ExampleIcon, ExamplePage } from "./src/page"
export default class ExampleExtension extends LensRendererExtension {
clusterPages = [
{
routePath: "/extension-example", // optional
exact: true, // optional
components: {
Page: () => <ExamplePage extension={this}/>,
}
}
]
clusterPageMenus = [
{
url: "/extension-example", // optional
title: "Example Extension",
components: {
Icon: ExampleIcon,
}
}
]
}
```
### Cluster Features
This extension can register installable features for a cluster. These features are visible in the "Cluster Settings" page.
``` typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions"
import { MyCustomFeature } from "./src/my-custom-feature"
export default class ExampleExtension extends LensRendererExtension {
clusterFeatures = [
{
title: "My Custom Feature",
components: {
Description: () => {
return (
<span>
Just an example.
</span>
)
}
},
feature: new MyCustomFeature()
}
]
}
```
### Status Bar Items
This extension can register custom icons and text to a status bar area.
``` typescript
import React from "react";
import { Component, LensRendererExtension, Navigation } from "@k8slens/extensions";
export default class ExampleExtension extends LensRendererExtension {
statusBarItems = [
{
item: (
<div className="flex align-center gaps hover-highlight" onClick={() => this.navigate("/example-page")} >
<Component.Icon material="favorite" />
</div>
)
}
]
}
```
### Kubernetes Object Menu Items
This extension can register custom menu items (actions) for specified Kubernetes kinds/apiVersions.
``` typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions";
import { CustomMenuItem, CustomMenuItemProps } from "./src/custom-menu-item"
export default class ExampleExtension extends LensRendererExtension {
kubeObjectMenuItems = [
{
kind: "Node",
apiVersions: ["v1"],
components: {
MenuItem: (props: CustomMenuItemProps) => <CustomMenuItem {...props} />
}
}
]
}
```
### Kubernetes Object Details
This extension can register custom details (content) for specified Kubernetes kinds/apiVersions.
``` typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions";
import { CustomKindDetails, CustomKindDetailsProps } from "./src/custom-kind-details"
export default class ExampleExtension extends LensRendererExtension {
kubeObjectDetailItems = [
{
kind: "CustomKind",
apiVersions: ["custom.acme.org/v1"],
components: {
Details: (props: CustomKindDetailsProps) => <CustomKindDetails {...props} />
}
}
]
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

View File

@ -0,0 +1,150 @@
# Styling an Extension
Lens provides a set of global styles and UI components that can be used by any extension to preserve the look and feel of the application.
## Layout
For layout tasks, Lens uses the [flex.box](https://www.npmjs.com/package/flex.box) library which provides helpful class names to specify some of the [flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) properties. For example, consider the following HTML and its associated CSS properties:
```html
<div className="flex column align-center"></div>
```
```css
div {
display: flex;
flex-direction: column;
align-items: center;
}
```
However, you are free to use any styling technique or framework you like, including [Emotion](https://github.com/emotion-js/emotion) or even plain CSS.
### Layout Variables
There is a set of CSS variables available for for basic layout needs. They are located inside `:root` and are defined in [app.scss](https://github.com/lensapp/lens/blob/master/src/renderer/components/app.scss):
```css
--unit: 8px;
--padding: var(--unit);
--margin: var(--unit);
--border-radius: 3px;
```
These variables are intended to set consistent margins and paddings across components. For example:
```css
.status {
padding-left: calc(var(--padding) * 2);
border-radius: var(--border-radius);
}
```
## Themes
Lens uses two built-in themes defined in [the themes directory](https://github.com/lensapp/lens/tree/master/src/renderer/themes) one light and one dark.
### Theme Variables
When Lens is loaded, it transforms the selected theme's `json` file into a list of [CSS Custom Properties (CSS Variables)](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties). This list then gets injected into the `:root` element so that any of the down-level components can use them.
![CSS vars listed in devtools](images/css-vars-in-devtools.png)
When the user changes the theme, the above process is repeated, and new CSS variables appear, replacing the previous ones.
If you want to preserve Lens's native look and feel, with respect to the lightness or darkness of your extension, you can use the provided variables and built-in Lens components such as `Button`, `Select`, `Table`, and so on.
There is a set of CSS variables available for extensions to use for theming. They are all located inside `:root` and are defined in [app.scss](https://github.com/lensapp/lens/blob/master/src/renderer/components/app.scss):
```css
--font-main: 'Roboto', 'Helvetica', 'Arial', sans-serif;
--font-monospace: Lucida Console, Monaco, Consolas, monospace;
--font-size-small: calc(1.5 * var(--unit));
--font-size: calc(1.75 * var(--unit));
--font-size-big: calc(2 * var(--unit));
--font-weight-thin: 300;
--font-weight-normal: 400;
--font-weight-bold: 500;
```
as well as in [the theme modules](https://github.com/lensapp/lens/tree/master/src/renderer/themes):
```
--blue: #3d90ce;
--magenta: #c93dce;
--golden: #ffc63d;
--halfGray: #87909c80;
--primary: #3d90ce;
--textColorPrimary: #555555;
--textColorSecondary: #51575d;
--textColorAccent: #333333;
--borderColor: #c9cfd3;
--borderFaintColor: #dfdfdf;
--mainBackground: #f1f1f1;
--contentColor: #ffffff;
--layoutBackground: #e8e8e8;
--layoutTabsBackground: #f8f8f8;
--layoutTabsActiveColor: #333333;
--layoutTabsLineColor: #87909c80;
...
```
These variables can be used in the following form: `var(--magenta)`. For example:
```css
.status {
font-size: var(--font-size-small);
background-color: var(--colorSuccess);
}
```
A complete list of themable colors can be found in the [Color Reference](../color-reference).
### Theme Switching
When the light theme is active, the `<body>` element gets a "theme-light" class, or: `<body class="theme-light">`. If the class isn't there, the theme defaults to dark. The active theme can be changed in the **Preferences** page:
![Color Theme](images/theme-selector.png)
Currently, there is no prescribed way of detecting changes to the theme in JavaScript. [This issue](https://github.com/lensapp/lens/issues/1336) has been raised to resolve this problem. In the meantime, you can use a [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) in order to observe the `<body>` element's `class` attribute in order to see if the "theme-light" class gets added to it:
```javascript
...
useEffect(function () {
const observer = new MutationObserver(function (mutations: MutationRecord[]) {
mutations.forEach((mutation: MutationRecord) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
if ((mutation.target as HTMLElement).classList.contains('theme-light')) {
// theme is LIGHT
} else {
// theme is DARK
}
}
});
});
observer.observe(document.body, {
attributes: true,
attributeFilter: ['class'],
});
return function () {
observer.disconnect();
};
}, []); // run once on mount
...
```
## Injected Styles
Every extension is affected by the list of default global styles defined in [app.scss](https://github.com/lensapp/lens/blob/master/src/renderer/components/app.scss). These are basic browser resets and element styles, including setting the `box-sizing` property for every element, default text and background colors, default font sizes, basic heading formatting, and so on.
Extensions may overwrite these defaults if needed. They have low CSS specificity, so overriding them should be fairly easy.
## CSS-in-JS
If an extension uses a system like `Emotion` to work with styles, it can use CSS variables as follows:
```javascript
const Container = styled.div(() => ({
backgroundColor: 'var(--mainBackground)'
}));
```

View File

@ -0,0 +1,97 @@
# Extension Anatomy
In the [previous section](your-first-extension.md) you learned how to create your first extension. In this section you will learn how this extension works under the hood.
The Hello World sample extension does three things:
- Implements `onActivate()` and outputs a message to the console.
- Implements `onDectivate()` and outputs a message to the console.
- Registers `ClusterPage` so that the page is visible in the left-side menu of the cluster dashboard.
Let's take a closer look at our Hello World sample's source code and see how these three things are achieved.
## Extension File Structure
```
.
├── .gitignore // Ignore build output and node_modules
├── Makefile // Config for build tasks that compiles the extension
├── README.md // Readable description of your extension's functionality
├── src
│ └── page.tsx // Extension's additional source code
├── main.ts // Source code for extension's main entrypoint
├── package.json // Extension manifest and dependencies
├── renderer.tsx // Source code for extension's renderer entrypoint
├── tsconfig.json // TypeScript configuration
├── webpack.config.js // Webpack configuration
```
The extension directory contains the extension's entry files and a few configuration files. Three files: `package.json`, `main.ts` and `renderer.tsx` are essential to understanding the Hello World sample extension. We'll look at those first.
### Extension Manifest
Each Lens extension must have a `package.json` file. It contains a mix of Node.js fields, including scripts and dependencies, and Lens-specific fields such as `publisher` and `contributes`. Some of the most-important fields include:
- `name` and `publisher`: Lens uses `@<publisher>/<name>` as a unique ID for the extension. For example, the Hello World sample has the ID `@lensapp-samples/helloworld-sample`. Lens uses this ID to uniquely identify your extension.
- `main`: the extension's entry point run in `main` process.
- `renderer`: the extension's entry point run in `renderer` process.
- `engines.lens`: the minimum version of Lens API that the extension depends upon.
``` javascript
{
"name": "helloworld-sample",
"publisher": "lens-samples",
"version": "0.0.1",
"description": "Lens helloworld-sample",
"license": "MIT",
"homepage": "https://github.com/lensapp/lens-extension-samples",
"engines": {
"lens": "^4.0.0"
},
"main": "dist/main.js",
"renderer": "dist/renderer.js",
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "npm run build --watch"
},
"dependencies": {
"react-open-doodles": "^1.0.5"
},
"devDependencies": {
"@k8slens/extensions": "^4.0.0-alpha.2",
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"@types/react": "^16.9.35",
"@types/node": "^12.0.0",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.11"
}
}
```
## Extension Entry Files
Lens extensions can have two separate entry files. One file is used in the `main` process of the Lens application and the other is used in the `renderer` process. The `main` entry file exports the class that extends `LensMainExtension`, and the `renderer` entry file exports the class that extends `LensRendererExtension`.
Both extension classes have `onActivate` and `onDeactivate` methods. The `onActivate` method is executed when your extension is activated. If you need to initialize something in your extension, this is where such an operation should occur. The `onDeactivate` method gives you a chance to clean up before your extension becomes deactivated. For extensions where explicit cleanup is not required, you don't need to override this method. However, if an extension needs to perform an operation when Lens is shutting down (or if the extension is disabled or uninstalled), this is the method where such an operation should occur.
The Hello World sample extension does not do anything on the `main` process, so we'll focus on the `renderer` process, instead. On the `renderer` entry point, the Hello World sample extension defines the `Cluster Page` object. The `Cluster Page` object registers the `/extension-example` path, and this path renders the `ExamplePage` React component. It also registers the `MenuItem` component that displays the `ExampleIcon` React component and the "Hello World" text in the left-side menu of the cluster dashboard. These React components are defined in the additional `./src/page.tsx` file.
``` typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { ExampleIcon, ExamplePage } from "./page"
import React from "react"
export default class ExampleExtension extends LensRendererExtension {
clusterPages = [
{
routePath: "/extension-example",
components: {
Page: () => <ExamplePage extension={this}/>,
}
}
]
}
```
The Hello World sample extension uses the `Cluster Page` capability, which is just one of the Lens extension API's capabilities. The [Common Capabilities](../capabilities/common-capabilities.md) page will help you home in on the right capabilities to use with your own extensions.

View File

@ -0,0 +1,19 @@
# Extension Development Overview
This is a general overview to how the development of an extension will procede. For building extensions there will be a few things that you should have installed, and some other things that might be of help.
### Required:
- [Node.js](https://www.nodejs.org/en/)
- [Git](https://www.git-scm.com/)
- Some sort of text editor we recommend [VSCode](https://code.visualstudio.com/)
- We use [Webpack](https://www.webpack.js.org/) for compilation. All extension need to be at least compatable with a webpack system.
### Recommended:
All Lens extensions are javascript packages. We recommend that you program in [Typescript](https://www.typescriptlang.org/) because it catches many common errors.
Lens is a standard [Electron](https://www.electronjs.org/) application with both main and renderer processes. An extension is made up of two parts, one for each of Lens's core processes. When an extension is loaded, each part is first loaded and issues a notification that it has been loaded. From there, the extension can start doing is work.
Lens uses [React](https://www.reactjs.org/) as its UI framework and provides some of Lens's own components for reuse with extensions. An extension is resonsible for the lifetime of any resources it spins up. If an extension's main part starts new processes they all must be stopped and cleaned up when the extension is deactivated or unloaded.
See [Your First Extension](your-first-extension.md) to get started.

View File

@ -0,0 +1,18 @@
# Wrapping Up
In [Your First Extension](your-first-extension.md), you learned how to create and run an extension. In [Extension Anatomy](anatomy.md), you learned in detail how a basic extension works. This is just a glimpse into what can be created with Lens extensions. Below are some suggested routes for learning more.
## Extension Capabilities
In this section, you'll find information on common extension capabilities, styling information, and a color reference guide. Determine whether your idea for an extension is doable and get ideas for new extensions by reading through the [Common Capabilities](../capabilities/common-capabilities.md) page.
## Guides and Samples
Here you'll find a collection of sample extensions that you can use as a base to work from. Some of these samples include a detailed guide that explains the source code. You can find all samples and guides in the [lens-extension-samples](https://github.com/lensapp/lens-extension-samples) repository.
## Testing and Publishing
In this section, you can learn:
* How to add [integration tests](../testing-and-publishing/testing.md) to your extension
* How to [publish your extension](../testing-and-publishing/publishing.md)

View File

@ -0,0 +1,87 @@
# Your First Extension
In this topic, you'll learn the basics of building extensions by creating an extension that adds a "Hello World" page to a cluster menu.
## Install the Extension
To install the extension, clone the [Lens Extension samples](https://github.com/lensapp/lens-extension-samples) repository to your local machine:
```sh
git clone https://github.com/lensapp/lens-extension-samples.git
```
Next you need to create a symlink. A symlink connects the directory that Lens will monitor for user-installed extensions to the sample extension. In this case the sample extension is `helloworld-sample`.
### Linux & macOS
```sh
mkdir -p ~/.k8slens/extensions
cd ~/.k8slens/extensions
ln -s lens-extension-samples/helloworld-sample helloworld-sample
```
### Windows
Create the directory that Lens will monitor for user-installed extensions:
```sh
mkdir C:\Users\<user>\.k8slens\extensions -force
cd C:\Users\<user>\.k8slens\extensions
```
If you have administrator rights, you can create symlink to the sample extension in this case `helloworld-sample`:
```sh
cmd /c mklink /D helloworld-sample lens-extension-samples\helloworld-sample
```
Without administrator rights, you need to copy the extensions sample directory into `C:\Users\<user>\.k8slens\extensions`:
```
Copy-Item 'lens-extension-samples\helloworld-sample' 'C:\Users\<user>\.k8slens\extensions\helloworld-sample'
```
## Build the Extension
To build the extension you can use `make` or run the `npm` commands manually:
```sh
cd <lens-extension-samples directory>/helloworld-sample
make build
```
To run the `npm` commands, enter:
```sh
cd <lens-extension-samples directory>/helloworld-sample
npm install
npm run build
```
Optionally, automatically rebuild the extension by watching for changes to the source code. To do so, enter:
```sh
cd <lens-extension-samples directory>/helloworld-sample
npm run dev
```
You must restart Lens for the extension to load. After this initial restart, reload Lens and it will automatically pick up changes any time the extension rebuilds.
With Lens running, either connect to an existing cluster or [create a new one](../../clusters/adding-clusters.md). You will see the "Hello World" page in the left-side cluster menu.
## Develop the Extension
Finally, you'll make a change to the message that our Hello World sample extension displays:
1. Navigate to `<lens-extension-samples directory>/helloworld-sample`.
2. In `page.tsx`, change the message from `HelloWorld!` to `Hello Lens Extensions`.
3. Rebuild the extension. If you used `npm run dev`, the extension will rebuild automatically.
4. Reload the Lens window.
5. Click on the Hello World page.
6. The updated message will appear.
## Next Steps
In the [next topic](anatomy.md), we'll take a closer look at the source code of our Hello World sample.
You can find the source code for this tutorial at: [lensapp/lens-extension-samples](https://github.com/lensapp/lens-extension-samples/tree/master/helloworld-sample). [Extension Guides](../guides/README.md) contains additional samples.

View File

@ -0,0 +1,28 @@
# Extension Guides
The basics of the Lens Extension API are covered in [Your First Extension](../get-started/your-first-extension.md). In this section detailed code guides and samples are used to explain how to use specific Lens Extension APIs.
Each guide or sample will include:
- Clearly commented source code.
- Instructions for running the sample extension.
- Image of the sample extension's appearance and usage.
- Listing of Extension API being used.
- Explanation of Extension API concepts.
## Guides
| Guide | APIs |
| ----- | ----- |
| [Main process extension](main-extension.md) | LensMainExtension |
| [Renderer process extension](renderer-extension.md) | LensRendererExtension |
| [Stores](stores.md) | |
| [Components](components.md) | |
| [KubeObjectListLayout](kube-object-list-layout.md) | |
## Samples
| Sample | APIs |
| ----- | ----- |
[helloworld](https://github.com/lensapp/lens-extension-samples/tree/master/helloworld-sample) | LensMainExtension <br> LensRendererExtension <br> Component.Icon <br> Component.IconProps |
[minikube](https://github.com/lensapp/lens-extension-samples/tree/master/minikube-sample) | LensMainExtension <br> Store.clusterStore <br> Store.workspaceStore |

View File

@ -0,0 +1,76 @@
# Main Extension
The main extension api is the interface to Lens' main process (Lens runs in main and renderer processes). It allows you to access, configure, and customize Lens data, add custom application menu items, and generally run custom code in Lens' main process.
## `LensMainExtension` Class
To create a main extension simply extend the `LensMainExtension` class:
``` typescript
import { LensMainExtension } from "@k8slens/extensions";
export default class ExampleExtensionMain extends LensMainExtension {
onActivate() {
console.log('custom main process extension code started');
}
onDeactivate() {
console.log('custom main process extension de-activated');
}
}
```
There are two methods that you can implement to facilitate running your custom code. `onActivate()` is called when your extension has been successfully enabled. By overriding `onActivate()` you can initiate your custom code. `onDeactivate()` is called when the extension is disabled (typically from the [Lens Extensions Page]()) and when implemented gives you a chance to clean up after your extension, if necessary. The example above simply logs messages when the extension is enabled and disabled. Note that to see standard output from the main process there must be a console connected to it. This is typically achieved by starting Lens from the command prompt.
The following example is a little more interesting in that it accesses some Lens state data and periodically logs the name of the currently active cluster in Lens.
``` typescript
import { LensMainExtension, Store } from "@k8slens/extensions";
const clusterStore = Store.clusterStore
export default class ActiveClusterExtensionMain extends LensMainExtension {
timer: NodeJS.Timeout
onActivate() {
console.log("Cluster logger activated");
this.timer = setInterval(() => {
if (!clusterStore.active) {
console.log("No active cluster");
return;
}
console.log("active cluster is", clusterStore.active.contextName)
}, 5000)
}
onDeactivate() {
clearInterval(this.timer)
console.log("Cluster logger deactivated");
}
}
```
See the [Stores](../stores) guide for more details on accessing Lens state data.
### `appMenus`
The only UI feature customizable in the main extension api is the application menu. Custom menu items can be inserted and linked to custom functionality, such as navigating to a specific page. The following example demonstrates adding a menu item to the Help menu.
``` typescript
import { LensMainExtension } from "@k8slens/extensions";
export default class SamplePageMainExtension extends LensMainExtension {
appMenus = [
{
parentId: "help",
label: "Sample",
click() {
console.log("Sample clicked");
}
}
]
}
```
`appMenus` is an array of objects satisfying the `MenuRegistration` interface. `MenuRegistration` extends React's `MenuItemConstructorOptions` interface. `parentId` is the id of the menu to put this menu item under (todo: is this case sensitive and how do we know what the available ids are?), `label` is the text to show on the menu item, and `click()` is called when the menu item is selected. In this example we simply log a message, but typically you would navigate to a specific page or perform some operation. Pages are associated with the [`LensRendererExtension`](renderer-extension.md) class and can be defined when you extend it.

View File

@ -0,0 +1 @@
# Renderer Extension

View File

@ -0,0 +1,38 @@
# Testing Extensions
## Console.log
Extension developers might find `console.log()` useful for printing out information and errors from extensions. To use `console.log()`, note that Lens is based on Electron, and that Electron has two types of processes: [Main and Renderer](https://www.electronjs.org/docs/tutorial/quick-start#main-and-renderer-processes).
### Renderer Process Logs
In the Renderer process, `console.log()` is printed in the Console in Developer Tools (**View** > **Toggle Developer Tools**).
### Main Process Logs
Viewing the logs from the Main process is a little trickier, since they cannot be printed using Developer Tools.
#### macOS
On macOS, view the Main process logs by running Lens from the terminal:
```bash
/Applications/Lens.app/Contents/MacOS/Lens
```
You can also use [Console.app](https://support.apple.com/en-gb/guide/console/welcome/mac) to view the Main process logs.
#### Linux
On Linux, you can access the Main process logs using the Lens PID. First get the PID:
```bash
ps aux | grep Lens | grep -v grep
```
Then get the Main process logs using the PID:
```bash
tail -f /proc/[pid]/fd/1 # stdout (console.log)
tail -f /proc/[pid]/fd/2 # stdout (console.error)
```

View File

@ -0,0 +1,18 @@
# Extension API Reference
## Modules
* [App](modules/_core_api_app_.md)
* [ClusterFeature](modules/_core_api_cluster_feature_.md)
* [EventBus](modules/_core_api_event_bus_.md)
* [Store](modules/_core_api_stores_.md)
* [Util](modules/_core_api_utils_.md)
* [Component](modules/_renderer_api_components_.md)
* [K8sApi](modules/_renderer_api_k8s_api_.md)
* [Navigation](modules/_renderer_api_navigation_.md)
## Classes
* [LensMainExtension](classes/lensmainextension.md)
* [LensRendererExtension](classes/lensrendererextension.md)

View File

@ -0,0 +1,3 @@
# Using Extensions
TBD

1
docs/faq/README.md Normal file
View File

@ -0,0 +1 @@
TBD

View File

@ -0,0 +1,55 @@
# Getting Started
Lens is lightweight and simple to install. You'll be up and running in just a few minutes.
## System Requirements
Review the [System Requirements](/supporting/requirements/) to check if your computer configuration is supported.
## macOS
1. [Download Lens](https://github.com/lensapp/lens/releases) for macOS.
2. Open the browser's download list and locate the downloaded archive.
3. Select the 'magnifying glass' icon to open the archive in Finder.
4. Double-click `Lens-{version}.dmg` and drag `Lens.app` to the `Applications` folder, making it available in the macOS Launchpad.
5. Add Lens to your Dock by right-clicking on the icon to bring up the context menu and choosing **Options**, **Keep in Dock**.
## Windows
1. Download the [Lens installer](https://github.com/lensapp/lens/releases) for Windows.
2. Once it is downloaded, run the installer `Lens-Setup-{version}.exe`. This will only take a minute.
3. By default, Lens is installed under `C:\users\{username}\AppData\Local\Programs\Lens`.
## Linux
See the [Download Lens](https://github.com/lensapp/lens/releases) page for a complete list of available installation options.
### Snap
Lens is officially distributed as a Snap package in the [Snap Store](https://snapcraft.io/store):
[![Get it from the Snap Store](images/snap-store.png)](https://snapcraft.io/kontena-lens)
You can install it by running:
```bash
sudo snap install kontena-lens --classic
```
## Update Cadence
Lens releases a new version each month with new features and important bug fixes. Lens supports auto updating and you will be prompted to install the new release when it becomes available!
To stay current with the Lens features, you can review the [release notes](https://github.com/lensapp/lens/releases).
## Next Steps
- [Add clusters](../clusters/adding-clusters.md)
- [Watch introductory videos](./introductory-videos.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,36 @@
# Introductory Videos
Continue your Lens journey with this set of introductory videos! These videos are meant to quickly familiarize you with Lens' various powerful features.
<ul class="video-list">
<li class="video">
<a target="_blank" href="https://youtu.be/mc-BzPDKfkQ">
<img src="https://img.youtube.com/vi/mc-BzPDKfkQ/mqdefault.jpg" alt aria-hidden="true" class="thumb"/>
<div class="info">
<h3 class="title">Getting started</h3>
<p class="description">Get Lens Kubernetes IDE Running in 5 Minutes</p>
<span class="duration"><span class="sr-only">Duration </span>35<span class="sr-only"> minutes</span></span>
</div>
</a>
</li>
<li class="video">
<a target="_blank" href="https://youtu.be/epw_MjxjMYI">
<img src="https://img.youtube.com/vi/epw_MjxjMYI/mqdefault.jpg" alt aria-hidden="true" class="thumb"/>
<div class="info">
<h3 class="title">Introducing Lens</h3>
<p class="description">Lens Kubernetes IDE overview</p>
<span class="duration"><span class="sr-only">Duration </span>2<span class="sr-only"> minutes</span></span>
</div>
</a>
</li>
<li class="video">
<a target="_blank" href="https://youtu.be/fqneoWCgJdw">
<img src="https://img.youtube.com/vi/fqneoWCgJdw/mqdefault.jpg" alt aria-hidden="true" class="thumb"/>
<div class="info">
<h3 class="title">Demo of Mirantis Lens</h3>
<p class="description">The Best IDE For Kubernetes</p>
<span class="duration"><span class="sr-only">Duration </span>10<span class="sr-only"> minutes</span></span>
</div>
</a>
</li>
</ul>

View File

@ -0,0 +1,28 @@
# Preferences
## Color Themes
The Color Themes option in Lens preferences lets you set the colors in the Lens user interface to suit your liking.
1. Go to **File** > **Preferences** (**Lens** > **Preferences** on Mac).
2. Select your preferred theme from the **Color Theme** dropdown.
![Color Theme](images/color-theme.png)
## Telemetry & Usage Tracking
Lens collects telemetry data, which is used to help us understand how to improve the product. For example, this usage data helps us to debug issues and to prioritize new features. While we appreciate the insights this data provides, we also know that not everyone wants to send usage data. Please see our [privacy statement](https://www.mirantis.com/company/privacy-policy/) to learn more.
### Disable Telemetry Reporting
If you don't wish to send usage data to Mirantis, you can disable the "Telemetry & Usage Tracking" in the Lens preferences.
1. Go to **File** > **Preferences** (**Lens** > **Preferences** on Mac).
2. Scroll down to **Telemetry & Usage Tracking**
3. Uncheck **Allow Telemetry & Usage Tracking**.
This will silence all telemetry events from Lens going forward. Telemetry information may have been collected and sent up until the point when you disable this setting.
![Disable Telemetry & Usage Tracking](images/disabled-telemetry-usage-tracking.png)

3
docs/helm/README.md Normal file
View File

@ -0,0 +1,3 @@
# Using Helm Charts
TBD

BIN
docs/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
.st1{fill:#3D90CE;}
.st2{fill:#FFFFFF;}
</style>
<rect y="0" class="st0" width="512" height="512"/>
<rect x="16" y="16" class="st1" width="480" height="480"/>
<g>
<path class="st2" d="M242.6,426h130.9l-30.2-128.7L242.6,426z"/>
<path class="st2" d="M86,352.5V426h137.6l57.5-73.5H86z"/>
<path class="st2" d="M273.1,167L426,241.4v-148L273.1,167z"/>
<path class="st2" d="M388.9,426H426V258l-86.4-42.1L388.9,426z"/>
<path class="st2" d="M406.9,86H216.4l-23,102.7L406.9,86z"/>
<path class="st2" d="M86,195.1v142.5h113.3L86,195.1z"/>
<path class="st2" d="M201.1,86H86v85.1l75,94.3L201.1,86z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 999 B

1
docs/img/play.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 22 22"><path fill="#fff" d="M9.35 15.95V6.6L15.4 11zM11 1C5.477 1 1 5.477 1 11c0 5.522 4.477 10 10 10s10-4.478 10-10c0-5.523-4.477-10-10-10zm0 18.5a8.5 8.5 0 1 1 .001-17.001A8.5 8.5 0 0 1 11 19.5z"/></svg>

After

Width:  |  Height:  |  Size: 283 B

View File

@ -0,0 +1,90 @@
:root {
--md-primary-fg-color: #3d90ce;
--md-accent-fg-color: #3d90ce;
}
:root > * {
/* Footer */
--md-footer-bg-color: #3d90ce;
}
.md-version__list {
overflow: auto;
}
ul.video-list {
counter-reset: section;
list-style: none;
padding-left: 0;
position:relative
}
ul.video-list .video:not(:last-of-type) a {
border-bottom:2px solid #e6e6e6
}
ul.video-list a {
position: relative;
padding: 2rem 2rem 2rem 4.2rem;
display: block;
box-sizing:border-box
}
ul.video-list a .info {
padding-top:0.25rem
}
ul.video-list a .info::before {
counter-increment: section;
content: counter(section);
position: absolute;
left: 1.5rem;
color:black
}
ul.video-list a .info > p, ul.video-list a .info > span {
color:black
}
ul.video-list a .info .title {
margin-top: 0;
margin-bottom:0.7rem
}
ul.video-list a .info .description {
margin-bottom: 1rem;
}
ul.video-list a .info .duration, ul.video-list a .info .duration span {
color: #6e6e6e;
}
ul.video-list a:hover, ul.video-list a:focus {
text-decoration:none
}
ul.video-list a:hover {
background:#f2f2f2
}
ul.video-list a:hover::after {
content: '';
display: block;
width: 6rem;
height: 6rem;
position: absolute;
background: url("/img/play.svg");
background-size: 6rem;
top: 3rem;
left:8.6rem
}
ul.video-list .thumb {
max-height: 8.2rem;
padding-right: 2rem;
position: relative;
float:left
}

View File

@ -0,0 +1,26 @@
# Requirements for Lens
## Hardware
Lens is a small download (< 300 MB) and has a disk footprint of 600 MB. Lens is lightweight and should easily run on today's hardware.
We recommend:
* 2 GHz or faster processor
* 1 GB of RAM
## Platforms
Lens has been tested on the following platforms:
* macOS
* Windows
* Linux
### Additional Windows requirements
...
### Additional Linux Requirements
...

View File

@ -1,8 +0,0 @@
install-deps:
yarn install
build: install-deps
yarn run build
test:
yarn run test

View File

@ -2,10 +2,10 @@ import { LensMainExtension } from "@k8slens/extensions";
export default class ExampleExtensionMain extends LensMainExtension {
onActivate() {
console.log('EXAMPLE EXTENSION MAIN: ACTIVATED', this.getMeta());
console.log('EXAMPLE EXTENSION MAIN: ACTIVATED', this.name, this.id);
}
onDeactivate() {
console.log('EXAMPLE EXTENSION MAIN: DEACTIVATED', this.getMeta());
console.log('EXAMPLE EXTENSION MAIN: DEACTIVATED', this.name, this.id);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -11,13 +11,14 @@
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "npm run build --watch",
"test": "echo NO TESTS"
"test": "jest --passWithNoTests --env=jsdom src $@"
},
"dependencies": {
"react-open-doodles": "^1.0.5"
},
"devDependencies": {
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"jest": "^26.6.3",
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"webpack": "^4.44.2"

View File

@ -5,11 +5,21 @@ import React from "react"
export default class ExampleExtension extends LensRendererExtension {
clusterPages = [
{
path: "/extension-example",
id: "example",
routePath: "/extension-example",
title: "Example Extension",
components: {
Page: () => <ExamplePage extension={this}/>,
MenuIcon: ExampleIcon,
}
}
]
clusterPageMenus = [
{
target: { pageId: "example", params: {} },
title: "Example Extension",
components: {
Icon: ExampleIcon,
}
}
]

View File

@ -0,0 +1,8 @@
install-deps:
npm install
build: install-deps
npm run build
test:
npm run test

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
{
"name": "kube-object-event-status",
"version": "0.1.0",
"description": "Adds kube object status from events",
"renderer": "dist/renderer.js",
"lens": {
"metadata": {},
"styles": []
},
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "npm run build --watch",
"test": "echo NO TESTS"
},
"dependencies": {},
"devDependencies": {
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"webpack": "^4.44.2",
"mobx": "^5.15.5",
"react": "^16.13.1"
}
}

View File

@ -0,0 +1,42 @@
import { LensRendererExtension, K8sApi } from "@k8slens/extensions";
import { resolveStatus, resolveStatusForCronJobs, resolveStatusForPods } from "./src/resolver"
export default class EventResourceStatusRendererExtension extends LensRendererExtension {
kubeObjectStatusTexts = [
{
kind: "Pod",
apiVersions: ["v1"],
resolve: (pod: K8sApi.Pod) => resolveStatusForPods(pod)
},
{
kind: "ReplicaSet",
apiVersions: ["v1"],
resolve: (replicaSet: K8sApi.ReplicaSet) => resolveStatus(replicaSet)
},
{
kind: "Deployment",
apiVersions: ["apps/v1"],
resolve: (deployment: K8sApi.Deployment) => resolveStatus(deployment)
},
{
kind: "StatefulSet",
apiVersions: ["apps/v1"],
resolve: (statefulSet: K8sApi.StatefulSet) => resolveStatus(statefulSet)
},
{
kind: "DaemonSet",
apiVersions: ["apps/v1"],
resolve: (daemonSet: K8sApi.DaemonSet) => resolveStatus(daemonSet)
},
{
kind: "Job",
apiVersions: ["batch/v1"],
resolve: (job: K8sApi.Job) => resolveStatus(job)
},
{
kind: "CronJob",
apiVersions: ["batch/v1"],
resolve: (cronJob: K8sApi.CronJob) => resolveStatusForCronJobs(cronJob)
},
]
}

View File

@ -0,0 +1,52 @@
import { K8sApi } from "@k8slens/extensions";
export function resolveStatus(object: K8sApi.KubeObject): K8sApi.KubeObjectStatus {
const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi)
const events = (eventStore as K8sApi.EventStore).getEventsByObject(object);
let warnings = events.filter(evt => evt.isWarning());
if (!events.length || !warnings.length) {
return null;
}
const event = [...warnings, ...events][0]; // get latest event
return {
level: K8sApi.KubeObjectStatusLevel.WARNING,
text: `${event.message}`,
timestamp: event.metadata.creationTimestamp
}
}
export function resolveStatusForPods(pod: K8sApi.Pod): K8sApi.KubeObjectStatus {
if (!pod.hasIssues()) {
return null
}
const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi)
const events = (eventStore as K8sApi.EventStore).getEventsByObject(pod);
let warnings = events.filter(evt => evt.isWarning());
if (!events.length || !warnings.length) {
return null;
}
const event = [...warnings, ...events][0]; // get latest event
return {
level: K8sApi.KubeObjectStatusLevel.WARNING,
text: `${event.message}`,
timestamp: event.metadata.creationTimestamp
}
}
export function resolveStatusForCronJobs(cronJob: K8sApi.CronJob): K8sApi.KubeObjectStatus {
const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi)
let events = (eventStore as K8sApi.EventStore).getEventsByObject(cronJob);
let warnings = events.filter(evt => evt.isWarning());
if (cronJob.isNeverRun()) {
events = events.filter(event => event.reason != "FailedNeedsStart");
}
if (!events.length || !warnings.length) {
return null;
}
const event = [...warnings, ...events][0]; // get latest event
return {
level: K8sApi.KubeObjectStatusLevel.WARNING,
text: `${event.message}`,
timestamp: event.metadata.creationTimestamp
}
}

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"outDir": "dist",
"module": "CommonJS",
"target": "ES2017",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"moduleResolution": "Node",
"sourceMap": false,
"declaration": false,
"strict": false,
"noImplicitAny": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"jsx": "react"
},
"include": [
"./*.ts",
"./*.tsx"
],
"exclude": [
"node_modules",
"*.js"
]
}

View File

@ -0,0 +1,35 @@
const path = require('path');
module.exports = [
{
entry: './renderer.tsx',
context: __dirname,
target: "electron-renderer",
mode: "production",
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
externals: [
{
"@k8slens/extensions": "var global.LensExtensions",
"react": "var global.React",
"mobx": "var global.Mobx"
}
],
resolve: {
extensions: [ '.tsx', '.ts', '.js' ],
},
output: {
libraryTarget: "commonjs2",
globalObject: "this",
filename: 'renderer.js',
path: path.resolve(__dirname, 'dist'),
},
},
];

View File

@ -1,8 +0,0 @@
install-deps:
yarn install
build: install-deps
yarn run build
test:
yarn run test

File diff suppressed because it is too large Load Diff

View File

@ -6,12 +6,13 @@
"scripts": {
"build": "webpack -p",
"dev": "webpack --watch",
"test": "echo NO TESTS"
"test": "jest --passWithNoTests --env=jsdom src $@"
},
"dependencies": {},
"devDependencies": {
"@types/webpack": "^4.41.17",
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"@types/webpack": "^4.41.17",
"jest": "^26.6.3",
"mobx": "^5.15.5",
"react": "^16.13.1",
"ts-loader": "^8.0.4",

View File

@ -1,8 +0,0 @@
install-deps:
yarn install
build: install-deps
yarn run build
test:
yarn run test

File diff suppressed because it is too large Load Diff

View File

@ -10,17 +10,18 @@
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "npm run build --watch",
"test": "echo NO TESTS"
"test": "jest --passWithNoTests --env=jsdom src $@"
},
"dependencies": {
"semver": "^7.3.2"
},
"devDependencies": {
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"jest": "^26.6.3",
"mobx": "^5.15.5",
"react": "^16.13.1",
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"webpack": "^4.44.2",
"mobx": "^5.15.5",
"react": "^16.13.1"
"webpack": "^4.44.2"
}
}

View File

@ -1,8 +0,0 @@
install-deps:
yarn install
build: install-deps
yarn run build
test:
yarn run test

File diff suppressed because it is too large Load Diff

View File

@ -10,15 +10,16 @@
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "npm run build --watch",
"test": "echo NO TESTS"
"test": "jest --passWithNoTests --env=jsdom src $@"
},
"dependencies": {},
"devDependencies": {
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"jest": "^26.6.3",
"mobx": "^5.15.5",
"react": "^16.13.1",
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"webpack": "^4.44.2",
"mobx": "^5.15.5",
"react": "^16.13.1"
"webpack": "^4.44.2"
}
}

View File

@ -1,8 +0,0 @@
install-deps:
yarn install
build: install-deps
yarn run build
test:
yarn run test

File diff suppressed because it is too large Load Diff

View File

@ -10,15 +10,16 @@
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "npm run build --watch",
"test": "echo NO TESTS"
"test": "jest --passWithNoTests --env=jsdom src $@"
},
"dependencies": {},
"devDependencies": {
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"webpack": "^4.44.2",
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"jest": "^26.6.3",
"mobx": "^5.15.5",
"react": "^16.13.1",
"@k8slens/extensions": "file:../../src/extensions/npm/extensions"
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"webpack": "^4.44.2"
}
}

View File

@ -1,8 +0,0 @@
install-deps:
yarn install
build: install-deps
yarn run build
test:
yarn run test

View File

@ -1,13 +1,12 @@
import { LensMainExtension, windowManager } from "@k8slens/extensions";
import { supportPageURL } from "./src/support.route";
import { LensMainExtension } from "@k8slens/extensions";
export default class SupportPageMainExtension extends LensMainExtension {
appMenus = [
{
parentId: "help",
label: "Support",
click() {
windowManager.navigate(supportPageURL());
click: () => {
this.navigate();
}
}
]

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
"scripts": {
"build": "webpack -p",
"dev": "webpack --watch",
"test": "echo NO TESTS"
"test": "jest --passWithNoTests --env=jsdom src $@"
},
"dependencies": {},
"devDependencies": {
@ -16,6 +16,7 @@
"@types/react-router": "^5.1.8",
"@types/webpack": "^4.41.17",
"css-loader": "^5.0.0",
"jest": "^26.6.3",
"mobx": "^5.15.5",
"react": "^16.13.1",
"sass-loader": "^10.0.4",

View File

@ -1,28 +1,21 @@
import React from "react";
import { Component, LensRendererExtension, Navigation } from "@k8slens/extensions";
import { supportPageRoute, supportPageURL } from "./src/support.route";
import { Support } from "./src/support";
import { Component, Interface, LensRendererExtension } from "@k8slens/extensions";
import { SupportPage } from "./src/support";
export default class SupportPageRendererExtension extends LensRendererExtension {
globalPages = [
globalPages: Interface.PageRegistration[] = [
{
...supportPageRoute,
url: supportPageURL(),
hideInMenu: true,
components: {
Page: Support,
Page: SupportPage,
}
}
]
statusBarItems = [
statusBarItems: Interface.StatusBarRegistration[] = [
{
item: (
<div
className="flex align-center gaps hover-highlight"
onClick={() => Navigation.navigate(supportPageURL())}
>
<Component.Icon material="help" smallest />
<div className="SupportPageIcon flex align-center" onClick={() => this.navigate()}>
<Component.Icon interactive material="help" smallest/>
</div>
)
}

View File

@ -1,7 +0,0 @@
import type { RouteProps } from "react-router";
export const supportPageRoute: RouteProps = {
path: "/support"
}
export const supportPageURL = () => supportPageRoute.path.toString();

View File

@ -1,4 +1,4 @@
.PageLayout.Support {
.SupportPage {
a[target=_blank] {
text-decoration: none;
border-bottom: 1px solid;
@ -10,4 +10,10 @@
margin-left: 2px;
}
}
}
.SupportPageIcon {
color: white;
font-size: var(--font-size-small);
padding-right: calc(var(--padding) / 2);
}

View File

@ -6,12 +6,12 @@ import { observer } from "mobx-react"
import { App, Component } from "@k8slens/extensions";
@observer
export class Support extends React.Component {
export class SupportPage extends React.Component {
render() {
const { PageLayout } = Component;
const { slackUrl, issuesTrackerUrl } = App;
return (
<PageLayout showOnTop className="Support" header={<h2>Support</h2>}>
<PageLayout showOnTop className="SupportPage" header={<h2>Support</h2>}>
<h2>Community Slack Channel</h2>
<p>
Ask a question, see what's being discussed, join the conversation <a href={slackUrl} target="_blank">here</a>

View File

@ -1,8 +0,0 @@
install-deps:
yarn install
build: install-deps
yarn run build
test:
yarn run test

File diff suppressed because it is too large Load Diff

View File

@ -11,19 +11,20 @@
"scripts": {
"build": "webpack -p",
"dev": "webpack --watch",
"test": "echo NO TESTS"
"test": "jest --passWithNoTests --env=jsdom src $@"
},
"dependencies": {},
"devDependencies": {
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
"@types/analytics-node": "^3.1.3",
"analytics-node": "^3.4.0-beta.3",
"jest": "^26.6.3",
"mobx": "^5.15.5",
"node-machine-id": "^1.1.12",
"react": "^16.13.1",
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"webpack": "^4.44.2",
"mobx": "^5.15.5",
"react": "^16.13.1",
"node-machine-id": "^1.1.12",
"universal-analytics": "^0.4.23",
"analytics-node": "^3.4.0-beta.3"
"webpack": "^4.44.2"
}
}

View File

@ -13,6 +13,7 @@ const itif = (condition: boolean) => condition ? it : it.skip
jest.setTimeout(60000)
// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below)
describe("Lens integration tests", () => {
const TEST_NAMESPACE = "integration-tests"
@ -47,17 +48,23 @@ describe("Lens integration tests", () => {
await clickWhatsNew(app)
})
// Todo figure out how to access main menu to get these to work
it.skip('shows "add cluster"', async () => {
await app.client.keys(['Shift', 'Meta', 'A'])
it('shows "add cluster"', async () => {
await app.electron.ipcRenderer.send('test-menu-item-click', "File", "Add Cluster")
await app.client.waitUntilTextExists("h2", "Add Cluster")
await app.client.keys(['Shift', 'Meta'])
})
it.skip('shows "preferences"', async () => {
await app.client.keys(['Meta', ','])
await app.client.waitUntilTextExists("h2", "Preferences")
await app.client.keys('Meta')
describe("preferences page", () => {
it('shows "preferences"', async () => {
let appName: string = process.platform === "darwin" ? "Lens" : "File"
await app.electron.ipcRenderer.send('test-menu-item-click', appName, "Preferences")
await app.client.waitUntilTextExists("h2", "Preferences")
})
it('ensures helm repos', async () => {
await app.client.waitUntilTextExists("div.repos #message-stable", "stable") // wait for the helm-cli to fetch the stable repo
await app.client.click("#HelmRepoSelect") // click the repo select to activate the drop-down
await app.client.waitUntilTextExists("div.Select__option", "") // wait for at least one option to appear (any text)
})
})
it.skip('quits Lens"', async () => {
@ -388,7 +395,7 @@ describe("Lens integration tests", () => {
if (drawer !== "") {
it(`shows ${drawer} drawer`, async () => {
expect(clusterAdded).toBe(true)
await app.client.click(`.sidebar-nav #${drawerId} span.link-text`)
await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`)
await app.client.waitUntilTextExists(`a[href^="/${pages[0].href}"]`, pages[0].name)
})
}
@ -403,13 +410,47 @@ describe("Lens integration tests", () => {
// hide the drawer
it(`hides ${drawer} drawer`, async () => {
expect(clusterAdded).toBe(true)
await app.client.click(`.sidebar-nav #${drawerId} span.link-text`)
await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`)
await expect(app.client.waitUntilTextExists(`a[href^="/${pages[0].href}"]`, pages[0].name, 100)).rejects.toThrow()
})
}
})
})
describe("viewing pod logs", () => {
beforeEach(appStartAddCluster, 40000)
afterEach(async () => {
if (app && app.isRunning()) {
return util.tearDown(app)
}
})
it(`shows a logs for a pod`, async () => {
expect(clusterAdded).toBe(true)
// Go to Pods page
await app.client.click(".sidebar-nav [data-test-id='workloads'] span.link-text")
await app.client.waitUntilTextExists('a[href^="/pods"]', "Pods")
await app.client.click('a[href^="/pods"]')
await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver")
// Open logs tab in dock
await app.client.click(".list .TableRow:first-child")
await app.client.waitForVisible(".Drawer")
await app.client.click(".drawer-title .Menu li:nth-child(2)")
// Check if controls are available
await app.client.waitForVisible(".PodLogs .VirtualList")
await app.client.waitForVisible(".PodLogControls")
await app.client.waitForVisible(".PodLogControls .SearchInput")
await app.client.waitForVisible(".PodLogControls .SearchInput input")
// Search for semicolon
await app.client.keys(":")
await app.client.waitForVisible(".PodLogs .list span.active")
// Click through controls
await app.client.click(".PodLogControls .timestamps-icon")
await app.client.click(".PodLogControls .undo-icon")
})
})
describe("cluster operations", () => {
beforeEach(appStartAddCluster, 40000)
@ -439,7 +480,7 @@ describe("Lens integration tests", () => {
it(`creates a pod in ${TEST_NAMESPACE} namespace`, async () => {
expect(clusterAdded).toBe(true)
await app.client.click(".sidebar-nav #workloads span.link-text")
await app.client.click(".sidebar-nav [data-test-id='workloads'] span.link-text")
await app.client.waitUntilTextExists('a[href^="/pods"]', "Pods")
await app.client.click('a[href^="/pods"]')
await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver")

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More