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

feat: Add and edit github connection #5263

Merged
merged 38 commits into from
Jul 31, 2024
Merged

Conversation

AdityaHegde
Copy link
Collaborator

@AdityaHegde AdityaHegde commented Jul 12, 2024

Base automatically changed from adityahegde/connect-to-github to main July 16, 2024 09:10
@AdityaHegde AdityaHegde marked this pull request as ready for review July 17, 2024 13:43
@ericpgreen2
Copy link
Contributor

Some initial UXQA –

  1. Editing the GitHub repo is buggy. The GitHub repo rendered in ProjectGitHubConnection.svelte never updates. And the listed resources appear to be linked to the previous (t-1) GitHub repo, not the current (t) GitHub repo. I'll send a Jam via Slack.
  2. The dropdown should be initialized with the current GitHub repository (in this case, rill-examples)
    image
  3. @ericokuma, it looks like we need to add a field to configure the subpath. FWIW, here's how Vercel handles selecting a "root directory":
    image

web-admin/src/routes/-/github/connect/+page.svelte Outdated Show resolved Hide resolved
Comment on lines 31 to 36
if (userStatus.isFetching || userRepos.isFetching) {
return {
isLoading: true,
error: undefined,
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We should be consistent with terminology. If reading isFetching, then we should return isFetching. If reading isLoading, then we should return isLoading.

} from "@rilldata/web-common/components/alert-dialog";
import { Button } from "@rilldata/web-common/components/button";
import Github from "@rilldata/web-common/components/icons/Github.svelte";
import Select from "@rilldata/web-common/components/forms/Select.svelte";
Copy link
Contributor

Choose a reason for hiding this comment

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

A little out-of-scope of this PR, but it'd be nice to deprecate this in favor of ShadCN's Select component

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO this extra layer of abstraction isn't necessary & adds complexity.

Is there something wrong with using vanilla TanStack Query in the ProjectGitHubConnection.svelte component? That's the pattern we're using most frequently throughout the codebase.

Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly, is there a reason to be adding this abstraction on top of vanilla TanStack Query? To update the GitHub repo seems like a vanilla mutation and shouldn't require too much complexity. I wonder if the bugginess I shared via Jam is a derivative of this complexity.

If we're to go down this route, I'd expect a "GithubRepoUpdater" to include a method to actually update the Github repo, but that looks to be happening outside of this abstraction in the GithubRepoSelectionDialog.svelte component.

Copy link
Collaborator Author

@AdityaHegde AdityaHegde Jul 18, 2024

Choose a reason for hiding this comment

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

This endpoint can be slow if there are a lot of repos and orgs connected. I want to avoid refetching it on window focus all the time, but only when connect to github or choose other repos is clicked.

Both this and GithubConnection have a check to only refetch if it was explicitly asked for (basically the connecting check).

Naming this GithubRepoUpdater is just a remnant of some old code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Gotcha. The vanilla TanStack approach would be to use $githubQuery.refetch() in the component itself. Might be simpler?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We are refetching the query right? The idea is to hide as much code outside of components as possible. We still need the check if we popped a page to select github repos or not.

This will also hopefully allow us to abstract such code out. But it will have to be follow ups

@AdityaHegde AdityaHegde force-pushed the adityahegde/connect-to-github-ui branch from 9d005a5 to 860211b Compare July 18, 2024 05:58
@AdityaHegde AdityaHegde force-pushed the adityahegde/connect-to-github-ui branch from 860211b to 546266e Compare July 18, 2024 15:01

function handleVisibilityChange() {
if (document.visibilityState !== "visible") return;
void githubReposConnection.focused();
Copy link
Contributor

Choose a reason for hiding this comment

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

I had to read this function implementation to know what it was doing. If we put the Query Observer in this component, we could use $githubUserReposQuery.refetch(), which would be more explicit.

Copy link
Contributor

Choose a reason for hiding this comment

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

Gotcha. The vanilla TanStack approach would be to use $githubQuery.refetch() in the component itself. Might be simpler?

Copy link
Contributor

@ericpgreen2 ericpgreen2 left a comment

Choose a reason for hiding this comment

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

Some more UXQA:

  • All user-facing text that says "github" or "Github" should be "GitHub"
  • After triggering the connect-to-GitHub flow via the UI, it looks like this page should say "... continue setup in your original tab."
    image
  • I get back 150 repos from the ListGithubUserRepos API, but the Select component only shows me the first 100.


function confirmConnectToGithub() {
confirmDialogOpen = false;
void githubConnection.check();
Copy link
Contributor

Choose a reason for hiding this comment

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

Here as well, I had to read the function implementation to understand what was going on. What about just

const githubUserStatusQuery = createAdminServiceGetGithubUserStatus();

...

window.open(
  $githubUserStatusQuery.data?.grantAccessUrl,
  "_blank",
)

@ericpgreen2
Copy link
Contributor

Writing down what we discussed live:

  • The motivation behind the GitHubConnection classes is to track the state of the connect-to-GitHub flow (which happens in a new tab). We want to be smart about when we refetch GetGitHubUserStatus and ListGitHubUserRepos, each of which can take a couple seconds. The refetches should happen after the connect-to-GitHub flow on page re-focus. However, these GitHubConnection classes are hard to read.
  • We should know why updating the GitHub repo leads to a page flash. We figured out it's the result of a GetProject request that omits cookies & returns a 401 error. But why does the request not include cookies?

@AdityaHegde AdityaHegde force-pushed the adityahegde/connect-to-github-ui branch from d18c8e8 to 21afe75 Compare July 22, 2024 14:18
@ericpgreen2
Copy link
Contributor

ericpgreen2 commented Jul 24, 2024

FYI, @jkhwu updated the designs to remove a couple cases of indentation. E.g., see these new mocks:

The GitHub block no longer is indented by the GitHub logo. Instead the logo is inside the button:
image

The "select your GitHub repository" form body is no longer indented by the GitHub logo: https://www.figma.com/design/Qt6EyotCBS3V6O31jVhMQ7/RILL?node-id=14933-609154&t=PgNKhdmzo8xhGY3P-1

Copy link
Contributor

@ericpgreen2 ericpgreen2 left a comment

Choose a reason for hiding this comment

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

UXQA:

  1. The "Are you sure you want to connect?" dialog flashes & proceeds without waiting for confirmation from the user. See Jam
  2. After going through the "choose other repos" flow, I get brought to this page that references the CLI.
    image
    Possibly related, I've been wondering – when the connect-to-GitHub flow is complete, can we somehow communicate this to the /status page, so it knows exactly when to refetch the list of repositories? Polling doesn't feel exactly right, (but the way you've contained the polling looks good).


function openGithubRepoCreator() {
// we need a popup window so we cannot use href
window.open("https://github.com/new", "", "width=1024,height=600");
Copy link
Contributor

@ericpgreen2 ericpgreen2 Jul 24, 2024

Choose a reason for hiding this comment

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

Nit: we can name the window (2nd parameter) githubWindow. I had to Google what the empty string represented.

this.openGithubConnectWindow(userStatus.grantAccessUrl);
}

public async refetch() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this function is only used internally – so it could be private?

@AdityaHegde AdityaHegde force-pushed the adityahegde/connect-to-github-ui branch from d9c6d47 to 61504ea Compare July 26, 2024 06:54
@AdityaHegde AdityaHegde force-pushed the adityahegde/connect-to-github-ui branch from 88539ad to af24d8b Compare July 26, 2024 12:34
@ericpgreen2
Copy link
Contributor

ericpgreen2 commented Jul 29, 2024

UXQA –

  1. After the "Choose another repo" flow, I see this page that references the CLI (cc @ericokuma):
    image
  2. I've followed the "subpath" placeholder text that advised to add a forward slash. It results in a double forward slash in the display.
    image
  3. I tried to edit the GitHub connection, I created a new blank repo, selected it in the dropdown, and clicked "Continue". See the 400 error below. If this flow is meant to write the files to the new repo, then it failed. If this flow is just meant to read the new repo's contents, then maybe we should have a custom error message that says something like "Repository is empty. Please select a repository that contains your Rill code files."
    image
    image
  4. I've added a file to my repo rill-test-ui-connect-to-github-2 so that it's non-empty. I confirmed my intention to overwrite and clicked "Continue." I hit the below 400 error.
    image


claims := auth.GetClaims(ctx)
if !claims.ProjectPermissions(ctx, proj.OrganizationID, proj.ID).ManageProject {
return nil, status.Error(codes.PermissionDenied, "does not have permission to delete project")
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Incorrect error msg delete project

@@ -0,0 +1,126 @@
package archive
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Should this be part of runtime/pkg since this is also used in runtime ?

SingleBranch: true,
})
if err != nil {
if errors.Is(err, transport.ErrEmptyRemoteRepository) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit : Can simplify the if-else block by switching the if condition

admin/server/github.go Outdated Show resolved Hide resolved
return fmt.Errorf("failed to copy data: %w", err)
}

// add back the older gitignore contents if present
Copy link
Member

Choose a reason for hiding this comment

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

If we are anyways overwriting all other files then I think it should be okay to also overwrite .gitignore file ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This was a requirement to not completely replace the existing file. But rather append like we do with rill init

Copy link
Member

Choose a reason for hiding this comment

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

IIRC in rill init we did not delete existing files so it made sense to not remove existing .gitignore.
Here we are deleting all existing files as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@nishantmonu51 @ericokuma Thoughts on the above?

@AdityaHegde AdityaHegde force-pushed the adityahegde/connect-to-github-ui branch from a27c050 to ce5ea9b Compare July 31, 2024 05:30
Copy link
Member

@k-anshul k-anshul left a comment

Choose a reason for hiding this comment

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

Looks good from backend POV apart from few nits.

defer os.RemoveAll(dir)

// use a subfolder for working with git
gitPath := filepath.Join(dir, "proj")
Copy link
Member

Choose a reason for hiding this comment

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

The subfolder should not be required now. We can directly use the temp_dir.

defer cancel()

// generate a temp dir to extract the archive
dir, err := os.MkdirTemp(os.TempDir(), "dest_git_repos")
Copy link
Member

Choose a reason for hiding this comment

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

Given this is used for both upload and git flow so we can just change the name to project or similar?

return err
}

// projPath is the target for extracting the archive
Copy link
Member

Choose a reason for hiding this comment

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

misplaced comment ?

Copy link
Member

@k-anshul k-anshul left a comment

Choose a reason for hiding this comment

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

Approving from backend POV

Comment on lines 26 to 33
public constructor() {}

public init(githubUrl: string, subpath: string, branch: string) {
this.githubUrl.set(githubUrl);
this.subpath.set(subpath);
this.branch.set(branch);
this.isConnected = !!githubUrl;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It'd be more idiomatic to implement the constructor, rather than create a separate init function

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ya that was ideal earlier. But it is simpler to do this than create a new instance everytime.

Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like the separation of concerns between the GitHubData and GitHubConnectionUpdater classes is blurry. It might be a matter of naming & comments, or maybe all the "update" methods (startRepoSelection, reselectRepos, openGitHubConnectWindow) should live on the "Updater" class?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

GitHubData is meant to be a wrapper around the user status and repos APIs. GitHubConnectionUpdater is only around the mutation to update. Both basically move code out of components as much as possible.

Comment on lines 84 to 90
!(await githubConnectionUpdater.update({
organization,
project,
force,
instanceId: $projectQuery.data?.prodDeployment?.runtimeInstanceId ?? "",
}))
) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Embedding the mutation into the conditional check makes this hard to read. I'd recommend declaring a self-describing boolean, like didUpdate.

Comment on lines +33 to +34
const githubData = new GithubData();
setGithubData(githubData);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should setGitHubData happen in the constructor?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

setGitHubData is the component tree logic. Makes sense for it to sit here.

Copy link
Contributor

@ericpgreen2 ericpgreen2 left a comment

Choose a reason for hiding this comment

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

Approving from the frontend POV 👍

@AdityaHegde AdityaHegde merged commit 8106e1a into main Jul 31, 2024
7 checks passed
@AdityaHegde AdityaHegde deleted the adityahegde/connect-to-github-ui branch July 31, 2024 14:53
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.

3 participants