-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add examples page #942
Conversation
Tests have been added! Ready for testing out and using 🚀 I have added some "follow up issues" to the topic here, especially lack of examples (only 3 "good" ones right now): #864 (comment) |
const example = examples.find(example => example.image === msg.image); | ||
if (example) { | ||
example.state = 'pulled'; | ||
console.log(examples); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be removed
// Function to update examples based on available images | ||
function updateExamplesWithPulledImages() { | ||
if (bootcAvailableImages) { | ||
bootcAvailableImages.forEach(image => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the linter is now recommending. for of pattern
bootcAvailableImages.forEach(image => { | ||
// Only do it if there is a RepoTags | ||
if (image.RepoTags) { | ||
const [imageRepo, imageTag] = image.RepoTags[0].split(':'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe use the optional ? pattern to reduce the if if if chaining
} | ||
|
||
// Reactive statement to call the function each time bootcAvailableImages updates | ||
$: if (bootcAvailableImages) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be a time to use $effect / svelte 5 runes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't as we use $$props.class
in the Card (copied from AI lab and we try to keep consistent with them too) which we can then not use since it puts the svelte file in "runes mode"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NVM, we don't actually use classes imported into it, so it's okay to switch to svelte 5 runes, updating now.
Could not get it to work reactively very well, even using $props as well as $effects. May just leave this like it is for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any reason why it would fail
<Card title={category.name} classes="{$$props.class} font-medium mt-4"> | ||
<div slot="content" class="w-full"> | ||
{#if examples.length === 0} | ||
<div class="text-gray-400 mt-2">There is no example in this category.</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should ot use empty screen ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need :) will always have examples!
Tried your suggestion though using empty screen but messed up formatting, so may be easier to just use this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: if we always have examples, then do not add the if clause
import { render, fireEvent, screen } from '@testing-library/svelte'; | ||
import { expect, test, vi } from 'vitest'; | ||
import ExampleCard from './ExampleCard.svelte'; | ||
import { bootcClient } from '../api/client'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use absolute import
</script> | ||
|
||
<a class="no-underline" href={href}> | ||
<div class="{classes} rounded-md flex-nowrap overflow-hidden" role="region" aria-label={title ?? 'Card'}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think usually we're using another pattern than having an explicit classes parameter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are doing this in a few places, often with different parameter names. In Svelte 5 you can do:
let {
class: className = '',
}: {
class?: string;
} = $props();
to make this cleaner, but since we ever only ever do classes="font-medium mt-4"
, maybe remove the parameter and put the styling in here?
@@ -38,7 +38,7 @@ | |||
"categories": [ | |||
{ | |||
"id": "fedora", | |||
"name": "Fedora BootC Images" | |||
"name": "Fedora Bootable Container Images" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be a separate small PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto to all the points @benoitf raised.
Worked fine when testing. The biggest gap to me was how to find details or instructions for each example. Why does it exist, what does it do, and how do I use it? The source goes to the repo root, then I have to guess at the folder and look at the readme. (and ok, Tailscale doesn't have anything)
Could we link directly to the folder, or ideally have a way to view the readme directly? Maybe needs a details page for each one?
Noted a few other minor usability issues:
- The page appears, then we switch buttons from Pull to Build. Is the API fast enough that we could do this before opening the page, or can we delay adding the button until we know which it is? (might need to move Source button to Link on the left so it doesn't move).
- Like on the dashboard, you don't know the image you're about to pull is huge. Would be nice to include the size on the card, or warn the user when they click on the button.
- No pull task or progress. Unrelated to this issue so I opened up Usability of pulling images #944.
We have https://gitlab.com/fedora/bootc/examples/-/issues/19 which I could work on next sprint with regards to descriptions of what each one does: #947 We have no way of knowing the size of the image before pulling, but we can at least add an approximate "size" on the description when pulling? ACK on button delay / showing it correctly. |
b1c339d
to
9cef29a
Compare
Updated the code based on the review:
UI update (shows size now): |
d4a109a
to
9a3da6f
Compare
fffee57
to
8db094c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes, worked well in testing. We have some ideas for additional improvements open, but this delivers on the core requirement.
Some minor requests for change but otherwise this is good to go for me.
</script> | ||
|
||
<a class="no-underline" href={href}> | ||
<div class="{classes} rounded-md flex-nowrap overflow-hidden" role="region" aria-label={title ?? 'Card'}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are doing this in a few places, often with different parameter names. In Svelte 5 you can do:
let {
class: className = '',
}: {
class?: string;
} = $props();
to make this cleaner, but since we ever only ever do classes="font-medium mt-4"
, maybe remove the parameter and put the styling in here?
import { render, screen } from '@testing-library/svelte'; | ||
import { expect, test, vi } from 'vitest'; | ||
import type { Example, Category } from '/@shared/src/models/examples'; | ||
import ExamplesCard from './ExamplesCard.svelte'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
component: ExamplesCard, test: ExampleCards. Can you rename one so that they match?
@@ -0,0 +1,56 @@ | |||
<script lang="ts"> | |||
import type { Example, Category } from '../../shared/src/models/examples'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should really use /@shared/...
here, and other places.
@deboer-tim @benoitf Updated based on the review comments and ready for another review 👍 |
a8eecb1
to
5647d96
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes @cdrage, a nice little addition we can continue to expand on.
|
||
// Wait until example1 says Build image as it updates reactively | ||
// same for example 2 but Pull image | ||
waitFor(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: missing await before waitFor
expect(buildImage1).toBeInTheDocument(); | ||
}); | ||
|
||
waitFor(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: missing await before waitFor
export let title: string | undefined = undefined; | ||
export let description: string | undefined = undefined; | ||
|
||
export let href: string | undefined = undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: use svelte5 runes
export let title: string | undefined = undefined; | |
export let description: string | undefined = undefined; | |
export let href: string | undefined = undefined; | |
interface Props { | |
title: string; | |
description: string; | |
href: string | |
} | |
let {title, description, href} : Props = $props(); |
export let href: string | undefined = undefined; | ||
</script> | ||
|
||
<a class="no-underline" href={href}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<a class="no-underline" href={href}> | |
<a class="no-underline" {href}> |
// Function that takes something in MB and returns it in GB is more than 1GB | ||
// in a nice string format | ||
function formatStringSize(size: number): string { | ||
if (size > 1000) { | ||
return `${(size / 1000).toFixed(1)} GB`; | ||
} | ||
return `${size} MB`; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: please use humansize library
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to use the filesize library https://www.npmjs.com/package/filesize which is used in podman desktop. the one you linked hasn't been updated in 10 years.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yes I think I took the wrong name but you figured it out
I mixed humanize-duration and this one
$: { | ||
example.state; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: feels hacky
use svelte5 ($props, $effect, etc)
icon={faArrowDown} | ||
aria-label="Pull image" | ||
title="Pull image" | ||
class="w-28" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: do we need to set a size there ?
inProgress={pullInProgress}>Pull image</Button> | ||
{:else} | ||
<!-- Show a spinner / in progress for querying button instead if we are still loading information--> | ||
<Button icon={faArrowDown} aria-label="Querying" title="Querying" class="w-28" inProgress={true} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: same here, why do we need to set a size there ? (w-28)
} | ||
|
||
// Reactive statement to call the function each time bootcAvailableImages updates | ||
$: if (bootcAvailableImages) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any reason why it would fail
<Card title={category.name} classes="{$$props.class} font-medium mt-4"> | ||
<div slot="content" class="w-full"> | ||
{#if examples.length === 0} | ||
<div class="text-gray-400 mt-2">There is no example in this category.</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: if we always have examples, then do not add the if clause
### What does this PR do? * Minor edit to category (see json update) * Adds an example page (rendered portion) that shows all the examples we currently have * Pull and build image buttons * Reactively do in-progress for pulling ### Screenshot / video of UI <!-- If this PR is changing UI, please include screenshots or screencasts showing the difference --> ### What issues does this PR fix or reference? <!-- Include any related issues from Podman Desktop repository (or from another issue tracker). --> Closes podman-desktop#895 ### How to test this PR? <!-- Please explain steps to reproduce --> 1. Go to examples page 2. Press pull image button 3. Then build image button after it finishes Signed-off-by: Charlie Drage <[email protected]>
Signed-off-by: Charlie Drage <[email protected]>
Signed-off-by: Charlie Drage <[email protected]>
Signed-off-by: Charlie Drage <[email protected]>
ec715a7
to
ab53d85
Compare
The more I use svelte5, the more I'm liking it! Much cleaner code. I have updated it to svelte5 paradigms. I also decided to use https://www.npmjs.com/package/filesize library instead of humansize since it's the same on in Podman Desktop + is more updated. Functionality of it working: Screen.Recording.2024-10-23.at.3.17.35.PM.mov |
Signed-off-by: Charlie Drage <[email protected]>
ab53d85
to
2e21ee2
Compare
yes the library name was wrongly spelled ! |
looks like there are some typechecking issue but approving |
bfedf6d
to
2e21ee2
Compare
Thanks! Formatter had messed up and did not put |
feat: add examples page
What does this PR do?
currently have
Screenshot / video of UI
Screen.Recording.2024-10-17.at.3.32.42.PM.mov
What issues does this PR fix or reference?
Closes #895
How to test this PR?
Signed-off-by: Charlie Drage [email protected]