Skip to content

refactor(Coder plugin): update workspace queries to use updated API endpoint definitions #126

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

Merged
merged 66 commits into from
May 3, 2024

Conversation

Parkreiner
Copy link
Member

@Parkreiner Parkreiner commented Apr 29, 2024

Closes #60

Not quite as much of a win on the performance side as I would've hoped, but on the bright side, it does remove the need for a bunch of code that was only here because of the previous API limitations

Changes made

  • Updates the getWorkspacesByRepo function exposed by CoderClient to use the updated API endpoints
  • Removes all code around checking build parameters, since we no longer need to make requests for the build parameters at all
  • Updates tests and mock server logic to account for more data getting threaded through the single /workspaces endpoint

Notes

@Parkreiner Parkreiner requested a review from Kira-Pilot April 29, 2024 20:49
@Parkreiner Parkreiner self-assigned this Apr 29, 2024
Comment on lines +208 to +216
const responses = await Promise.allSettled(
config.repoUrlParamKeys.map(key => {
const patchedRequest = {
...request,
q: appendParamToQuery(request.q, key, stringUrl),
};

return baseSdk.getWorkspaces(patchedRequest);
}),
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 was one of the limitations I ran into with the new API endpoint: you can't make a single request for every repo key that the user adds to their workspaces config. If your config has the repo URL keys [repo_url, alt_repo_url], then a request like this:

owner:me param:"repo_url=url.com" param:"alt_repo_url=url.com"

Won't work, because it will search for workspaces that have both keys, even though realistically, a workspace will only ever have one of them

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not a huge deal – the previous logic was using Promise.allSettled, too – but it's not making the API logic that much faster

Copy link
Member

Choose a reason for hiding this comment

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

Yea, this is just an unfortunate consequence of our search filtering. We have to make opinions, and cannot support both union and intersection type searches easily at the moment.

Our search filter is very limited at present, and there is no effort to improve it in it's current state. It's just too much of a headache is the answer atm.

Another idea I had awhile back worth peaking at: coder/coder#12706

Copy link
Member

@Kira-Pilot Kira-Pilot May 3, 2024

Choose a reason for hiding this comment

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

^^ What steven said
I chatted with Steven a little bit about this constraint and I guess our current search filtering cannot support both intersection and union searches. To implement both we'd basically have to duplicate all of this logic, which is already really long.

There's not a shorter syntax because we use SQLc so we must use CASE statements. Here is an open discussion we can return to in the future if this ever becomes more problematic.

Anyway, all this to say I think what you have is great!

@@ -73,7 +73,7 @@ describe(`${CoderWorkspacesCard.name}`, () => {

await user.tripleClick(searchbox);
await user.keyboard('[Backspace]');
await user.keyboard('I can do it - I can do it nine times');
await user.keyboard('I-can-do-it-I-can-do-it-nine-times');
Copy link
Member Author

Choose a reason for hiding this comment

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

Removed the spaces (1) to account for the mock server logic better, and (2) to account for the fact that the actual Coder API doesn't expect spaces like this, either

Base automatically changed from mes/api-v2-02 to main April 30, 2024 17:44
@Parkreiner
Copy link
Member Author

@Kira-Pilot Changes should be ready now!

config.repoUrlParamKeys.map(key => {
const patchedRequest = {
...request,
q: appendParamToQuery(request.q, key, stringUrl),
Copy link
Member

Choose a reason for hiding this comment

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

are key and stringUrl guaranteed to be strings as opposed to null or undefined?

Copy link
Member Author

@Parkreiner Parkreiner May 3, 2024

Choose a reason for hiding this comment

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

Luckily, they're both guaranteed to be defined

With key, we're getting the values through .map. That doesn't guarantee that we'll have a non-empty array, but it does mean that the mapper callback will only be called if we have a defined element to feed into it. That's one of the benefits of the array methods and for/of over traditional i loops – they can guarantee no null-ish values, because they're going through JS's iterator protocol

And as for stringUrl, it's wonky, but that's also guaranteed to be of type string. If we had this:

const patchedRequest = {
  ...request,
  q: appendParamToQuery(request.q, key, config.repoUrl),
};

config.repoUrl would be type string | undefined. But TS type narrowing helps get around that:

// Rule out that config.repoUrl is not undefined; TS is smart
// enough to shrink size down to just string for all code after
// this if statement
if (config.repoUrl === undefined) {
  return { workspaces: [], count: 0 };
}

// Capture the value after we've proven it's a string only. Because
// this is a const and can't be reassigned, TS knows that undefined
// can never be assigned to this version of the value
const stringUrl = config.repoUrl;

// Normally, the type of a union value would "reset" when you
// have a different callback, because TS can't look at the code and
// make guarantees about whether the value will change before the
// callback runs. But as long as we use the "captured" version of
// the value, it will always be a string and can't be reset
const responses = /* */

Copy link
Member

Choose a reason for hiding this comment

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

But as long as we use the "captured" version of the value, it will always be a string and can't be reset

I see your comment above now. Thank you for the explanation!

key: string,
value: string,
): string {
const keyValuePair = `param:"${key}=${value}"`;
Copy link
Member

Choose a reason for hiding this comment

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

Is it worth check that these don't contain empty strings?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, good call. Let me fix that really quick

Copy link
Member

@Kira-Pilot Kira-Pilot left a comment

Choose a reason for hiding this comment

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

This looks good to me!

@Parkreiner Parkreiner merged commit cd9f90c into main May 3, 2024
2 checks passed
@Parkreiner Parkreiner deleted the mes/by-repo branch May 3, 2024 20:28
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.

Coder plugin: integrate new query by workspace param functionality
3 participants