Skip to content
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

Allow setting builds as args rather than parameters #90

Closed
wants to merge 1 commit into from

Conversation

tmeasday
Copy link
Member

@tmeasday tmeasday commented Sep 8, 2023

Trying this out - is this what you had in mind @yannbf? It seems like the types don't like it though @kasperpeulen (see the @ts-expect-error, not quite sure why. I can set args.AddonVisualTestsBuild in the meta but not in the story.

It does work though.

image

📦 Published PR as canary version: 0.0.64--canary.90.6a458fa.0

✨ Test out this PR locally via:

npm install @chromaui/[email protected]
# or 
yarn add @chromaui/[email protected]

Comment on lines +366 to +367
// @ts-expect-error
AddonVisualTestsBuild: constructResult({ storyBuild: pendingBuild }),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason it errors if I set this arg on the Story but not on the Meta.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make more sense to make more sense for the arg to be the input to constructResult if we want the user to be able to edit this in the controls panel?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would that work @shilman? constructResult is specific to this query...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, if you use typeof meta, it only looks at the component type, and it can really do anything with the satisfies part.

You will have to do something as:

type StoryArgs = Parameters<typeof VisualTests>[0] & {
    AddonVisualTestsBuild: ResultOf<typeof QueryBuild>;
}

const meta = { } satisfies Meta<StoryArgs>;

type Story = StoryObj<StoryArgs>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kasperpeulen but am I correct in saying that would mean we would lose any args that were defined in meta (in terms of being required?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is right, you have to set them optional yourself in StoryObj.

I have thought about this scenario, but I think there is no way, as the satisfies constraint has no effect on the inferred return type of meta.

Factories would solve this problem 🤓

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured you'd say that :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This worked OK, FTR:
image

Only problem was a couple of stories that had a render() function, the args were typed wrongly :/

Copy link
Member

@shilman shilman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!!

@kasperpeulen
Copy link

Really nice to see that args can be used for together with msw, would make it much more powerful!

@tmeasday
Copy link
Member Author

Closing this in favour of a similar change in #124

Note in that PR I nested the args under $graphql:

args: {
$graphql: {
AddonVisualTestsBuild: {
lastBuildOnBranch: withTests(pendingBuild, pendingTests),
},
},
localBuildProgress: {
...EmptyBranchLocalBuildCapturing.args.localBuildProgress,
buildProgressPercentage: 90,
stepProgress: {
...EmptyBranchLocalBuildCapturing.args.localBuildProgress.stepProgress,
snapshot: {
...EmptyBranchLocalBuildCapturing.args.localBuildProgress.stepProgress.snapshot,
numerator: 310,
},
},
},
},

I also add a "mapping" concept:

argTypes: {
addNotification: { type: "function", target: "manager-api" },
$graphql: {
AddonVisualTestsBuild: { map: mapQuery },
},
},

function mapQuery(
{ lastBuildOnBranch, userCanReview = true, ...input }: QueryInput,
{ selectedBuildId }: VariablesOf<typeof QueryBuild>
) {
const possibleSelectedBuilds =
("selectedBuild" in input && input.selectedBuild && [input.selectedBuild]) ||
("selectedBuilds" in input && input.selectedBuilds) ||
[];
if (lastBuildOnBranch) possibleSelectedBuilds.push(lastBuildOnBranch);
const selectedBuild = possibleSelectedBuilds.find((b) => b.id === selectedBuildId);
console.log({ possibleSelectedBuilds, lastBuildOnBranch, selectedBuild, selectedBuildId });
return {
project: {
name: "acme",
lastBuildOnBranch: lastBuildOnBranch || selectedBuild,
},
selectedBuild,
viewer: {
projectMembership: {
userCanReview,
},
},
};
}

It works pretty well. @shilman I think nesting under $graphql makes it a little more intuitive to read, but a bit more awkward to write--ie:

export const StoryAddedNotInBuild = {
  args: {
    $graphql: {
      AddonVisualTestsBuild: {
        selectedBuild: withTests({ ...pendingBuild }, []),
      },
    },
  },
}

// vs 

export const StoryAddedNotInBuild = {
  args: {
    AddonVisualTestsBuild: {
      selectedBuild: withTests({ ...pendingBuild }, []),
    },
  },
}

On the one hand the extra level of nesting is just more work all the time, on the other hand it makes it much more clear what this arg that has nothing to do with the component's props is doing.

@tmeasday tmeasday closed this Oct 10, 2023
@shilman
Copy link
Member

shilman commented Oct 10, 2023

Haven't thought this through, but I wonder if we could just hoist $graphql and make $x the convention for targeted args, reducing one level of hierarchy?

@tmeasday
Copy link
Member Author

tmeasday commented Oct 10, 2023

@shilman we could but I guess I was saying the $graphql is actually useful because at a glance it distinguishes the target of the args when you read the story and don't have all the context.

If it was $AddonVisualTestsBuild it would still be clear it's not a prop, but not where it's going.

Maybe that's a good tradeoff though? I guess in any given project you are probably only going to have one or two arg "targets".

If we did it that way, we could even just make the $- thing a convention, given you'll have to define somewhere that $AddonVisualTestsBuild targets graphql.

@shilman
Copy link
Member

shilman commented Oct 10, 2023

Sorry I meant the other way. Pull $graphql to be a peer of args.

@tmeasday
Copy link
Member Author

So a new annotation?

@yannbf
Copy link
Contributor

yannbf commented Oct 10, 2023

I think it makes sense to have them under args:

  1. People already connect args to the controls table, or addons that provide a controls-like experience
  2. You still maintain a scope, rather than having a freeform property in the story top annotation level
  3. The $ prefix (maybe it should be $$) helps distinguish what is not a prop, the only framework that prepends certain properties with $ is angular, for observables

@shilman
Copy link
Member

shilman commented Oct 10, 2023

Yeah a new class of annotation. Where we could have $graphql, $mock, $<yourTargetHere>.

I don't love it, but I'm bringing it up because we always try to be careful about scoping things correctly and then we generate these deeply nested structures that are not that ergonomic, and then we end up hoisting them later. But maybe we should consider just hoisting from the beginning under the assumption that targeted args will be a big deal and people will be using them a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants