-
Notifications
You must be signed in to change notification settings - Fork 130
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
Add Tasks component #896
Add Tasks component #896
Conversation
Thanks for your contribution! Depending on what you are working on, you may want to request a review from a Shopify team:
|
4a8b299
to
c5f1830
Compare
Coverage report
Show new covered files 🐣
Show files with reduced coverage 🔻
Test suite run success886 tests passing in 459 suites. Report generated by 🧪jest coverage report action from 9f1d971 |
This comment has been minimized.
This comment has been minimized.
682aaf9
to
b394ee5
Compare
f1d7727
to
09110a8
Compare
import React, {useEffect, useRef, useState} from 'react' | ||
import gradient from 'gradient-string' |
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.
Not blocking, but these imports, especially React, might have a negative impact on the startup time of the CLI. I'm working on a tool that will help us see if this is a bottleneck, and if it is we'll have to move them to dynamic imports.
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.
This PR removes chalk-animation
in favor of a more minimal dependency on gradient-string
so in theory this should improve things. I'll wait for the decision regarding dynamic imports 👍
@@ -34,7 +34,8 @@ describe('Prompt', async () => { | |||
|
|||
expect(renderInstance.lastFrame()).toMatchInlineSnapshot(` | |||
"? Associate your project with the org Castile Ventures? | |||
[36m✔[39m [36msecond[39m" |
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.
When I see these tests I always wonder if we should do matches without ASCI escape characters. As a code reviewer, [36m
says nothing to me. I'd have to go and search what the escape code means. Nothing actionable in for this PR though, just a random thought that I had.
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.
The reason why I added these is that if someone changes the color of the border in the prompt this test will fail. It's not really so that developers understand what this is, it's more to protect against breaking changes. See it as a screenshot diff if you will. Without these codes all the prompt tests would look the same.
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.
That's a good idea. In a future iteration we could provide a custom matcher that outputs in the terminal the two outputs so that you can see the styles applied.
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.
Actually if you get an error right now it already works, you will see the colored output in the terminal since the escape sequences are interpreted.
asyncFunction() | ||
.then(() => { | ||
onResolve() | ||
unmountInk() |
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.
What does unmounting
mean in the context of a component?
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.
Also, that side effect doesn't seem well captured in the name of the function, useAsync
.
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.
Basically, this hook allows you to wait inside react components for async behavior. Once this behavior resolves we want to unmount the rendering ink
instance explicitly so that the promise we're awaiting from the outside (waitForExit
) resolves.
Regarding the naming I'm open to suggestions. Would something like useAsyncAndUnmount
be better?
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.
@pepicrft how about useEffectAsync
?
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'm more inclined towards useAsyncAndUnmount
.
|
||
const MIN_WIDTH = 80 | ||
|
||
export default function useLayout() { |
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.
What about adding a unit test for this one?
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.
Will do 👍
for (const task of tasks) { | ||
setCurrentTask(task) | ||
// eslint-disable-next-line no-await-in-loop | ||
await task.task() |
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.
Are there plans to implement a version of this component with tasks that run concurrently?
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 looked at listr2 and it seems like tasks are not being processed concurrently there as well so for now I think we can keep this sequential. Parallel tasks would also need a different interface to report progress.
|
||
export default function useAsync( | ||
asyncFunction: () => Promise<unknown>, | ||
{onResolve = () => {}, onReject = () => {}}: Options, |
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.
Nitpick: What about aligning the naming of the then
function: onFulfilled
and onRejected
?
/** | ||
* Runs async tasks and displays their progress to the console. | ||
*/ | ||
export function renderTasks(tasks: Task[]) { |
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.
Task is a public
interface so I recommend moving it to the public/node
folder as well. Otherwise we might introduce breaking changes there in the future without realising it.
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.
renderPrompt
also uses PromptProps
which is an interface defined privately. We could remove the dependency on these private interfaces by creating new public ones that mirror the private ones, but this might introduce some differences in the future that typescript will not catch for us (e.g. we add a field to the private ones and forget to update the public one).
fa942e9
to
71a3586
Compare
3ec97ef
to
b04defa
Compare
Benchmark reportThe following table contains a summary of the startup time for all commands.
|
WHY are these changes introduced?
We want to be able to convey to the user that a some tasks are running. So far we've been using
listr2
, but we want to follow our own design approach.We'll need to merge this other PR first before we can review this properly.WHAT is this pull request doing?
This PR introduces a new
renderTasks
method which takes an array of items in the form of:{title: string, task: Promise}
and displays an animated bar while these tasks are running. At the end it displays a green bar in case of success or a red bar in case any of the tasks has failed to complete.How to test your changes?
Run
kitchen-sink
and see the bar for yourself at the end! It should look like this:Measuring impact
How do we know this change was effective? Please choose one:
Checklist
dev
ordeploy
have been reflected in the internal flowchart.