Skip to content

Commit

Permalink
Remove Logo Trademarks from the Jupyter Web App and make logos config…
Browse files Browse the repository at this point in the history
…urable (kubeflow#5823)

* rebase: Make logos configurable in configmap and remove trademark references

Rebased to remove the changes to the package-lock.json

* review: add suggested changes and add image group section to README
  • Loading branch information
davidspek committed Apr 13, 2021
1 parent 8a12599 commit d73e468
Show file tree
Hide file tree
Showing 27 changed files with 333 additions and 339 deletions.
26 changes: 26 additions & 0 deletions components/crud-web-apps/jupyter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@

This web app is responsible for allowing the user to manipulate the Jupyter Notebooks in their Kubeflow cluster. To achieve this it provides a user friendly way to handle the lifecycle of Notebook CRs.

## Image Groups

With the release of Kubeflow 1.3, two types have Notebook Servers have been added
alongside the familiar JupyterLab:

- Group 1
- Group 2

Some extra configurations are applied Notebook Servers belonging to these groups:

The annotation `notebooks.kubeflow.org/http-rewrite-uri: /` is added to Notebook
resources of both groups. This configures Istio to rewrite the URI to `/` on
the container. This is useful for applications which host their on `/`
and do not allow you to change the URI subpath easily.

The annotation `notebooks.kubeflow.org/http-headers-request-set:`
`'{"X-RStudio-Root-Path":"/notebook/<namespace>/<name>/"}'` is added to
Notebook resources belonging to Group 2. This configures Istio to add
this header to requests, which is necessary for images from Group 2 to work.

The Jupyter Web App displays the logos for each Notebook Server group
in a button toggle in the Spawner UI. To easily identify the group of
a running Notebook Server, the Index page contains a column that displays
the icon for each image group. The SVG logos and icons for each group are added
with a [configmap](./manifests/base/configs/logos-configmap.yaml) to make it easy for users to customize the logos and icons for their environment.

## Development

Requirements:
Expand Down
6 changes: 3 additions & 3 deletions components/crud-web-apps/jupyter/backend/apps/common/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def set_notebook_image_pull_policy(notebook, body, defaults):


def set_server_type(notebook, body, defaults):
valid_server_types = ["jupyter", "vs-code", "rstudio"]
valid_server_types = ["jupyter", "group-one", "group-two"]
notebook_annotations = notebook["metadata"]["annotations"]
server_type = get_form_value(body, defaults, "serverType")
if server_type == "":
Expand All @@ -153,9 +153,9 @@ def set_server_type(notebook, body, defaults):
rstudio_header = '{"X-RStudio-Root-Path":"/notebook/%s/%s/"}' % (nb_ns,
nb_name)
notebook_annotations[SERVER_TYPE_ANNOTATION] = server_type
if server_type == "vs-code" or server_type == "rstudio":
if server_type == "group-one" or server_type == "group-two":
notebook_annotations[URI_REWRITE_ANNOTATION] = "/"
if server_type == "rstudio":
if server_type == "group-two":
notebook_annotations[HEADERS_ANNOTATION] = rstudio_header


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,23 @@ spawnerFormDefaults:
- public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/jupyter-pytorch-cuda-full:master-1831e436
- public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/jupyter-tensorflow-full:master-1831e436
- public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/jupyter-tensorflow-cuda-full:master-1831e436
imageVSCode:
# The container Image for the user's VS-Code Server
imageGroupOne:
# The container Image for the user's Group One Server
# The annotation `notebooks.kubeflow.org/http-rewrite-uri: /`
# is applied to notebook in this group, configuring
# the Istio rewrite for containers that host their web UI at `/`
value: public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/codeserver-python:master-1831e436
# The list of available standard container Images
options:
- public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/codeserver-python:master-1831e436
imageRStudio:
# The container Image for the user's RStudio Server
imageGroupTwo:
# The container Image for the user's Group Two Server
# The annotation `notebooks.kubeflow.org/http-rewrite-uri: /`
# is applied to notebook in this group, configuring
# the Istio rewrite for containers that host their web UI at `/`
# The annotation `notebooks.kubeflow.org/http-headers-request-set`
# is applied to notebook in this group, configuring Istio
# to add the `X-RStudio-Root-Path` header to requests
value: public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/rstudio-tidyverse:master-164fa2ea
# The list of available standard container Images
options:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<app-form-image
[parentForm]="formCtrl"
[images]="config?.image?.options"
[imagesVSCode]="config?.imageVSCode?.options"
[imagesRStudio]="config?.imageRStudio?.options"
[imagesGroupOne]="config?.imageGroupOne?.options"
[imagesGroupTwo]="config?.imageGroupTwo?.options"
[allowCustomImage]="config?.allowCustomImage"
></app-form-image>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,17 @@ export class FormDefaultComponent implements OnInit, OnDestroy {
// Use the custom image instead
if (notebook.customImageCheck) {
notebook.image = notebook.customImage;
} else if (notebook.serverType === 'vs-code') {
// Set notebook image from imageVSCode
notebook.image = notebook.imageVSCode;
} else if (notebook.serverType === 'rstudio') {
// Set notebook image from imageRStudio
notebook.image = notebook.imageRStudio;
} else if (notebook.serverType === 'group-one') {
// Set notebook image from imageGroupOne
notebook.image = notebook.imageGroupOne;
} else if (notebook.serverType === 'group-two') {
// Set notebook image from imageGroupTwo
notebook.image = notebook.imageGroupTwo;
}

// Remove unnecessary images from the request sent to the backend
delete notebook.imageVSCode;
delete notebook.imageRStudio;
delete notebook.imageGroupOne;
delete notebook.imageGroupTwo;

// Ensure CPU input is a string
if (typeof notebook.cpu === 'number') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@
>
<mat-icon class="server-type" svgIcon="jupyterlab"></mat-icon>
</mat-button-toggle>
<mat-button-toggle value="vs-code" aria-label="Use VS-Code based server">
<mat-icon class="server-type" svgIcon="vs-code"></mat-icon>
<mat-button-toggle
value="group-one"
aria-label="Use Group One based server"
>
<mat-icon class="server-type" svgIcon="group-one"></mat-icon>
</mat-button-toggle>
<mat-button-toggle
value="rstudio"
aria-label="Use RStudio based server"
matTooltip="RStudio® and the RStudio logo are registered trademarks of RStudio, PBC"
matTooltipPosition="after"
value="group-two"
aria-label="Use Group Two based server"
>
<mat-icon class="server-type" svgIcon="rstudio"></mat-icon>
<mat-icon class="server-type" svgIcon="group-two"></mat-icon>
</mat-button-toggle>
</mat-button-toggle-group>
</div>
Expand Down Expand Up @@ -63,16 +64,16 @@
appearance="outline"
*ngIf="
!parentForm?.value.customImageCheck &&
parentForm?.value.serverType === 'vs-code'
parentForm?.value.serverType === 'group-one'
"
>
<!-- If readonly, then make it an input element instead of select -->
<mat-label>Image</mat-label>
<mat-select
placeholder="Docker Image"
[formControl]="parentForm.get('imageVSCode')"
[formControl]="parentForm.get('imageGroupOne')"
>
<mat-option *ngFor="let img of imagesVSCode" [value]="img">
<mat-option *ngFor="let img of imagesGroupOne" [value]="img">
{{ img }}
</mat-option>
</mat-select>
Expand All @@ -84,16 +85,16 @@
appearance="outline"
*ngIf="
!parentForm?.value.customImageCheck &&
parentForm?.value.serverType === 'rstudio'
parentForm?.value.serverType === 'group-two'
"
>
<!-- If readonly, then make it an input element instead of select -->
<mat-label>Image</mat-label>
<mat-select
placeholder="Docker Image"
[formControl]="parentForm.get('imageRStudio')"
[formControl]="parentForm.get('imageGroupTwo')"
>
<mat-option *ngFor="let img of imagesRStudio" [value]="img">
<mat-option *ngFor="let img of imagesGroupTwo" [value]="img">
{{ img }}
</mat-option>
</mat-select>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { MatIconRegistry } from '@angular/material/icon';
export class FormImageComponent implements OnInit, OnDestroy {
@Input() parentForm: FormGroup;
@Input() images: string[];
@Input() imagesVSCode: string[];
@Input() imagesRStudio: string[];
@Input() imagesGroupOne: string[];
@Input() imagesGroupTwo: string[];
@Input() allowCustomImage: boolean;

subs = new Subscription();
Expand All @@ -25,12 +25,12 @@ export class FormImageComponent implements OnInit, OnDestroy {
sanitizer.bypassSecurityTrustResourceUrl(environment.jupyterlabLogo),
);
iconRegistry.addSvgIcon(
'vs-code',
sanitizer.bypassSecurityTrustResourceUrl(environment.vscodeLogo),
'group-one',
sanitizer.bypassSecurityTrustResourceUrl(environment.groupOneLogo),
);
iconRegistry.addSvgIcon(
'rstudio',
sanitizer.bypassSecurityTrustResourceUrl(environment.rstudioLogo),
'group-two',
sanitizer.bypassSecurityTrustResourceUrl(environment.groupTwoLogo),
);
}

Expand All @@ -41,33 +41,33 @@ export class FormImageComponent implements OnInit, OnDestroy {
if (check) {
this.parentForm.get('customImage').setValidators(Validators.required);
this.parentForm.get('image').setValidators([]);
this.parentForm.get('imageVSCode').setValidators([]);
this.parentForm.get('imageRStudio').setValidators([]);
this.parentForm.get('imageGroupOne').setValidators([]);
this.parentForm.get('imageGroupTwo').setValidators([]);
}
this.parentForm.get('serverType').valueChanges.subscribe(selection => {
if (selection === 'jupyter') {
this.parentForm.get('customImage').setValidators([]);
this.parentForm.get('image').setValidators(Validators.required);
this.parentForm.get('imageVSCode').setValidators([]);
this.parentForm.get('imageRStudio').setValidators([]);
} else if (selection === 'vs-code') {
this.parentForm.get('imageGroupOne').setValidators([]);
this.parentForm.get('imageGroupTwo').setValidators([]);
} else if (selection === 'group-one') {
this.parentForm.get('customImage').setValidators([]);
this.parentForm.get('image').setValidators([]);
this.parentForm
.get('imageVSCode')
.get('imageGroupOne')
.setValidators(Validators.required);
this.parentForm.get('imageRStudio').setValidators([]);
} else if (selection === 'rstudio') {
this.parentForm.get('imageGroupTwo').setValidators([]);
} else if (selection === 'group-two') {
this.parentForm.get('customImage').setValidators([]);
this.parentForm.get('image').setValidators([]);
this.parentForm.get('imageVSCode').setValidators([]);
this.parentForm.get('imageGroupOne').setValidators([]);
this.parentForm
.get('imageRStudio')
.get('imageGroupTwo')
.setValidators(Validators.required);
}
this.parentForm.get('image').updateValueAndValidity();
this.parentForm.get('imageVSCode').updateValueAndValidity();
this.parentForm.get('imageRStudio').updateValueAndValidity();
this.parentForm.get('imageGroupOne').updateValueAndValidity();
this.parentForm.get('imageGroupTwo').updateValueAndValidity();
});
this.parentForm.get('customImage').updateValueAndValidity();
this.parentForm.get('serverType').updateValueAndValidity();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export function getFormDefaults(): FormGroup {
name: ['', [Validators.required]],
namespace: ['', [Validators.required]],
image: ['', [Validators.required]],
imageVSCode: ['', [Validators.required]],
imageRStudio: ['', [Validators.required]],
imageGroupOne: ['', [Validators.required]],
imageGroupTwo: ['', [Validators.required]],
allowCustomImage: [true, []],
imagePullPolicy: ['IfNotPresent', [Validators.required]],
customImage: ['', []],
Expand Down Expand Up @@ -151,9 +151,9 @@ export function initFormControls(formCtrl: FormGroup, config: Config) {

formCtrl.controls.image.setValue(config.image.value);

formCtrl.controls.imageVSCode.setValue(config.imageVSCode.value);
formCtrl.controls.imageGroupOne.setValue(config.imageGroupOne.value);

formCtrl.controls.imageRStudio.setValue(config.imageRStudio.value);
formCtrl.controls.imageGroupTwo.setValue(config.imageGroupTwo.value);

formCtrl.controls.imagePullPolicy.setValue(config.imagePullPolicy.value);
if (config.imagePullPolicy.readOnly) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<app-form-image
[parentForm]="formCtrl"
[images]="config?.image?.options"
[imagesVSCode]="config?.imageVSCode?.options"
[imagesRStudio]="config?.imageRStudio?.options"
[imagesGroupOne]="config?.imageGroupOne?.options"
[imagesGroupTwo]="config?.imageGroupTwo?.options"
[allowCustomImage]="config?.allowCustomImage"
></app-form-image>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
aria-label="JupyterLab based server"
></mat-icon>
<mat-icon
*ngIf="notebookServerType === 'vs-code'"
svgIcon="vs-code-icon"
*ngIf="notebookServerType === 'group-one'"
svgIcon="group-one-icon"
aria-hidden="false"
aria-label="VS-Code based server"
aria-label="Group One based server"
></mat-icon>
<mat-icon
*ngIf="notebookServerType === 'rstudio'"
svgIcon="rstudio-icon"
*ngIf="notebookServerType === 'group-two'"
svgIcon="group-two-icon"
aria-hidden="false"
aria-label="RStudio based server"
matTooltip="RStudio® and the RStudio logo are registered trademarks of RStudio, PBC"
aria-label="Group Two based server"
></mat-icon>
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ export class ServerTypeComponent implements TableColumnComponent {
sanitizer.bypassSecurityTrustResourceUrl(environment.jupyterIcon),
);
iconRegistry.addSvgIcon(
'vs-code-icon',
sanitizer.bypassSecurityTrustResourceUrl(environment.vscodeIcon),
'group-one-icon',
sanitizer.bypassSecurityTrustResourceUrl(environment.groupOneIcon),
);
iconRegistry.addSvgIcon(
'rstudio-icon',
sanitizer.bypassSecurityTrustResourceUrl(environment.rstudioIcon),
'group-two-icon',
sanitizer.bypassSecurityTrustResourceUrl(environment.groupTwoIcon),
);
}

Expand Down
10 changes: 5 additions & 5 deletions components/crud-web-apps/jupyter/frontend/src/app/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface JWABackendResponse extends BackendResponse {
vendors?: string[];
}

export type ServerType = 'jupyter' | 'vscode' | 'rstudio';
export type ServerType = 'jupyter' | 'group-one' | 'group-two';

export interface NotebookResponseObject {
name: string;
Expand Down Expand Up @@ -39,8 +39,8 @@ export interface NotebookFormObject {
name: string;
namespace: string;
image: string;
imageVSCode: string;
imageRStudio: string;
imageGroupOne: string;
imageGroupTwo: string;
allowCustomImage: boolean;
imagePullPolicy: string;
customImage?: string;
Expand Down Expand Up @@ -142,12 +142,12 @@ export interface Config {
options: string[];
};

imageVSCode?: {
imageGroupOne?: {
value: string;
options: string[];
};

imageRStudio?: {
imageGroupTwo?: {
value: string;
options: string[];
};
Expand Down
Loading

0 comments on commit d73e468

Please sign in to comment.