berkeley-dsep-infra / datahub

JupyterHubs for use by Berkeley enrolled students
https://docs.datahub.berkeley.edu
BSD 3-Clause "New" or "Revised" License
62 stars 37 forks source link

Add customizable datahub branding for hub admins #3248

Open aculich opened 2 years ago

aculich commented 2 years ago

Summary

A branding mechanism would help to more easily & quickly distinguish at a glance between multiple datahubs.

User Stories

Acceptance criteria

Important information

Tasks to complete

balajialg commented 2 years ago

@aculich Thanks for raising this request. It comes at the right time as we are also working on creating branding collaterals for Datahub which includes a logo. I will scope this request for discussion during the March sprint and hope that your request is not a time-sensitive one. Let us know!

aculich commented 2 years ago

Not time-sensitive at the moment, but a nice-to-have especially if we start using it more heavily in the future.

balajialg commented 2 years ago

@yuvipanda nudge to add your suggestions from the sprint planning meeting!

yuvipanda commented 2 years ago

@aculich the homepage (pre-login) is easily customizable by forking https://github.com/berkeley-dsep-infra/datahub-homepage, which has all the HTML, CSS and images for https://datahub.berkeley.edu. If you can do that, we can then use the same image on the top left. How does that sound?

aculich commented 2 years ago

I added dlab-logo-with-url.svg to: https://github.com/berkeley-dsep-infra/datahub-homepage/tree/master/extra-assets/images

Looks like I had commit access (which I didn't realize) so I ended up uploading it directly instead of in a fork (oops, sorry if that's bad?!)

From here, how do I get the dlab deployment to use this custom image?

balajialg commented 2 years ago

@aculich Did you have any luck with adding Dlab's logo in the deployment? I am also currently in the process of figuring out the steps to add the latest logo for Datahub (Check here)

@yuvipanda @ryanlovett Can you please share the detailed steps to change the logo for a particular hub deployment! It will be helpful to keep this GitHub issue as a source of truth for any such requests in the future. Thanks!

ryanlovett commented 2 years ago

@yuvipanda @felder re: disambiguating hubs, custom logos, etc.

balajialg commented 2 years ago
felder commented 2 years ago

@balajialg looking through the info there, I have had some limited success.

On a local branch I modified https://github.com/berkeley-dsep-infra/datahub/blob/staging/deployments/datahub/config/common.yaml and added the following directive to hub: -> extraConfig: underneath the custom theme.

    extraConfig:
      04-custom-theme: |
        c.JupyterHub.template_paths = ['/usr/local/share/jupyterhub/custom_templates/']

Change starts here:

      logoConfig: |
        import urllib.request
        urllib.request.urlretrieve("https://www.isabellacounty.org/wp-content/uploads/2022/04/computer.jpg", "mylogo.png")
        c.JupyterHub.logo_file = '/srv/jupyterhub/mylogo.png'

I then used hubploy to push that change to staging. It seems to work, is currently live on datahub staging, and will be until someone sends something else to staging. Check it out if you get a chance.

However, this is not ideal since the image is being pulled from an external source. I believe what we could do here is modify our hub image here:

https://github.com/berkeley-dsep-infra/datahub/blob/staging/images/hub/Dockerfile

To include all of the custom logo images and then modify the configs for each hub to use the appropriate custom logo as indicated in the logoConfig block above.

felder commented 2 years ago

Ok this closed PR (I did not want to merge this) shows what needs to occur:

https://github.com/berkeley-dsep-infra/datahub/pull/3500/files

Of particular interest is this configuration that tells the hub to use the custom logo: https://github.com/berkeley-dsep-infra/datahub/blob/c3366a39ff828b24636349c2d6d67ffd4c5363b2/deployments/datahub/config/common.yaml#L84

Where the Dockerfile for the hub pod is modified to have the custom logo: https://github.com/berkeley-dsep-infra/datahub/blob/c3366a39ff828b24636349c2d6d67ffd4c5363b2/images/hub/Dockerfile#L10

The addition of the custom logo itself: https://github.com/berkeley-dsep-infra/datahub/blob/c3366a39ff828b24636349c2d6d67ffd4c5363b2/images/hub/logos/computer.jpg

The wizardry for this was asking Yuvi how to push changes to the hub pod which is done using chartpress --push

The format for the dlab custom logo (SVG) can't be displayed. We need a standard image format such as png or jpg, and we should be mindful of where the logo is being displayed (it's tiny!). Once we have a suitable image for this, I should be able to move forward with adding it.

Ryan pointed me to docs for rebuilding the hub image: https://docs.datahub.berkeley.edu/en/latest/admins/howto/rebuild-hub-image.html

balajialg commented 2 years ago

Thanks, @felder for figuring out the way forward!

@aculich In order for us to execute your request, we will require the D-Lab logo as a PNG/JPG image in the dimensions 416x80 at 72 dpi. You can probably take a look at the space the current logo occupies and design the new logo with those dimensions in mind.

@yuvipanda Couple of questions for you -

aculich commented 2 years ago

Just seeing this re-assigned to me for the logo update... I'll get back to you shortly with the correct dimensions and format.

aculich commented 1 year ago

@balajialg Here's the logo at 416x80. It's a fairly sparse logo, but you can use it for now and later we'll create a version that better fits those dimensions.

dlab-logo-416x80

Here's our original size logo at 768x512 dlab-logo-768x512

What's the current status of getting this fully implemented? It would be great to kick off next semester with the branding in place.

balajialg commented 1 year ago

Thanks @aculich! We were mostly waiting for the D-lab logo in the PNG format. I will sync with @felder and confirm with you about getting this issue closed before the start of Spring semester.

balajialg commented 1 year ago

@felder Can you look into this issue when you have sometime this week?

felder commented 1 year ago

@balajialg I will try, I have been very busy with other RTL projects this week. I'd say this week is unlikely, but not impossible.

aculich commented 1 year ago

Totally fine if you get to it next week or the following— no need to squeeze it in amongst much higher priorities!

Thanks for bringing attention to this when you're ready to tackle it.

aculich commented 1 year ago

Is this off the table for Spring 2023? Just want to check so I can set expectations. I was talking to other folks on campus about this possible feature and they were potentially interested, too @wrathofquan

We'll absolutely want to have ready to be a part of our Fall 2023 offering— though it would be nice to have by start of summer (mid-May after the semester finishes). Thanks!

balajialg commented 1 year ago

@aculich Apologies for the delay at our end! We were severely constrained during the last three weeks from a dev cycles standpoint which made it difficult to prioritize this task for February. I will try to scope this task for March and if that's not feasible then keep April as the deadline month to make some progress. We will be able to circle back on this in the next few day's time. Tagging @felder @shaneknapp!

gmerritt commented 1 year ago

Noting that in some contexts (e.g., jupyterlab interface) the upper-left logo is not a simple single image element, but rather a set of objects "drawn" in the browser; this may have implications for rebranding all page contexts of a given hub.

The screenshot below illustrates this drawn-in-browser nature via edits of the loaded-in-browser source as a demonstration:

screenshot_572
gmerritt commented 1 year ago

Jonathan has an example from summer of 2022 that shows one of the methods for including a custom logo for a hub.

Note that this strategy has a couple of pieces. The first is a directive in the hub-building Dockerfile that says "copy this here logos directory into the container file system" --

COPY logos /srv/logos

This means that the custom logo for given hub will need to go into a logos/ directory that's "local" to the Dockerfile run context; with this Docker magic, a customlogo.png in the appropriate logos/ directory in the hub source will get copied into the container as /srv/logos/customlogo.png.

The complementary configuration change to support a hub's custom logo is to include this configuration directive in the hub's deployments/<hubname>/config/common.yaml to tell JupyterHub to replace the default logo file path parameter with this custom file that's been copied to the container's /srv/logos/ by the Dockerfile:

    extraConfig:
      logoConfig: |
        c.JupyterHub.logo_file = '/srv/logos/customlogo.png'

Note that in the dataub universe, there are two places for Dockerfile (with associated inheritance):

  1. images/hub/Dockerfile and
  2. deployments/<hubname>/image/Dockerfile

It's my understanding that if COPY logos /srv/logos is used in the service-wide images/hub/Dockerfile, then all custom hub logos would need to go into a directory that's in the service-wide context of images/hub/logos. This is the strategy described in this example.

However, to keep the custom image data and directives within the context/scope of the specific hub that's getting a custom image, the modified Dockerfile would be the one local to the hub -- i.e., deployments/<hubname>/image/Dockerfile -- and that hub's custom logo would be placed into a logos directory right next to that Dockerfile, i.e., deployments/<hubname>/image/logos/customlogo.png.

I was able to partially test this with repo2docker running on my local machine. Regrettably, repo2docker cannot be used to test modifications to deployments/<hubname>/config/common.yaml, as this file is not used by repo2docker -- it is, relative to repo2docker's run context of deployments/<hubname>/image/, in the neighboring folder ../config/, which is completely outside of the scope of the Dockerfile used for a local instance of a hub fired up with repo2docker.

I did test the Dockerfile COPY directive, and was pleased to see that my logos directory, and its contents, were appropriately included in my container in /srv/:

screenshot_786

Of course, since common.yaml is not used by repo2docker, the image itself is not rendered in the browser in this local test context.

We should probably follow through with testing by making custom logo changes to the new logodev hub, and push it to staging to confirm that this works as expected. (A similar solution worked fine for a local tljh installation, so I am optimistic.)

aculich commented 1 year ago

@gmerritt thanks for advancing the discussion.

@balajialg for us(@pssachdeva) here at D-Lab this is now a much higher priority as we test RTC for use over the summer, we'd like to make sure our summer workshop participants can clearly differentiate which datahub they're using.

ryanlovett commented 1 year ago

@aculich @gmerritt One issue to consider is that RTC uses jupyterlab which doesn't feature the /hub/logo as much as classic jupyter notebook does. Classic notebook has the large logo at the top left:

Screenshot 2023-04-17 at 1 43 15 PM

While JupyterLab has the smaller icon in the corner:

Screenshot 2023-04-17 at 1 43 31 PM

JupyterLab specifies the top-left icon here, here, and here.

RStudio doesn't use the logo at all.

The logo would still be seen at /hub/home however, though most regular users don't visit that page that often.

So jupyter notebook would require customizing the logo at /hub/logo which involves putting the image in the hub container and customizing the c.JupyterHub.logo_file traitlet as @felder found and which @gmerritt summarized above.

Customizing the top-left logo in lab may require replacing the logo in the singleuser image. I'm not sure where else that svg may appear. Given that the name of the file is jupyter.svg, it may appear in non-logo contexts.

Lastly, there may be other opportunities for branding besides the logo. For example there could be a jupyterlab extension which loads a new top-level menu with an icon for the menu name and "About {deployment}" as one of the menu items.

gmerritt commented 1 year ago

Indeed, thanks @ryanlovett -- I dissected that .svg here, above.

My initial thought is to do the jupyter notebooks (non-lab, "classic") first, get that checked off, and then visit other contexts as follow-on tasks?

gmerritt commented 1 year ago

I will note that for hubs that currently do not use a custom Dockerfile (a discouraged practice to use custom Dockerfiles!), simply adding a custom logo means that a non-trivial Dockerfile (to which one will add the COPY directive) must be created, as here: https://mybinder.readthedocs.io/en/latest/tutorials/dockerfile.html.

This seems to be kind of a bummer -- more moving parts, and extra things to "get wrong" for a hub that may not otherwise be using this discouraged method of customization.

Do we have a "starter" Dockerfile to use with a hub? I.e., a Dockerfile with "nothing special" that will otherwise build a hub with defaults?

