From 1ebe4c7a6fb1ee1ee9ad1cc08e7cf9ba1d609d64 Mon Sep 17 00:00:00 2001 From: Luca Stocchi <49404737+lstocchi@users.noreply.github.com> Date: Fri, 21 Jul 2023 17:02:44 +0200 Subject: [PATCH] feat: allow extensions to customize icons (#1899) (#3131) * feat: allow extensions to customize icons (#1899) Signed-off-by: lstocchi * fix: keep storage to server and move evaluation to renderer Signed-off-by: lstocchi * fix: clean and add tests Signed-off-by: lstocchi * fix: rename file and fix function signature Signed-off-by: lstocchi * fix: move contextKeyValue type Signed-off-by: lstocchi * fix: clean after messed rebase Signed-off-by: lstocchi * fix: replace icon and refactor Signed-off-by: lstocchi * chore: replace icon with one with margin Signed-off-by: lstocchi --------- Signed-off-by: lstocchi --- extensions/kind/kind-icon.woff2 | Bin 0 -> 1396 bytes extensions/kind/package.json | 17 +++ .../renderer/src/lib/ContainerList.svelte | 144 +++++++++++------- .../src/lib/container/ContainerInfoUI.ts | 2 + .../src/lib/container/container-utils.spec.ts | 48 ++++++ .../src/lib/container/container-utils.ts | 54 ++++++- .../renderer/src/lib/images/StatusIcon.svelte | 8 +- packages/renderer/src/lib/view/views.ts | 1 + packages/renderer/src/stores/views.spec.ts | 88 +++++++++++ 9 files changed, 305 insertions(+), 57 deletions(-) create mode 100644 extensions/kind/kind-icon.woff2 create mode 100644 packages/renderer/src/lib/view/views.ts create mode 100644 packages/renderer/src/stores/views.spec.ts diff --git a/extensions/kind/kind-icon.woff2 b/extensions/kind/kind-icon.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..73241f4ff38d73a06b4e554ca41f94b6836c013e GIT binary patch literal 1396 zcmV-)1&jK3Pew8T0RR9100nda3jhEB01OZS00kug0RR9100000000000000000000 z0000Seg8~_0}0we=81Rw>33I}EzlnSGwijqV2&jZ_-`N$!hxk!w& zjY=Q9Lc@O&3;(%>PAD7#Z8SUaHHiQA>$B>1KOES83&b;j!2w|6kR1sX8HJ=`qjF-S zG=lzDYum-NX}VBQZDL6*y@&vYu<^FI!iAN(v0=*EBtb1@uy*&a3)XhegtMcJ*5NnD_mdbLu~ zYhD4V0(zE6A1oK+X{s5HJ0Asb0N+$`8tkn~C zAeS-Cq%kVIn)yv;4>)79pC#-^b&Tl|)btoe^du^J1|2GQEP9Ugh=p zMexCZ34pbLEx-@{J3)#qcgQ(%JC|G0wQbXNO*>xGcWYMU^Y~~@y=hxFoyX%sdP|&d zSLWJv&}>)_D|27#OIL@~RviCm%BE3M0Cf))cc-PHREpcwfWkERgKn)huzFv_TJA;lbE1IosKIprGBbuY>lN8 z%MhE`64TZw$$e);yE)R*ysCBM(5#x(4;KS1O5_rOQIz;T*2mIFsl5eRs#sx;VaJM9 zk(Q`)HNsRZQG)bnfE1}VXU zt|;68a>{Khoa1sMZe6Ca@=g`oA*j6M9#FJ0{+4v@(5<*J`~` z>iE8RPet=4x#rTw@Xu}im8@N)HK&4K0-gjck;UXY5=a6%hFd%+fotC7QTWA(wuV+U z)>gBLIKwC4pU!$CJRwPk&nF^8E{lO!b=xG+=`4g@yh$bC_!{I6%h@KHn#88&Mgz?t zz6i*m`%NlLW-DtOTRVG4j-5EAoPb;EXSCM(wZZNC_yQ_uB99d6XrY8QGS~+I0002I C9*4*P literal 0 HcmV?d00001 diff --git a/extensions/kind/package.json b/extensions/kind/package.json index 9a6aac7ea996..f99b25b936ed 100644 --- a/extensions/kind/package.json +++ b/extensions/kind/package.json @@ -50,6 +50,15 @@ } } }, + "icons": { + "kind-icon": { + "description": "Kind icon", + "default": { + "fontPath": "kind-icon.woff2", + "fontCharacter": "\\EA01" + } + } + }, "menus": { "dashboard/image": [ { @@ -57,6 +66,14 @@ "title": "Push image to Kind cluster" } ] + }, + "views": { + "icons/containersList": [ + { + "when": "io.x-k8s.kind.cluster in containerLabelKeys", + "icon": "${kind-icon}" + } + ] } }, "scripts": { diff --git a/packages/renderer/src/lib/ContainerList.svelte b/packages/renderer/src/lib/ContainerList.svelte index 68d7d081ffb8..c59ec077e836 100644 --- a/packages/renderer/src/lib/ContainerList.svelte +++ b/packages/renderer/src/lib/ContainerList.svelte @@ -1,9 +1,10 @@ @@ -19,7 +19,11 @@ $: solid = status === 'RUNNING' || status === 'STARTING' || status === 'USED' || class:border-gray-700="{!solid}" class:text-gray-700="{!solid}" title="{status}"> - + {#if typeof icon === 'string'} + + {:else} + + {/if} {#if status === 'CREATED'} diff --git a/packages/renderer/src/lib/view/views.ts b/packages/renderer/src/lib/view/views.ts new file mode 100644 index 000000000000..a44ef8be2f25 --- /dev/null +++ b/packages/renderer/src/lib/view/views.ts @@ -0,0 +1 @@ +export const CONTAINER_LIST_VIEW = 'icons/containersList'; diff --git a/packages/renderer/src/stores/views.spec.ts b/packages/renderer/src/stores/views.spec.ts new file mode 100644 index 000000000000..cea20544d3c1 --- /dev/null +++ b/packages/renderer/src/stores/views.spec.ts @@ -0,0 +1,88 @@ +/********************************************************************** + * Copyright (C) 2023 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { get } from 'svelte/store'; +import type { Mock } from 'vitest'; +import { expect, test, vi } from 'vitest'; +import { fetchViews, viewsEventStore, viewsContributions } from './views'; +import type { ViewInfoUI } from '../../../main/src/plugin/api/view-info'; + +// first, path window object +const callbacks = new Map(); +const eventEmitter = { + receive: (message: string, callback: any) => { + callbacks.set(message, callback); + }, +}; + +const listViewsMock: Mock> = vi.fn(); + +Object.defineProperty(global, 'window', { + value: { + listViewsContributions: listViewsMock, + events: { + receive: eventEmitter.receive, + }, + addEventListener: eventEmitter.receive, + }, + writable: true, +}); + +beforeAll(() => { + vi.clearAllMocks(); +}); + +test('views should be updated in case of an extension is stopped', async () => { + // initial view + listViewsMock.mockResolvedValue([ + { + extensionId: 'extension', + viewId: 'view', + when: 'when', + icon: 'icon', + } as unknown as ViewInfoUI, + ]); + viewsEventStore.setup(); + + const callback = callbacks.get('extensions-already-started'); + // send 'extensions-already-started' event + expect(callback).toBeDefined(); + await callback(); + + // now ready to fetch volumes + await fetchViews(); + + // now get list + const views = get(viewsContributions); + expect(views.length).toBe(1); + expect(views[0].extensionId).toEqual('extension'); + + // ok now mock the listVolumes function to return an empty list + listViewsMock.mockResolvedValue([]); + + // call 'container-removed-event' event + const extensionStoppedCallback = callbacks.get('extension-stopped'); + expect(extensionStoppedCallback).toBeDefined(); + await extensionStoppedCallback(); + + // check if the volumes are updated + const views2 = get(viewsContributions); + expect(views2.length).toBe(0); +});