mirror of https://github.com/artifacthub/hub.git
Add support for Headlamp plugins (#3594)
Signed-off-by: Sergio Castaño Arteaga <tegioz@icloud.com> Signed-off-by: Cintia Sanchez Garcia <cynthiasg@icloud.com> Co-authored-by: Sergio Castaño Arteaga <tegioz@icloud.com> Co-authored-by: Cintia Sanchez Garcia <cynthiasg@icloud.com>
This commit is contained in:
parent
38071dc17c
commit
7a2e090ec5
|
|
@ -59,7 +59,7 @@ updates:
|
|||
interval: "weekly"
|
||||
ignore:
|
||||
- dependency-name: "node"
|
||||
versions: ["19-alpine3.19", "20-alpine3.19"]
|
||||
versions: ["19-alpine3.19", "20-alpine3.19", "21-alpine3.19"]
|
||||
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/cmd/scanner"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ At the moment, the following artifacts kinds are supported *(with plans to suppo
|
|||
- [CoreDNS plugins](https://coredns.io/)
|
||||
- [Falco configurations](https://falco.org/)
|
||||
- [Gatekeeper policies](https://open-policy-agent.github.io/gatekeeper/website/docs/)
|
||||
- [Headlamp plugins](https://headlamp.dev)
|
||||
- [Helm charts](https://helm.sh/)
|
||||
- [Helm plugins](https://helm.sh/docs/topics/plugins/)
|
||||
- [KCL modules](https://kcl-lang.io)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ apiVersion: v2
|
|||
name: artifact-hub
|
||||
description: Artifact Hub is a web-based application that enables finding, installing, and publishing Kubernetes packages.
|
||||
type: application
|
||||
version: 1.16.1-4
|
||||
version: 1.16.1-5
|
||||
appVersion: 1.16.0
|
||||
kubeVersion: ">= 1.19.0-0"
|
||||
home: https://artifacthub.io
|
||||
|
|
@ -28,6 +28,7 @@ keywords:
|
|||
- argo
|
||||
- kubearmor
|
||||
- kcl
|
||||
- headlamp
|
||||
maintainers:
|
||||
- name: Sergio
|
||||
email: tegioz@icloud.com
|
||||
|
|
|
|||
|
|
@ -1162,7 +1162,7 @@
|
|||
},
|
||||
"repositoriesKinds": {
|
||||
"title": "Repositories kinds to process ([] = all)",
|
||||
"description": "The following kinds are supported at the moment: falco, helm, olm, opa, tbaction, krew, helm-plugin, tekton-task, keda-scaler, coredns, keptn, tekton-pipeline, container, kubewarden, gatekeeper, kyverno, knative-client-plugin, backstage, argo-template, kubearmor, kcl",
|
||||
"description": "The following kinds are supported at the moment: falco, helm, olm, opa, tbaction, krew, helm-plugin, tekton-task, keda-scaler, coredns, keptn, tekton-pipeline, container, kubewarden, gatekeeper, kyverno, knative-client-plugin, backstage, argo-template, kubearmor, kcl, headlamp",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ func newLintCmd() *cobra.Command {
|
|||
return lint(opts, &output{cmd.OutOrStdout()})
|
||||
},
|
||||
}
|
||||
lintCmd.Flags().StringVarP(&opts.kind, "kind", "k", "helm", "repository kind: argo-template, backstage, coredns, falco, gatekeeper, helm, helm-plugin, kcl, keda-scaler, keptn, knative-client-plugin, krew, kubearmor, kubewarden, kyverno, olm, opa, tbaction, tekton-task, tekton-pipeline")
|
||||
lintCmd.Flags().StringVarP(&opts.kind, "kind", "k", "helm", "repository kind: argo-template, backstage, coredns, falco, gatekeeper, headlamp, helm, helm-plugin, kcl, keda-scaler, keptn, knative-client-plugin, krew, kubearmor, kubewarden, kyverno, olm, opa, tbaction, tekton-task, tekton-pipeline")
|
||||
lintCmd.Flags().StringVarP(&opts.path, "path", "p", ".", "repository's packages path")
|
||||
return lintCmd
|
||||
}
|
||||
|
|
@ -114,6 +114,7 @@ func lint(opts *lintOptions, out *output) error {
|
|||
hub.CoreDNS,
|
||||
hub.Falco,
|
||||
hub.Gatekeeper,
|
||||
hub.Headlamp,
|
||||
hub.KCL,
|
||||
hub.KedaScaler,
|
||||
hub.Keptn,
|
||||
|
|
@ -617,6 +618,7 @@ func (out *output) printPkgDetails(pkg *hub.Package) {
|
|||
hub.CoreDNS,
|
||||
hub.Falco,
|
||||
hub.Gatekeeper,
|
||||
hub.Headlamp,
|
||||
hub.KCL,
|
||||
hub.KedaScaler,
|
||||
hub.Keptn,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
insert into repository_kind values (21, 'Headlamp plugins');
|
||||
|
||||
---- create above / drop below ----
|
||||
|
||||
delete from repository_kind where repository_kind_id = 21;
|
||||
|
|
@ -560,7 +560,8 @@ select results_eq(
|
|||
(17, 'Backstage plugins'),
|
||||
(18, 'Argo templates'),
|
||||
(19, 'KubeArmor policies'),
|
||||
(20, 'KCL modules')
|
||||
(20, 'KCL modules'),
|
||||
(21, 'Headlamp plugins')
|
||||
$$,
|
||||
'Repository kinds should exist'
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1299,6 +1299,30 @@ paths:
|
|||
$ref: "#/components/responses/TooManyRequests"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalServerError"
|
||||
"/packages/headlamp/{repoName}/{packageName}":
|
||||
get:
|
||||
tags:
|
||||
- Packages
|
||||
summary: Get package details
|
||||
description: Get package details
|
||||
operationId: getHeadlampPluginDetails
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/RepoNameParam"
|
||||
- $ref: "#/components/parameters/PackageNameParam"
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HeadlampPluginPackage"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundResponse"
|
||||
"429":
|
||||
$ref: "#/components/responses/TooManyRequests"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalServerError"
|
||||
|
||||
"/packages/kcl/{repoName}/{packageName}":
|
||||
get:
|
||||
tags:
|
||||
|
|
@ -1790,7 +1814,31 @@ paths:
|
|||
$ref: "#/components/responses/TooManyRequests"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalServerError"
|
||||
"/packages/KCL/{repoName}/{packageName}/{version}":
|
||||
"/packages/headlamp/{repoName}/{packageName}/{version}":
|
||||
get:
|
||||
tags:
|
||||
- Packages
|
||||
summary: Get package version details
|
||||
description: Get package version details
|
||||
operationId: getHeadlampVersionDetails
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/RepoNameParam"
|
||||
- $ref: "#/components/parameters/PackageNameParam"
|
||||
- $ref: "#/components/parameters/VersionParam"
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HeadlampPluginPackage"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundResponse"
|
||||
"429":
|
||||
$ref: "#/components/responses/TooManyRequests"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalServerError"
|
||||
"/packages/kcl/{repoName}/{packageName}/{version}":
|
||||
get:
|
||||
tags:
|
||||
- Packages
|
||||
|
|
@ -3967,6 +4015,27 @@ components:
|
|||
example: "http://repo.url"
|
||||
HelmPluginPackage:
|
||||
$ref: "#/components/schemas/Package"
|
||||
HeadlampPluginPackage:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/Package"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
nullable: false
|
||||
properties:
|
||||
headlamp/plugin/archive-url:
|
||||
type: string
|
||||
example: "https://headlamp.dev/sample-plugin-url"
|
||||
headlamp/plugin/distro-compat:
|
||||
type: string
|
||||
example: "in-cluster,web,docker-desktop"
|
||||
headlamp/plugin/version-compat:
|
||||
type: string
|
||||
example: ">=1.2.3"
|
||||
headlamp/plugin/archive-checksum:
|
||||
type: string
|
||||
example: "sha256:123456..."
|
||||
KCLPackage:
|
||||
$ref: "#/components/schemas/Package"
|
||||
KedaScalerPackage:
|
||||
|
|
@ -4689,6 +4758,7 @@ components:
|
|||
- 18
|
||||
- 19
|
||||
- 20
|
||||
- 21
|
||||
description: |
|
||||
Repository kind:
|
||||
* `0` - Helm charts
|
||||
|
|
@ -4712,6 +4782,7 @@ components:
|
|||
* `18` - Argo templates
|
||||
* `19` - KubeArmor templates
|
||||
* `20` - KCL packages
|
||||
* `21` - Headlamp plugins
|
||||
RepositoryKindParam:
|
||||
type: string
|
||||
enum:
|
||||
|
|
@ -4736,6 +4807,7 @@ components:
|
|||
- argo-template
|
||||
- kubearmor
|
||||
- kcl
|
||||
- headlamp
|
||||
description: |
|
||||
Repository kind name:
|
||||
* `helm` - Helm charts
|
||||
|
|
@ -4759,6 +4831,7 @@ components:
|
|||
* `argo-template` - Argo templates
|
||||
* `kubearmor` - KubeArmor policies
|
||||
* `kcl` - KCL packages
|
||||
* `headlamp` - Headlamp plugins
|
||||
RepositorySummary:
|
||||
type: object
|
||||
required:
|
||||
|
|
@ -5299,6 +5372,7 @@ components:
|
|||
* `18` - Argo templates
|
||||
* `19` - KubeArmor templates
|
||||
* `20` - KCL packages
|
||||
* `21` - Headlamp plugins
|
||||
PackageNameParam:
|
||||
in: path
|
||||
name: packageName
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
# Headlamp annotations
|
||||
|
||||
You can provide some extra information about your Headlamp plugins by using the `annotations` field in the [Artifact Hub package metadata file](https://github.com/artifacthub/hub/blob/master/docs/metadata/artifacthub-pkg.yml).
|
||||
|
||||
## Supported annotations
|
||||
|
||||
- **headlamp/plugin/archive-url** *(string, required)*
|
||||
|
||||
Plugin archive tarball URL (e.g. "https://.../my-archive.tar.gz").
|
||||
|
||||
- **headlamp/plugin/archive-checksum** *(string, required)*
|
||||
|
||||
Plugin archive tarball checksum (e.g. "sha256:MY_CHECKSUM").
|
||||
|
||||
- **headlamp/plugin/version-compat** *(string, optional)*
|
||||
|
||||
Headlamp versions this plugin is compatible with (e.g. ">=1.2.3").
|
||||
|
||||
- **headlamp/plugin/distro-compat** *(string, optional)*
|
||||
|
||||
Headlamp flavor this plugin is compatible with (e.g. one or more of app, in-cluster, web, docker-desktop, linux, windows, mac).
|
||||
|
||||
## Example
|
||||
|
||||
```yaml
|
||||
...
|
||||
annotations:
|
||||
headlamp/plugin/archive-url: "https://.../my-archive.tar.gz"
|
||||
headlamp/plugin/archive-checksum: "sha256:MY_CHECKSUM"
|
||||
headlamp/plugin/version-compat: ">=1.2.3"
|
||||
headlamp/plugin/distro-compat: "in-cluster,web,docker-desktop"
|
||||
```
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
## Headlamp plugins repositories
|
||||
|
||||
Headlamp plugins repositories are expected to be hosted in GitHub, GitLab or Bitbucket repos. When adding your repository to Artifact Hub, the url used **must** follow the following format:
|
||||
|
||||
- `https://github.com/user/repo[/path/to/packages]`
|
||||
- `https://gitlab.com/user/repo[/path/to/packages]`
|
||||
- `https://bitbucket.org/user/repo[/path/to/packages]`
|
||||
|
||||
By default the `master` branch is used, but it's possible to specify a different one from the UI.
|
||||
|
||||
*Please NOTE that the repository URL used when adding the repository to Artifact Hub **must NOT** contain the git hosting platform specific parts, like **tree/branch**, just the path to your packages like it would show in the filesystem.*
|
||||
|
||||
The *path/to/packages* provided can contain metadata for one or more packages. Each package version **must** be on a separate folder, and it's up to you to decide if you want to publish one or multiple versions of your package.
|
||||
|
||||
The structure of a repository with multiple plugins packages and versions could look something like this:
|
||||
|
||||
```sh
|
||||
$ tree path/to/packages
|
||||
path/to/packages
|
||||
├── artifacthub-repo.yml
|
||||
├── package1
|
||||
│ ├── 1.0.0
|
||||
│ │ ├── README.md
|
||||
│ │ └── artifacthub-pkg.yml
|
||||
│ └── 2.0.0
|
||||
│ ├── README.md
|
||||
│ └── artifacthub-pkg.yml
|
||||
└── package2
|
||||
└── 1.0.0
|
||||
├── README.md
|
||||
└── artifacthub-pkg.yml
|
||||
```
|
||||
|
||||
This structure is flexible, and in some cases where you only have a package and a version it can be greatly simplified. In the case of a single package with a single version available at a time (the publisher doesn't want to make previous ones available, for example), the structure could look like this:
|
||||
|
||||
```sh
|
||||
$ tree path/to/packages
|
||||
path/to/packages
|
||||
├── artifacthub-repo.yml
|
||||
└── package1
|
||||
├── README.md
|
||||
└── artifacthub-pkg.yml
|
||||
```
|
||||
|
||||
In the previous case, even the `package1` directory could be omitted. The reason is that both packages names and versions are read from the `artifacthub-pkg.yml` metadata file, so directories names are not used at all.
|
||||
|
||||
Each package version **needs** an `artifacthub-pkg.yml` metadata file. Please see the file [spec](https://github.com/artifacthub/hub/blob/master/docs/metadata/artifacthub-pkg.yml) and the [Headlamp annotations documentation](https://github.com/artifacthub/hub/blob/master/docs/headlamp_annotations.md) for more details. The [artifacthub-repo.yml](https://github.com/artifacthub/hub/blob/master/docs/metadata/artifacthub-repo.yml) repository metadata file shown above can be used to setup features like [Verified publisher](https://github.com/artifacthub/hub/blob/master/docs/repositories.md#verified-publisher) or [Ownership claim](https://github.com/artifacthub/hub/blob/master/docs/repositories.md#ownership-claim). This file must be located at `/path/to/packages`.
|
||||
|
||||
Once you have added your repository, you are all set up. As you add new versions of your plugins packages or new packages to your git repository, they'll be automatically indexed and listed in Artifact Hub.
|
||||
|
|
@ -9,6 +9,7 @@ The following repositories kinds are supported at the moment:
|
|||
- [Containers images repositories](https://github.com/artifacthub/hub/blob/master/docs/container_images_repositories.md)
|
||||
- [CoreDNS plugins repositories](https://github.com/artifacthub/hub/blob/master/docs/coredns_plugins_repositories.md)
|
||||
- [Falco rules repositories](https://github.com/artifacthub/hub/blob/master/docs/falco_rules_repositories.md)
|
||||
- [Headlamp plugins repositories](https://github.com/artifacthub/hub/blob/master/docs/headlamp_plugins_repositories.md)
|
||||
- [Helm charts repositories](https://github.com/artifacthub/hub/blob/master/docs/helm_charts_repositories.md)
|
||||
- [Helm plugins repositories](https://github.com/artifacthub/hub/blob/master/docs/helm_plugins_repositories.md)
|
||||
- [KCL modules repositories](https://github.com/artifacthub/hub/blob/master/docs/kcl_modules_repositories.md)
|
||||
|
|
|
|||
|
|
@ -13,14 +13,15 @@ The documentation is organized in the following topics:
|
|||
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [Repositories guide](/docs/topics/repositories) | The repositories guide explains how to add repositories to Artifact Hub, as well as other related concepts like Verified publisher or Ownership Claim. |
|
||||
| [Argo annotations](/docs/topics/annotations/argo) | Describes some custom annotations that allow enriching the existing metadata in Argo templates to improve users' experience in Artifact Hub. |
|
||||
| [Headlamp annotations](/docs/topics/annotations/headlamp) | Describes some custom annotations that allow enriching the existing metadata in Headlamp plugins to improve users' experience in Artifact Hub. |
|
||||
| [Helm annotations](/docs/topics/annotations/helm) | Describes some custom annotations that allow enriching the existing metadata in Helm Charts to improve users' experience in Artifact Hub. |
|
||||
| [Keptn annotations](/docs/topics/annotations/keptn) | Describes some custom annotations that allow enriching the existing metadata in Keptn integrations to improve users' experience in Artifact Hub. |
|
||||
| [Krew annotations](/docs/topics/annotations/krew) | Describes some custom annotations that allow enriching the existing metadata in Krew kubectl plugins to improve users' experience in Artifact Hub. |
|
||||
| [Kubewarden annotations](/docs/topics/annotations/kubewarden) | Describes some custom annotations that allow enriching the existing metadata in Kubewarden policies to improve users' experience in Artifact Hub. |
|
||||
| [Kyverno annotations](/docs/topics/annotations/kyverno) | Describes some custom annotations that allow enriching the existing metadata in Kyverno policies to improve users' experience in Artifact Hub. |
|
||||
| [OLM annotations](/docs/topics/annotations/olm) | Describes some custom annotations that allow enriching the existing metadata in OLM operators to improve users' experience in Artifact Hub. |
|
||||
| [Tekton annotations](/docs/topics/annotations/tekton) | Describes some custom annotations that allow enriching the existing metadata in Tekton tasks to improve users' experience in Artifact Hub.
|
||||
| [Embedding artifacts](/docs/topics/embedding_artifacts) | Explains how to embed a single artifact or a group of them in other websites. |
|
||||
| [Tekton annotations](/docs/topics/annotations/tekton) | Describes some custom annotations that allow enriching the existing metadata in Tekton tasks to improve users' experience in Artifact Hub. |
|
||||
| [Embedding artifacts](/docs/topics/embedding_artifacts) | Explains how to embed a single artifact or a group of them in other websites. |
|
||||
| [Packages security report](/docs/topics/security_report) | Explains how packages are scanned for security vulnerabilities and the structure of the security report. |
|
||||
| [Authorization](/docs/topics/authorization) | Explains how the authorization mechanism that allows organizations to define what actions can be performed by their members works and how to set it up. |
|
||||
| [Architecture](/docs/topics/architecture) | Describes the components that form Artifact Hub, what each of them do and the layout of the source repository. |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: "Headlamp"
|
||||
aliases: [
|
||||
"/headlamp_annotations",
|
||||
]
|
||||
---
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: "Headlamp plugins"
|
||||
aliases: [
|
||||
"/headlamp_plugins_repositories",
|
||||
]
|
||||
---
|
||||
|
|
@ -265,7 +265,7 @@ func (h *Handlers) setupRouter() {
|
|||
r.Get("/stats", h.Packages.GetStats)
|
||||
r.With(corsMW).Get("/search", h.Packages.Search)
|
||||
r.With(h.Users.RequireLogin).Get("/starred", h.Packages.GetStarredByUser)
|
||||
r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl$}/{repoName}/{packageName}", func(r chi.Router) {
|
||||
r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp$}/{repoName}/{packageName}", func(r chi.Router) {
|
||||
r.Get("/feed/rss", h.Packages.RssFeed)
|
||||
r.With(corsMW).Get("/summary", h.Packages.GetSummary)
|
||||
r.Get("/{version}", h.Packages.Get)
|
||||
|
|
@ -430,7 +430,7 @@ func (h *Handlers) setupRouter() {
|
|||
|
||||
// Index special entry points
|
||||
r.Route("/packages", func(r chi.Router) {
|
||||
r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl$}/{repoName}/{packageName}", func(r chi.Router) {
|
||||
r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp$}/{repoName}/{packageName}", func(r chi.Router) {
|
||||
r.With(h.Packages.InjectIndexMeta).Get("/{version}", h.Static.Index)
|
||||
r.With(h.Packages.InjectIndexMeta).Get("/", h.Static.Index)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2155,6 +2155,17 @@ func TestBuildURL(t *testing.T) {
|
|||
"2.0.0",
|
||||
baseURL + "/packages/kcl/repo1/pkg1/2.0.0",
|
||||
},
|
||||
{
|
||||
&hub.Package{
|
||||
NormalizedName: "pkg1",
|
||||
Repository: &hub.Repository{
|
||||
Kind: hub.Headlamp,
|
||||
Name: "repo1",
|
||||
},
|
||||
},
|
||||
"2.0.0",
|
||||
baseURL + "/packages/headlamp/repo1/pkg1/2.0.0",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
|
|
|
|||
|
|
@ -109,6 +109,9 @@ const (
|
|||
|
||||
// KCL represents a repository with KCL modules.
|
||||
KCL RepositoryKind = 20
|
||||
|
||||
// Headlamp represents a repository with Headlamp plugins.
|
||||
Headlamp RepositoryKind = 21
|
||||
)
|
||||
|
||||
// GetKindName returns the name of the provided repository kind.
|
||||
|
|
@ -126,6 +129,8 @@ func GetKindName(kind RepositoryKind) string {
|
|||
return "falco"
|
||||
case Gatekeeper:
|
||||
return "gatekeeper"
|
||||
case Headlamp:
|
||||
return "headlamp"
|
||||
case Helm:
|
||||
return "helm"
|
||||
case HelmPlugin:
|
||||
|
|
@ -177,6 +182,8 @@ func GetKindFromName(kind string) (RepositoryKind, error) {
|
|||
return Falco, nil
|
||||
case "gatekeeper":
|
||||
return Gatekeeper, nil
|
||||
case "headlamp":
|
||||
return Headlamp, nil
|
||||
case "helm":
|
||||
return Helm, nil
|
||||
case "helm-plugin":
|
||||
|
|
|
|||
|
|
@ -29,6 +29,13 @@ var (
|
|||
// ErrInvalidMetadata indicates that the metadata provided is not valid.
|
||||
ErrInvalidMetadata = errors.New("invalid metadata")
|
||||
|
||||
// headlampRequiredAnnotations represents a list of annotations that must
|
||||
// be present in Headlamp plugins packages.
|
||||
headlampRequiredAnnotations = []string{
|
||||
"headlamp/plugin/archive-url",
|
||||
"headlamp/plugin/archive-checksum",
|
||||
}
|
||||
|
||||
// validChangeKinds is the list of valid kinds that a pkg change can use.
|
||||
validChangeKinds = []string{
|
||||
"added",
|
||||
|
|
@ -119,49 +126,70 @@ func PreparePackageFromMetadata(md *hub.PackageMetadata) (*hub.Package, error) {
|
|||
func ValidatePackageMetadata(kind hub.RepositoryKind, md *hub.PackageMetadata) error {
|
||||
var errs *multierror.Error
|
||||
|
||||
// Version
|
||||
if md.Version == "" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s", ErrInvalidMetadata, "version not provided"))
|
||||
} else if _, err := semver.NewVersion(md.Version); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s: %w", ErrInvalidMetadata, "invalid version (semver expected)", err))
|
||||
}
|
||||
|
||||
// Name, display name and alternative name
|
||||
if md.Name == "" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s", ErrInvalidMetadata, "name not provided"))
|
||||
}
|
||||
if md.DisplayName == "" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s", ErrInvalidMetadata, "display name not provided"))
|
||||
}
|
||||
if md.AlternativeName != "" &&
|
||||
!strings.Contains(md.Name, md.AlternativeName) &&
|
||||
!strings.Contains(md.AlternativeName, md.Name) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s", ErrInvalidMetadata, "invalid alternative name (must be a subset or superset of the name)"))
|
||||
}
|
||||
|
||||
// Category
|
||||
if md.Category != "" {
|
||||
if _, err := hub.PackageCategoryFromName(md.Category); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %w", ErrInvalidMetadata, err))
|
||||
}
|
||||
}
|
||||
if md.DisplayName == "" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s", ErrInvalidMetadata, "display name not provided"))
|
||||
}
|
||||
|
||||
// Created at
|
||||
if md.CreatedAt == "" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s", ErrInvalidMetadata, "createdAt not provided"))
|
||||
} else if _, err := time.Parse(time.RFC3339, md.CreatedAt); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s: %w", ErrInvalidMetadata, "invalid createdAt (RFC3339 expected)", err))
|
||||
}
|
||||
|
||||
// Description
|
||||
if md.Description == "" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s", ErrInvalidMetadata, "description not provided"))
|
||||
|
||||
}
|
||||
|
||||
// Maintainers
|
||||
for _, maintainer := range md.Maintainers {
|
||||
if maintainer.Email == "" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %s", ErrInvalidMetadata, "maintainer email not provided"))
|
||||
}
|
||||
}
|
||||
|
||||
// Changes
|
||||
for _, change := range md.Changes {
|
||||
if err := ValidateChange(change); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %w", ErrInvalidMetadata, err))
|
||||
}
|
||||
}
|
||||
|
||||
// Containers images
|
||||
if err := ValidateContainersImages(kind, md.ContainersImages); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %w", ErrInvalidMetadata, err))
|
||||
}
|
||||
|
||||
// Annotations
|
||||
if err := ValidateAnnotations(kind, md.Annotations); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("%w: %w", ErrInvalidMetadata, err))
|
||||
}
|
||||
|
||||
return errs.ErrorOrNil()
|
||||
}
|
||||
|
||||
|
|
@ -250,3 +278,21 @@ func ValidateContainersImages(kind hub.RepositoryKind, images []*hub.ContainerIm
|
|||
|
||||
return errs.ErrorOrNil()
|
||||
}
|
||||
|
||||
// ValidateAnnotations checks if the provided annotations are valid.
|
||||
func ValidateAnnotations(kind hub.RepositoryKind, annotations map[string]string) error {
|
||||
var errs *multierror.Error
|
||||
|
||||
// Repository kind specific validation
|
||||
switch kind {
|
||||
case hub.Headlamp:
|
||||
// Required annotations
|
||||
for _, requiredAnnotation := range headlampRequiredAnnotations {
|
||||
if _, ok := annotations[requiredAnnotation]; !ok {
|
||||
errs = multierror.Append(errs, fmt.Errorf(`required annotation "%s" not provided`, requiredAnnotation))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errs.ErrorOrNil()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ var (
|
|||
hub.CoreDNS,
|
||||
hub.Falco,
|
||||
hub.Gatekeeper,
|
||||
hub.Headlamp,
|
||||
hub.Helm,
|
||||
hub.HelmPlugin,
|
||||
hub.KCL,
|
||||
|
|
@ -283,6 +284,7 @@ func (m *Manager) ClaimOwnership(ctx context.Context, repoName, orgName string)
|
|||
hub.CoreDNS,
|
||||
hub.Falco,
|
||||
hub.Gatekeeper,
|
||||
hub.Headlamp,
|
||||
hub.HelmPlugin,
|
||||
hub.KCL,
|
||||
hub.KedaScaler,
|
||||
|
|
@ -461,6 +463,7 @@ func (m *Manager) locateMetadataFile(r *hub.Repository, basePath string) string
|
|||
hub.CoreDNS,
|
||||
hub.Falco,
|
||||
hub.Gatekeeper,
|
||||
hub.Headlamp,
|
||||
hub.HelmPlugin,
|
||||
hub.KCL,
|
||||
hub.KedaScaler,
|
||||
|
|
@ -823,6 +826,7 @@ func (m *Manager) validateURL(r *hub.Repository) error {
|
|||
hub.CoreDNS,
|
||||
hub.Falco,
|
||||
hub.Gatekeeper,
|
||||
hub.Headlamp,
|
||||
hub.HelmPlugin,
|
||||
hub.KCL,
|
||||
hub.KedaScaler,
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ func SetupSource(i *hub.TrackerSourceInput) hub.TrackerSource {
|
|||
hub.Backstage,
|
||||
hub.CoreDNS,
|
||||
hub.Gatekeeper,
|
||||
hub.Headlamp,
|
||||
hub.KCL,
|
||||
hub.KedaScaler,
|
||||
hub.Keptn,
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ func (t *Tracker) cloneRepository() (string, string, error) {
|
|||
hub.CoreDNS,
|
||||
hub.Falco,
|
||||
hub.Gatekeeper,
|
||||
hub.Headlamp,
|
||||
hub.HelmPlugin,
|
||||
hub.KCL,
|
||||
hub.KedaScaler,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ cat docs/www/headers/container_images_repositories docs/container_images_reposit
|
|||
cat docs/www/headers/coredns_plugins_repositories docs/coredns_plugins_repositories.md > docs/www/content/topics/repositories/coredns-plugins.md
|
||||
cat docs/www/headers/falco_rules_repositories docs/falco_rules_repositories.md > docs/www/content/topics/repositories/falco-rules.md
|
||||
cat docs/www/headers/gatekeeper_policies_repositories docs/gatekeeper_policies_repositories.md > docs/www/content/topics/repositories/gatekeeper-policies.md
|
||||
cat docs/www/headers/headlamp_plugins_repositories docs/headlamp_plugins_repositories.md > docs/www/content/topics/repositories/headlamp-plugins.md
|
||||
cat docs/www/headers/helm_charts_repositories docs/helm_charts_repositories.md > docs/www/content/topics/repositories/helm-charts.md
|
||||
cat docs/www/headers/helm_plugins_repositories docs/helm_plugins_repositories.md > docs/www/content/topics/repositories/helm-plugins.md
|
||||
cat docs/www/headers/kcl_modules_repositories docs/kcl_modules_repositories.md > docs/www/content/topics/repositories/kcl-modules.md
|
||||
|
|
@ -30,6 +31,7 @@ cat docs/www/headers/tinkerbell_actions_repositories docs/tinkerbell_actions_rep
|
|||
cat docs/www/headers/security_report docs/security_report.md > docs/www/content/topics/security_report.md
|
||||
cat docs/www/headers/cli docs/cli.md > docs/www/content/topics/cli.md
|
||||
cat docs/www/headers/argo_annotations docs/argo_annotations.md > docs/www/content/topics/annotations/argo.md
|
||||
cat docs/www/headers/headlamp_annotations docs/headlamp_annotations.md > docs/www/content/topics/annotations/headlamp.md
|
||||
cat docs/www/headers/helm_annotations docs/helm_annotations.md > docs/www/content/topics/annotations/helm.md
|
||||
cat docs/www/headers/keptn_annotations docs/keptn_annotations.md > docs/www/content/topics/annotations/keptn.md
|
||||
cat docs/www/headers/krew_annotations docs/krew_annotations.md > docs/www/content/topics/annotations/krew.md
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 408 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<path d="M407.951,324.939L376.111,367.867L407.951,466.798L204.117,512L0,466.798L31.84,367.867L0,324.939L0,204.686L31.84,163.18L31.84,93.246L133.899,56.573L133.899,0L274.052,0L274.052,56.573L376.111,93.246L376.111,163.18L407.951,204.686L407.951,324.939ZM204.118,367.867C260.406,367.867 306.176,322.097 306.176,265.808C306.176,209.519 260.406,163.749 204.118,163.749C147.829,163.749 102.059,209.519 102.059,265.808C102.059,322.097 147.829,367.867 204.118,367.867Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 959 B |
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
<svg width="408" height="512" viewBox="0 0 408 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M407.951 324.939V204.686L376.111 163.18V93.246L274.052 56.573V0H133.899V56.573L31.8399 93.246V163.18L0 204.686V324.939L31.8399 367.867L0 466.798L204.117 512L407.951 466.798L376.111 367.867L407.951 324.939Z" fill="black"/>
|
||||
<path d="M204.118 367.867C260.406 367.867 306.176 322.097 306.176 265.808C306.176 209.519 260.406 163.749 204.118 163.749C147.829 163.749 102.059 209.519 102.059 265.808C102.059 322.097 147.829 367.867 204.118 367.867Z" fill="#FFF200"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 576 B |
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
|
|
@ -17,6 +17,7 @@ interface Props {
|
|||
icon?: JSX.Element;
|
||||
disabled?: boolean;
|
||||
label?: string;
|
||||
title?: string;
|
||||
tooltipType?: 'normal' | 'light';
|
||||
noTooltip?: boolean;
|
||||
onClick?: () => void;
|
||||
|
|
@ -105,6 +106,7 @@ const ButtonCopyToClipboard = (props: Props) => {
|
|||
}}
|
||||
disabled={props.disabled}
|
||||
aria-label={props.label || 'Copy to clipboard'}
|
||||
title={props.title}
|
||||
>
|
||||
<div className="d-flex flex-row align-items-center" aria-hidden="true">
|
||||
{!isUndefined(props.visibleBtnText) && props.visibleBtnText && props.contentBtn && (
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ const Image = (props: Props) => {
|
|||
return '/static/media/placeholder_pkg_kubearmor.png';
|
||||
case RepositoryKind.KCL:
|
||||
return '/static/media/placeholder_pkg_kcl.png';
|
||||
case RepositoryKind.Headlamp:
|
||||
return '/static/media/placeholder_pkg_headlamp.png';
|
||||
default:
|
||||
return PLACEHOLDER_SRC;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,10 @@ const ICONS = {
|
|||
default: '/static/media/kcl.svg',
|
||||
white: '/static/media/kcl-light.svg',
|
||||
},
|
||||
[RepositoryKind.Headlamp]: {
|
||||
default: '/static/media/headlamp.svg',
|
||||
white: '/static/media/headlamp-light.svg',
|
||||
},
|
||||
};
|
||||
|
||||
const RepositoryIcon = (props: Props) => {
|
||||
|
|
|
|||
|
|
@ -475,6 +475,17 @@ const RepositoryModal = (props: Props) => {
|
|||
</ExternalLink>
|
||||
);
|
||||
break;
|
||||
case RepositoryKind.Headlamp:
|
||||
link = (
|
||||
<ExternalLink
|
||||
href="/docs/topics/repositories/headlamp-plugins"
|
||||
className="text-primary fw-bold"
|
||||
label="Open documentation"
|
||||
>
|
||||
Headlamp plugins
|
||||
</ExternalLink>
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isUndefined(link)) return;
|
||||
|
|
@ -503,6 +514,7 @@ const RepositoryModal = (props: Props) => {
|
|||
case RepositoryKind.ArgoTemplate:
|
||||
case RepositoryKind.KubeArmor:
|
||||
case RepositoryKind.KCL:
|
||||
case RepositoryKind.Headlamp:
|
||||
return (
|
||||
<>
|
||||
<p
|
||||
|
|
@ -895,6 +907,7 @@ const RepositoryModal = (props: Props) => {
|
|||
RepositoryKind.ArgoTemplate,
|
||||
RepositoryKind.KubeArmor,
|
||||
RepositoryKind.KCL,
|
||||
RepositoryKind.Headlamp,
|
||||
].includes(selectedKind) && (
|
||||
<div>
|
||||
<InputField
|
||||
|
|
@ -1040,6 +1053,7 @@ const RepositoryModal = (props: Props) => {
|
|||
RepositoryKind.ArgoTemplate,
|
||||
RepositoryKind.KubeArmor,
|
||||
RepositoryKind.KCL,
|
||||
RepositoryKind.Headlamp,
|
||||
].includes(selectedKind) && (
|
||||
<div className="mt-4 mb-3">
|
||||
<div className="form-check form-switch ps-0">
|
||||
|
|
|
|||
|
|
@ -84,6 +84,16 @@ exports[`Repository Modal - repositories section creates snapshot 1`] = `
|
|||
>
|
||||
Falco rules
|
||||
</option>
|
||||
<option
|
||||
value="14"
|
||||
>
|
||||
Gatekeeper policies
|
||||
</option>
|
||||
<option
|
||||
value="21"
|
||||
>
|
||||
Headlamp plugins
|
||||
</option>
|
||||
<option
|
||||
value="0"
|
||||
>
|
||||
|
|
@ -94,11 +104,6 @@ exports[`Repository Modal - repositories section creates snapshot 1`] = `
|
|||
>
|
||||
Helm plugins
|
||||
</option>
|
||||
<option
|
||||
value="14"
|
||||
>
|
||||
Gatekeeper policies
|
||||
</option>
|
||||
<option
|
||||
value="20"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ exports[`Home index creates snapshot 1`] = `
|
|||
<div
|
||||
class="text-center px-3 px-xs-0"
|
||||
>
|
||||
Artifact Hub is a web-based application that enables finding, installing, and publishing packages and configurations for CNCF projects. For example, this could include Helm charts and plugins, Falco configurations, Open Policy Agent (OPA) and Gatekeeper policies, OLM operators, Tinkerbell actions, kubectl plugins, Tekton tasks and pipelines, KEDA scalers, CoreDNS plugins, Keptn integrations, container images, Kubewarden policies, Kyverno policies, Knative client, Backstage plugins, Argo templates, KubeArmor policies and KCL modules.
|
||||
Artifact Hub is a web-based application that enables finding, installing, and publishing packages and configurations for CNCF projects. For example, this could include Helm charts and plugins, Falco configurations, Open Policy Agent (OPA) and Gatekeeper policies, OLM operators, Tinkerbell actions, kubectl plugins, Tekton tasks and pipelines, KEDA scalers, CoreDNS plugins, Keptn integrations, container images, Kubewarden policies, Kyverno policies, Knative client, Backstage plugins, Argo templates, KubeArmor policies, KCL modules and Headlamp plugins.
|
||||
<div
|
||||
class="py-0 py-lg-5"
|
||||
>
|
||||
|
|
@ -457,6 +457,32 @@ exports[`Home index creates snapshot 1`] = `
|
|||
<div
|
||||
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
|
||||
>
|
||||
<a
|
||||
aria-label="Open Headlamp site"
|
||||
class="link col iconLink"
|
||||
href="https://headlamp.dev"
|
||||
rel="noopener noreferrer"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
target="_blank"
|
||||
>
|
||||
<div
|
||||
class="d-flex flex-column justify-content-between align-items-center h-100"
|
||||
>
|
||||
<img
|
||||
alt="Icon"
|
||||
class="aboutIcon"
|
||||
src="/static/media/headlamp-light.svg"
|
||||
/>
|
||||
<div
|
||||
class="d-none d-sm-block text-light mt-2 legendIcon"
|
||||
>
|
||||
<small>
|
||||
Headlamp plugins
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
aria-label="Open Helm site"
|
||||
class="link col iconLink"
|
||||
|
|
@ -563,6 +589,10 @@ exports[`Home index creates snapshot 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
|
||||
>
|
||||
<a
|
||||
aria-label="Open Knative client repository"
|
||||
class="link col iconLink"
|
||||
|
|
@ -589,10 +619,6 @@ exports[`Home index creates snapshot 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
|
||||
>
|
||||
<a
|
||||
aria-label="Open Krew site"
|
||||
class="link col iconLink"
|
||||
|
|
@ -697,6 +723,10 @@ exports[`Home index creates snapshot 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
|
||||
>
|
||||
<a
|
||||
aria-label="Open Operator framework site"
|
||||
class="link col iconLink"
|
||||
|
|
@ -723,13 +753,6 @@ exports[`Home index creates snapshot 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
|
||||
>
|
||||
<div
|
||||
class="col"
|
||||
/>
|
||||
<a
|
||||
aria-label="Open Policy Agent site"
|
||||
class="link col iconLink"
|
||||
|
|
@ -808,9 +831,6 @@ exports[`Home index creates snapshot 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div
|
||||
class="col"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
Discovering artifacts to use with CNCF projects can be difficult. If every CNCF project that needs to share artifacts creates its own Hub this creates a fair amount of repeat work for each project and a fractured experience for those trying to find the artifacts to consume. The Artifact Hub attempts to solve that by providing a single experience for consumers that any CNCF project can leverage.
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ describe('Home index', () => {
|
|||
await waitFor(() => expect(API.getStats).toHaveBeenCalledTimes(1));
|
||||
|
||||
const links = await screen.findAllByRole('button');
|
||||
expect(links).toHaveLength(25);
|
||||
expect(links).toHaveLength(26);
|
||||
|
||||
expect(links[2]).toHaveProperty('href', 'https://github.com/artifacthub/hub');
|
||||
expect(links[3]).toHaveProperty('href', 'https://cloud-native.slack.com/channels/artifact-hub');
|
||||
|
|
@ -140,21 +140,22 @@ describe('Home index', () => {
|
|||
expect(links[8]).toHaveProperty('href', 'https://opencontainers.org/');
|
||||
expect(links[9]).toHaveProperty('href', 'https://coredns.io/');
|
||||
expect(links[10]).toHaveProperty('href', 'https://falco.org/');
|
||||
expect(links[11]).toHaveProperty('href', 'https://helm.sh/');
|
||||
expect(links[12]).toHaveProperty('href', 'https://kcl-lang.io/');
|
||||
expect(links[13]).toHaveProperty('href', 'https://keda.sh/');
|
||||
expect(links[14]).toHaveProperty('href', 'https://keptn.sh/');
|
||||
expect(links[15]).toHaveProperty('href', 'https://github.com/knative/client');
|
||||
expect(links[16]).toHaveProperty('href', 'https://krew.sigs.k8s.io/');
|
||||
expect(links[17]).toHaveProperty('href', 'https://kubearmor.io/');
|
||||
expect(links[18]).toHaveProperty('href', 'https://www.kubewarden.io/');
|
||||
expect(links[19]).toHaveProperty('href', 'https://www.kyverno.io/');
|
||||
expect(links[20]).toHaveProperty('href', 'https://github.com/operator-framework');
|
||||
expect(links[21]).toHaveProperty('href', 'https://www.openpolicyagent.org/');
|
||||
expect(links[22]).toHaveProperty('href', 'https://tekton.dev/');
|
||||
expect(links[23]).toHaveProperty('href', 'https://tinkerbell.org/');
|
||||
expect(links[11]).toHaveProperty('href', 'https://headlamp.dev/');
|
||||
expect(links[12]).toHaveProperty('href', 'https://helm.sh/');
|
||||
expect(links[13]).toHaveProperty('href', 'https://kcl-lang.io/');
|
||||
expect(links[14]).toHaveProperty('href', 'https://keda.sh/');
|
||||
expect(links[15]).toHaveProperty('href', 'https://keptn.sh/');
|
||||
expect(links[16]).toHaveProperty('href', 'https://github.com/knative/client');
|
||||
expect(links[17]).toHaveProperty('href', 'https://krew.sigs.k8s.io/');
|
||||
expect(links[18]).toHaveProperty('href', 'https://kubearmor.io/');
|
||||
expect(links[19]).toHaveProperty('href', 'https://www.kubewarden.io/');
|
||||
expect(links[20]).toHaveProperty('href', 'https://www.kyverno.io/');
|
||||
expect(links[21]).toHaveProperty('href', 'https://github.com/operator-framework');
|
||||
expect(links[22]).toHaveProperty('href', 'https://www.openpolicyagent.org/');
|
||||
expect(links[23]).toHaveProperty('href', 'https://tekton.dev/');
|
||||
expect(links[24]).toHaveProperty('href', 'https://tinkerbell.org/');
|
||||
|
||||
expect(links[24]).toHaveProperty('href', 'https://www.cncf.io/sandbox-projects/');
|
||||
expect(links[25]).toHaveProperty('href', 'https://www.cncf.io/sandbox-projects/');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ const HomeView = () => {
|
|||
configurations, Open Policy Agent (OPA) and Gatekeeper policies, OLM operators, Tinkerbell actions,
|
||||
kubectl plugins, Tekton tasks and pipelines, KEDA scalers, CoreDNS plugins, Keptn integrations,
|
||||
container images, Kubewarden policies, Kyverno policies, Knative client, Backstage plugins, Argo
|
||||
templates, KubeArmor policies and KCL modules.
|
||||
templates, KubeArmor policies, KCL modules and Headlamp plugins.
|
||||
<div className="py-0 py-lg-5">
|
||||
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
|
||||
<ExternalLink
|
||||
|
|
@ -293,6 +293,18 @@ const HomeView = () => {
|
|||
</ExternalLink>
|
||||
</div>
|
||||
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
|
||||
<ExternalLink
|
||||
href="https://headlamp.dev"
|
||||
className={`col ${styles.iconLink}`}
|
||||
label="Open Headlamp site"
|
||||
>
|
||||
<div className="d-flex flex-column justify-content-between align-items-center h-100">
|
||||
<RepositoryIcon kind={RepositoryKind.Headlamp} type="white" className={styles.aboutIcon} />
|
||||
<div className={`d-none d-sm-block text-light mt-2 ${styles.legendIcon}`}>
|
||||
<small>Headlamp plugins</small>
|
||||
</div>
|
||||
</div>
|
||||
</ExternalLink>
|
||||
<ExternalLink href="https://helm.sh" className={`col ${styles.iconLink}`} label="Open Helm site">
|
||||
<div className="d-flex flex-column justify-content-between align-items-center h-100">
|
||||
<RepositoryIcon kind={RepositoryKind.Helm} type="white" className={styles.aboutIcon} />
|
||||
|
|
@ -325,6 +337,8 @@ const HomeView = () => {
|
|||
</div>
|
||||
</div>
|
||||
</ExternalLink>
|
||||
</div>
|
||||
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
|
||||
<ExternalLink
|
||||
href="https://github.com/knative/client"
|
||||
className={`col ${styles.iconLink}`}
|
||||
|
|
@ -341,8 +355,6 @@ const HomeView = () => {
|
|||
</div>
|
||||
</div>
|
||||
</ExternalLink>
|
||||
</div>
|
||||
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
|
||||
<ExternalLink
|
||||
href="https://krew.sigs.k8s.io"
|
||||
className={`col ${styles.iconLink}`}
|
||||
|
|
@ -391,6 +403,8 @@ const HomeView = () => {
|
|||
</div>
|
||||
</div>
|
||||
</ExternalLink>
|
||||
</div>
|
||||
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
|
||||
<ExternalLink
|
||||
href="https://github.com/operator-framework"
|
||||
className={`col ${styles.iconLink}`}
|
||||
|
|
@ -403,9 +417,6 @@ const HomeView = () => {
|
|||
</div>
|
||||
</div>
|
||||
</ExternalLink>
|
||||
</div>
|
||||
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
|
||||
<div className="col" />
|
||||
<ExternalLink
|
||||
href="https://www.openpolicyagent.org"
|
||||
className={`col ${styles.iconLink}`}
|
||||
|
|
@ -442,7 +453,6 @@ const HomeView = () => {
|
|||
</div>
|
||||
</div>
|
||||
</ExternalLink>
|
||||
<div className="col" />
|
||||
</div>
|
||||
</div>
|
||||
Discovering artifacts to use with CNCF projects can be difficult. If every CNCF project that needs to
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ const Footer = (props: Props) => {
|
|||
{!whiteLabel && (
|
||||
<div className={`text-center py-2 px-3 px-md-4 ${styles.trademark} trademark`}>
|
||||
<small className="opacity-75">
|
||||
© 2022{' '}
|
||||
© 2024{' '}
|
||||
<ExternalLink className="opacity-100 text-white" href="https://linuxfoundation.org/">
|
||||
The Linux Foundation
|
||||
</ExternalLink>
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ exports[`Footer creates snapshot 1`] = `
|
|||
<small
|
||||
class="opacity-75"
|
||||
>
|
||||
© 2022
|
||||
© 2024
|
||||
<a
|
||||
aria-label="Open external link"
|
||||
class="link opacity-100 text-white"
|
||||
|
|
|
|||
|
|
@ -26,3 +26,8 @@
|
|||
.icon {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-size: 0.65rem;
|
||||
line-height: 0.65rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { useCallback, useEffect, useState } from 'react';
|
|||
import {
|
||||
ArgoTemplateData,
|
||||
Channel,
|
||||
HeadlampData,
|
||||
HelmChartType,
|
||||
KeptnData,
|
||||
KubewardenData,
|
||||
|
|
@ -15,6 +16,7 @@ import {
|
|||
RepositoryKind,
|
||||
Version as VersionData,
|
||||
} from '../../types';
|
||||
import ButtonCopyToClipboard from '../common/ButtonCopyToClipboard';
|
||||
import RSSLinkTitle from '../common/RSSLinkTitle';
|
||||
import SeeAllModal from '../common/SeeAllModal';
|
||||
import SmallTitle from '../common/SmallTitle';
|
||||
|
|
@ -24,6 +26,7 @@ import ContainerRegistry from './ContainerRegistry';
|
|||
import ContainersImages from './ContainersImages';
|
||||
import Dependencies from './Dependencies';
|
||||
import styles from './Details.module.css';
|
||||
import Flavors from './Flavors';
|
||||
import Keywords from './Keywords';
|
||||
import Last30DaysViews from './Last30DaysViews';
|
||||
import LastYearActivity from './LastYearActivity';
|
||||
|
|
@ -166,6 +169,8 @@ const Details = (props: Props) => {
|
|||
case RepositoryKind.Keptn:
|
||||
case RepositoryKind.Kubewarden:
|
||||
case RepositoryKind.Gatekeeper:
|
||||
case RepositoryKind.KCL:
|
||||
case RepositoryKind.Headlamp:
|
||||
return (
|
||||
<>
|
||||
{props.package.appVersion && (
|
||||
|
|
@ -443,6 +448,51 @@ const Details = (props: Props) => {
|
|||
</>
|
||||
);
|
||||
|
||||
case RepositoryKind.Headlamp:
|
||||
return (
|
||||
<>
|
||||
{props.package.data &&
|
||||
(props.package.data[HeadlampData.Url] || props.package.data[HeadlampData.Checksum]) && (
|
||||
<div>
|
||||
<SmallTitle text="Plugin archive" />
|
||||
<div className="d-flex flex-row mb-3">
|
||||
{props.package.data[HeadlampData.Url] && (
|
||||
<ButtonCopyToClipboard
|
||||
text={props.package.data[HeadlampData.Url]}
|
||||
contentBtn="URL"
|
||||
title={props.package.data[HeadlampData.Url]}
|
||||
visibleBtnText
|
||||
className={`btn btn-outline-secondary btn-sm p-1 me-2 ${styles.btn}`}
|
||||
label="Copy url to clipboard"
|
||||
/>
|
||||
)}
|
||||
{props.package.data[HeadlampData.Checksum] && (
|
||||
<ButtonCopyToClipboard
|
||||
text={props.package.data[HeadlampData.Checksum]}
|
||||
contentBtn="CHECKSUM"
|
||||
title={props.package.data[HeadlampData.Checksum]}
|
||||
visibleBtnText
|
||||
className={`btn btn-outline-secondary btn-sm p-1 ${styles.btn}`}
|
||||
label="Copy checksum to clipboard"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{props.package.data && props.package.data[HeadlampData.Version] && (
|
||||
<div>
|
||||
<SmallTitle text="Headlamp version" />
|
||||
<p data-testid="headlampVersion" className={`text-truncate ${styles.text}`}>
|
||||
{props.package.data[HeadlampData.Version]}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{props.package.data && props.package.data[HeadlampData.Flavors] && (
|
||||
<Flavors title="Headlamp Flavors" flavors={props.package.data[HeadlampData.Flavors]} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
.text {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
import Flavors from './Flavors';
|
||||
|
||||
const defaultProps = {
|
||||
flavors: 'in-cluster,web,docker-desktop',
|
||||
title: 'Headlamp Flavors',
|
||||
};
|
||||
|
||||
describe('Flavors', () => {
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('creates snapshot', () => {
|
||||
const { asFragment } = render(<Flavors {...defaultProps} />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('Render', () => {
|
||||
it('renders component', () => {
|
||||
render(<Flavors {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText('Headlamp Flavors')).toBeInTheDocument();
|
||||
const flavors = screen.getAllByTestId('flavor');
|
||||
expect(flavors).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('renders only uniq flavors', () => {
|
||||
render(<Flavors flavors={`${defaultProps.flavors} web`} title="Headlamp Flavors" />);
|
||||
|
||||
const flavors = screen.getAllByTestId('flavor');
|
||||
expect(flavors).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('does not render component if platforms is undefined', () => {
|
||||
const { container } = render(<Flavors title="Headlamp Flavors" />);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import compact from 'lodash/compact';
|
||||
import trim from 'lodash/trim';
|
||||
import uniq from 'lodash/uniq';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import SmallTitle from '../common/SmallTitle';
|
||||
import styles from './Flavors.module.css';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
flavors?: string;
|
||||
}
|
||||
|
||||
const Flavors = (props: Props) => {
|
||||
const cleanFlavors = useCallback((): string[] => {
|
||||
let flavors: string[] = [];
|
||||
if (props.flavors) {
|
||||
flavors = uniq(compact(props.flavors.split(',')));
|
||||
}
|
||||
|
||||
return flavors;
|
||||
}, [props.flavors]);
|
||||
|
||||
const [flavors, setFlavors] = useState<string[]>(cleanFlavors());
|
||||
|
||||
useEffect(() => {
|
||||
setFlavors(cleanFlavors());
|
||||
}, [cleanFlavors, props.flavors]);
|
||||
|
||||
if (flavors.length === 0) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<SmallTitle text={props.title} />
|
||||
<div className="mb-3">
|
||||
{flavors.map((flavor: string) => (
|
||||
<div data-testid="flavor" className={`text-truncate mb-1 ${styles.text}`} key={`flavor_${flavor}`}>
|
||||
<div className="d-flex align-items-center">
|
||||
<span className="pe-1">·</span>
|
||||
<small>{trim(flavor)}</small>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Flavors;
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Flavors creates snapshot 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="mt-2 mb-1 undefined"
|
||||
data-testid="smallTitle"
|
||||
>
|
||||
<small
|
||||
class="card-title text-muted text-uppercase"
|
||||
>
|
||||
<span
|
||||
aria-level="5"
|
||||
role="heading"
|
||||
>
|
||||
Headlamp Flavors
|
||||
</span>
|
||||
</small>
|
||||
</div>
|
||||
<div
|
||||
class="mb-3"
|
||||
>
|
||||
<div
|
||||
class="text-truncate mb-1 text"
|
||||
data-testid="flavor"
|
||||
>
|
||||
<div
|
||||
class="d-flex align-items-center"
|
||||
>
|
||||
<span
|
||||
class="pe-1"
|
||||
>
|
||||
·
|
||||
</span>
|
||||
<small>
|
||||
in-cluster
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-truncate mb-1 text"
|
||||
data-testid="flavor"
|
||||
>
|
||||
<div
|
||||
class="d-flex align-items-center"
|
||||
>
|
||||
<span
|
||||
class="pe-1"
|
||||
>
|
||||
·
|
||||
</span>
|
||||
<small>
|
||||
web
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-truncate mb-1 text"
|
||||
data-testid="flavor"
|
||||
>
|
||||
<div
|
||||
class="d-flex align-items-center"
|
||||
>
|
||||
<span
|
||||
class="pe-1"
|
||||
>
|
||||
·
|
||||
</span>
|
||||
<small>
|
||||
docker-desktop
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
|
@ -22,6 +22,7 @@ export enum RepositoryKind {
|
|||
ArgoTemplate,
|
||||
KubeArmor,
|
||||
KCL,
|
||||
Headlamp,
|
||||
}
|
||||
|
||||
export enum PackageCategory {
|
||||
|
|
@ -52,6 +53,13 @@ export enum KyvernoData {
|
|||
Category = 'kyvernoCategory',
|
||||
}
|
||||
|
||||
export enum HeadlampData {
|
||||
Url = 'headlampPluginArchiveUrl',
|
||||
Checksum = 'headlampPluginArchiveChecksum',
|
||||
Version = 'headlampPluginVersionCompat',
|
||||
Flavors = 'headlampPluginDistroCompat',
|
||||
}
|
||||
|
||||
export enum HelmChartType {
|
||||
Library = 'library',
|
||||
Application = 'application',
|
||||
|
|
@ -255,6 +263,10 @@ export interface PackageData {
|
|||
[KyvernoData.Version]?: string;
|
||||
[KyvernoData.Category]?: string;
|
||||
[KyvernoData.KubernetesVersion]?: string;
|
||||
[HeadlampData.Url]?: string;
|
||||
[HeadlampData.Checksum]?: string;
|
||||
[HeadlampData.Version]?: string;
|
||||
[HeadlampData.Flavors]?: string;
|
||||
[ArgoTemplateData.Version]?: string;
|
||||
tasks?: TektonTaskInPipeline[];
|
||||
alternativeLocations?: string[];
|
||||
|
|
|
|||
|
|
@ -132,6 +132,24 @@ export const REPOSITORY_KINDS: RepoKindDef[] = [
|
|||
icon: <RepositoryIcon kind={RepositoryKind.Falco} className="mw-100 mh-100" />,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
kind: RepositoryKind.Gatekeeper,
|
||||
label: 'gatekeeper',
|
||||
name: 'Gatekeeper policies',
|
||||
singular: 'Gatekeeper policy',
|
||||
plural: 'Gatekeeper policies',
|
||||
icon: <RepositoryIcon kind={RepositoryKind.Gatekeeper} className="mw-100 mh-100" />,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
kind: RepositoryKind.Headlamp,
|
||||
label: 'headlamp',
|
||||
name: 'Headlamp plugins',
|
||||
singular: 'Headlamp plugin',
|
||||
plural: 'Headlamp plugins',
|
||||
icon: <RepositoryIcon kind={RepositoryKind.Headlamp} className="mw-100 mh-100" />,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
kind: RepositoryKind.Helm,
|
||||
label: 'helm',
|
||||
|
|
@ -150,15 +168,6 @@ export const REPOSITORY_KINDS: RepoKindDef[] = [
|
|||
icon: <RepositoryIcon kind={RepositoryKind.Helm} className="mw-100 mh-100" />,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
kind: RepositoryKind.Gatekeeper,
|
||||
label: 'gatekeeper',
|
||||
name: 'Gatekeeper policies',
|
||||
singular: 'Gatekeeper policy',
|
||||
plural: 'Gatekeeper policies',
|
||||
icon: <RepositoryIcon kind={RepositoryKind.Gatekeeper} className="mw-100 mh-100" />,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
kind: RepositoryKind.KCL,
|
||||
label: 'kcl',
|
||||
|
|
@ -777,7 +786,7 @@ export const CVSS_V3_VECTORS: { [key: string]: CVSSVectorMetric[] } = {
|
|||
export const OCI_PREFIX = 'oci://';
|
||||
|
||||
export const PKG_DETAIL_PATH =
|
||||
/^\/packages\/(helm|falco|opa|olm|tbaction|krew|helm-plugin|tekton-task|keda-scaler|coredns|keptn|tekton-pipeline|kubewarden|gatekeeper|kyverno|knative-client-plugin|backstage|argo-template|kubearmor|kcl|container)\//;
|
||||
/^\/packages\/(helm|falco|opa|olm|tbaction|krew|helm-plugin|tekton-task|keda-scaler|coredns|keptn|tekton-pipeline|kubewarden|gatekeeper|kyverno|knative-client-plugin|backstage|argo-template|kubearmor|kcl|headlamp|container)\//;
|
||||
|
||||
export const HOME_ROUTES = [
|
||||
'/verify-email',
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ const getRepoKind = (repoName: string): RepositoryKind | null => {
|
|||
return RepositoryKind.KubeArmor;
|
||||
case 'kcl':
|
||||
return RepositoryKind.KCL;
|
||||
case 'headlamp':
|
||||
return RepositoryKind.Headlamp;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
@ -93,6 +95,8 @@ const getRepoKindName = (repoKind: RepositoryKind): string | null => {
|
|||
return 'kubearmor';
|
||||
case RepositoryKind.KCL:
|
||||
return 'kcl';
|
||||
case RepositoryKind.Headlamp:
|
||||
return 'headlamp';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
<div class="artifacthub-widget-group" data-url="http://localhost:8000/packages/search?kind=21&sort=relevance&page=1" data-theme="light" data-header="false" data-stars="true" data-color="#417598" data-responsive="true" data-loading="true"></div>
|
||||
<div class="artifacthub-widget-group" data-url="http://localhost:8000/packages/search?kind=21&sort=relevance&page=1" data-theme="dark" data-header="false" data-stars="true" data-color="#417598" data-responsive="true" data-loading="true"></div>
|
||||
<div class="artifacthub-widget-group" data-url="http://localhost:8000/packages/search?kind=20&sort=relevance&page=1" data-theme="light" data-header="false" data-stars="true" data-color="#417598" data-responsive="true" data-loading="true"></div>
|
||||
<div class="artifacthub-widget-group" data-url="http://localhost:8000/packages/search?repo=kubearmor&sort=relevance&page=1" data-theme="light" data-header="false" data-stars="true" data-color="#417598" data-responsive="true" data-loading="true"></div>
|
||||
<div class="artifacthub-widget-group" data-url="http://localhost:8000/packages/search?kind=0&deprecated=true&sort=relevance&page=1" data-theme="light" data-header="false" data-stars="true" data-color="#417598" data-responsive="true" data-loading="true"></div>
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ const getRepoKindName = (repoKind: RepositoryKind): string | null => {
|
|||
return 'kubearmor';
|
||||
case RepositoryKind.KCL:
|
||||
return 'kcl';
|
||||
case RepositoryKind.Headlamp:
|
||||
return 'headlamp';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,6 +158,13 @@ describe('Image', () => {
|
|||
expect(image).toHaveProperty('src', 'https://localhost:8000/static/media/placeholder_pkg_kcl.png');
|
||||
});
|
||||
|
||||
it('renders Headlamp icon', () => {
|
||||
render(<Image {...defaultProps} kind={RepositoryKind.Headlamp} />);
|
||||
const image = screen.getByAltText('alt image');
|
||||
expect(image).toBeInTheDocument();
|
||||
expect(image).toHaveProperty('src', 'https://localhost:8000/static/media/placeholder_pkg_headlamp.png');
|
||||
});
|
||||
|
||||
it('renders placeholder icon', () => {
|
||||
render(<Image {...defaultProps} placeholderIcon={<>icon</>} />);
|
||||
expect(screen.getByText('icon')).toBeInTheDocument();
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ const Image = (props: Props) => {
|
|||
return '/static/media/placeholder_pkg_kubearmor.png';
|
||||
case RepositoryKind.KCL:
|
||||
return '/static/media/placeholder_pkg_kcl.png';
|
||||
case RepositoryKind.Headlamp:
|
||||
return '/static/media/placeholder_pkg_headlamp.png';
|
||||
default:
|
||||
return PLACEHOLDER_SRC;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ const ICONS: IconsList = {
|
|||
[RepositoryKind.ArgoTemplate]: <SVGIcons name="argo" />,
|
||||
[RepositoryKind.KubeArmor]: <SVGIcons name="kubearmor" />,
|
||||
[RepositoryKind.KCL]: <SVGIcons name="kcl" />,
|
||||
[RepositoryKind.Headlamp]: <SVGIcons name="headlamp" />,
|
||||
};
|
||||
|
||||
const RepositoryIcon = (props: Props) => (
|
||||
|
|
|
|||
|
|
@ -100,6 +100,10 @@ const REPOSITORY_KINDS: RepoKindDef[] = [
|
|||
kind: RepositoryKind.KCL,
|
||||
name: 'KCL module',
|
||||
},
|
||||
{
|
||||
kind: RepositoryKind.Headlamp,
|
||||
name: 'Headlamp plugin',
|
||||
},
|
||||
];
|
||||
|
||||
const Wrapper = styled('span')`
|
||||
|
|
|
|||
|
|
@ -118,6 +118,11 @@ describe('SVGIcons', () => {
|
|||
expect(screen.getByTitle('kcl'));
|
||||
});
|
||||
|
||||
it('renders Headlamp icon', () => {
|
||||
render(<SVGIcons name="headlamp" />);
|
||||
expect(screen.getByTitle('headlamp'));
|
||||
});
|
||||
|
||||
it('does not render when name is not in the list', () => {
|
||||
render(<SVGIcons name="not-listed" />);
|
||||
expect(screen.getByTestId('iconWrapper')).toBeEmptyDOMElement();
|
||||
|
|
|
|||
|
|
@ -939,6 +939,21 @@ const SVGIcons = (props: Props) => (
|
|||
</svg>
|
||||
);
|
||||
|
||||
case 'headlamp':
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<title>{props.name}</title>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M407.951 324.939V204.686l-31.84-41.506V93.246L274.052 56.573V0H133.899v56.573L31.839 93.246v69.934L0 204.686v120.253l31.84 42.928L0 466.798 204.117 512l203.834-45.202-31.84-98.931 31.84-42.928Z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFF200"
|
||||
d="M204.118 367.867c56.288 0 102.058-45.77 102.058-102.059 0-56.289-45.77-102.059-102.058-102.059-56.289 0-102.059 45.77-102.059 102.059 0 56.289 45.77 102.059 102.059 102.059Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
case 'kubewarden':
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 135 135">
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export enum RepositoryKind {
|
|||
ArgoTemplate,
|
||||
KubeArmor,
|
||||
KCL,
|
||||
Headlamp,
|
||||
}
|
||||
|
||||
export interface SearchResults {
|
||||
|
|
|
|||
Loading…
Reference in New Issue