Given the link above, and some quick local testing, a blank local Dockerfile (one to which we'd hope to simply add the COPY command for the logos directory, and nothing else, in the interest of simplicity) does not seem to be supported.

balajialg commented 1 year ago

Thanks a lot, @gmerritt and @ryanlovett for your detailed inputs! To your question Greg, based on my initial exploration, most of D-Lab Python-based workshops use JupyterLab as the default interface (eg: Try clicking the "launch datahub" button present in the https://github.com/dlab-berkeley/Python-Fundamentals-Pilot). @aculich - Please clarify if I am incorrect here. From this perspective, pursuing JupyterLab-related changes would make sense over changes to classic notebook interface for this particular issue.

Having said that, I assumed earlier that changing the logo on the tree page would be a helpful way to differentiate hubs in addition to the logo change in the interface. However, As @rylo highlighted most students would skip the interface by using nbgitpuller links to launch the classic notebook or lab (in this context) or RStudio directly. Whether a proposal to change the logo in the JupyterLab interface alone will solve your need here? @aculich. Please clarify!

I am personally in favor of the JupyterLab extension with the menu name and icon as suggested by @rylo. However, not sure how complex such an implementation will be and whether an equivalent implementation for R Studio is possible. I have seen 2i2c folks differentiate the 50+ hubs by modifying the logo in the home page - https://ciroh.awi.2i2c.cloud/hub/login?next=%2Fhub%2F. Not sure whether it is relevant here.

aculich commented 1 year ago

Yes, modifying the logo for the home page before logging in is also desirable, however I think once logged in we would want a quick visual indicator to let us know which one we are connected to.

balajialg commented 1 year ago

@aculich Just an FYI, Modifying the JupyterLab logo in the D Lab hub will show up like this - https://innovationoutside.github.io/jupyterlab_ou_brand_extension/lab/index.html (small logo at the left hand top corner)

aculich commented 1 year ago

Oh yeah, that's tiny, but that'll do just fine for starters. Here's the screenshot of that link for the record:

image

Our logo is distinctive enough as a badge for our folks to recognize it.

gmerritt commented 1 year ago

@aculich, we've merged to staging the code changes that support custom logos for the "classic" notebook interface for hubs.

An example is currently deployed on this temporary development hub.

The short story for adding a custom logo for the "classic" notebook interface for D-Lab would be the following two additions:

  1. Add a suitable logo image file, such as a .png, to this hubwide directory: images/hub/logos/.
  2. Add an extraConfig: block under hub: in D-Lab's common.yaml file, like so, in which the filename matches the filename of the logo file included in 1. above (note the different path!):
hub:
    ...
    extraConfig:
      20-logoConfig: |
        c.JupyterHub.logo_file = '/srv/logos/dlab-logo-notebook.png'

Aaron, we would like very much to also provide customization options for additional contexts (e.g., /lab); these changes are to follow.

gmerritt commented 1 year ago

@aculich Just an FYI, Modifying the JupyterLab logo in the D Lab hub will show up like this - https://innovationoutside.github.io/jupyterlab_ou_brand_extension/lab/index.html (small logo at the left hand top corner)

Here's the top-level link to the source:

https://github.com/innovationOUtside/jupyterlab_ou_brand_extension

In our datahub repo, it looks like jupyterlab comes in only via reference in requirements.txt (jupyterlab==3.4.5)...I'll have to dig into this to understand how this is used, and how/whether it could be integrated into, and configured for, our hubs.

More documentation related to above-linked repo is here:

https://blog.ouseful.info/2022/04/29/custom-branded-logos-for-jupyterlab-and-retrolab-jupyter-notebook-v-7/

gmerritt commented 1 year ago

Investigating custom jupyterlab theme extensions

Proposed:

Use custom jupyterlab theme extensions to allow customization of the visual user experience, indlucing at least the opportunity to replace the default upper left jupyter logo on a hub's /lab view.

Jupyterhub archictecture notes:

Custom themes are jupyterlab extensions.

The jupyterlab community has made available a cookiecutter template for creating custom jupyterlab extensions; this includes a custom theme option:

Generally speaking, an extensions is installed via the methods described at the bototm of this page: https://github.com/jupyterlab/extension-examples/tree/main/server-extension

If available via pypi.org: pip install <extension-name>

If installing locally: pip install -e ./ (in the extension's root directory)

The page linked above also describes running...

...but this may not be required for our build context.

I have not encountered examples of, nor have I yet tried, installing via a public github repo: pip install git+git://github.com…/user/repo.git [EDIT] -- Yes! This works for a public github repo using git+https... but we do not want to deal with separate repos.

Our practice for hub-specific customization:

Hub-specific custom configuration code should go into the berkeley-dsep-infra/datahub repo, not outside of it. Candidate locations for hub-specific custom configuration code include:

What I've tried and learned so far with repo2docker and jupyterlab theme extensions in our repo context:

Adding a custom local jupyterlab extension seems to require, in our context, adding the image directory (with appropriate files within) to datahub/deployments/<hubname>/, as noted in our new hub documentation, at the very bottom of the page:

I've created a custom jupyterlab extension using the cookiecutter template linked above, and have added it to our datahub/deployments/<hubname>/image/ directory.

I've added the following to the Dockerfile in datahub/deployments/<hubname>/image/:

Our practice includes these lines that incorporate and build the environment.yml file in the datahub/deployments/<hubname>/image/ directory:

The build happens via a line added to environment.yml that adds the following directive:

Dependecies and errors are vexing, and slow to debug with the repo2docker long build times. For the sample image directory I used, this sample theme extension required updates to...

I am currently getting the following error when I build with repo2docker in the image directory; perhaps a dependency issue?:

Note that I have successfully built theme-darcula non-locally, via dependencies: - theme-darcula in environment.yml; this works great, and shows up in the /lab view as a theme option. I have not yet tried to build theme-darcula locally, but I suspect it would work.

When I copy the theme-darcula repo locally to image/ and try to use the Dockerfile / environment.yml approach, I get this error:

If I only COPY the theme-dracula repo into /tmp via the Dockerfile, and then try to build with terminal in jupyterlab, I also get the Permission denied error However, if I copy /tmp/theme-darcula to ~/ in my jupyterlab terminal, then pip install ./ works successfully.

What to consider next? (In addition to continued debugging of current build error)

gmerritt commented 1 year ago

Also: very not-yet-done is figuring out how to modify the custom theme extension to render a custom logo! This has been assumed possible & straightforward, and my expectation has been that the custom theme extension integration & build would be the tricky bits!

gmerritt commented 1 year ago

Node.js needs to be just the right version for the cookiecutter theme & its dependencies; the latest of version 16 seems to work, so environment.yml can set...

dependencies:
- nodejs==16.*

Due to subtle peculiarities of the build process, in order to build your custom theme into the image using the cookiecutter official jupyterlab theme extension approach one must use a custom image with Dockerfile (putting your custom theme extension folder in deployments//image/ alongside the Dockerfile) and adding these lines to Dockerfile just after RUN mamba; this will result in getting your theme added to your /lab url’s theme menu:

COPY logodevtheme /tmp/logodevtheme
RUN cd /tmp/logodevtheme; tar -czvf /tmp/logodevtheme.tar.gz *
RUN pip install --user /tmp/logodevtheme.tar.gz

Dockerfile will also need additional lines to even create the default image for your hub; we do not have any current example aside from those that are more-highly-customized for hubs that use them for special requirements, so this is a big "to-do," i.e. creating a starter Dockerfile-based custom image file tree that accurately defines the default hub and that is ready to accommodate a custom theme extension build.

Notes to follow regarding understandings of how to customize the theme with your desired logo in the upper left corner of /lab view.

gmerritt commented 1 year ago

To modify the custom cookiecutter-created official theme extension as referenced previously, I found the following to be necessary:

Create a folder deployments/<hubname>/image/style/and include your custom .svg logo in that folder. (I've tried with one .png that did not seem to work well? More testing needed.)

Add a base.css file to deployments/<hubname>/image/style/ with the following contents, including the reference to your custom .svg file:

#jp-MainLogo > svg {
    visibility: hidden;
}

#jp-MainLogo {
    background-image: url(./images/logodevtheme_logo.svg);
    background-repeat: no-repeat;
    }

In deployments/<hubname>/image/style/index.css add the line @import './base.css';.

I'm now working on understanding how to change the default theme to the custom theme. https://github.com/jupyterlab/jupyterlab/issues/9988 provides some inspiration via the overrides.json approach; see:

https://github.com/berkeley-dsep-infra/datahub/blob/staging/deployments/stat159/image/overrides.json & https://github.com/berkeley-dsep-infra/datahub/blob/staging/deployments/stat159/image/postBuild .

Neither this build-time postBuild file approach nor the run-time start file approach worked for me (yet!) in local testing.

balajialg commented 1 year ago

@aculich My understanding of where things stand now based on the comprehensive exploration done by @gmerritt - You can customize the logo for Jupyter Notebooks but to customize the theme/logo for lab requires more dev bandwidth which Greg currently doesn't have. If anyone in your team has the necessary skills + some dev bandwidth to continue this exploration for JupyterLab, I think Greg would be more than happy to give a knowledge transfer (most of which is documented in this issue clearly). Please let us know!

@shaneknapp @gmerritt Please feel free to add and also correct if I have missed or misrepresented the next steps.

gmerritt commented 1 year ago

Thank you very much for this summary, @balajialg. Yes, while using a custom theme for a lab is quite technically possible, it all-too-quickly becomes a "rabbit hole" of committing to defining and maintaining a custom image for that hub. This includes navigating version conflicts of many of the dependencies, and one may quickly find oneself supporting an intricate set of subtly interacting version requirements that may also be very different versions from our standard hub installation.

@aculich, if you would like to start along this path of a more self-supported hub image, I would be more than happy to meet to review what I've learned.

aculich commented 1 year ago

@balajialg @gmerritt thanks to both of you keeping this moving forward.

Yes, @gmerritt would love to set up a time to meet along with my colleague @pssachdeva about a more self-supported hub image.