Skip to content
This repository has been archived by the owner on Aug 1, 2022. It is now read-only.

refactor(ui): source browsing #995

Closed
wants to merge 27 commits into from
Closed

Conversation

sarahscott
Copy link
Contributor

@sarahscott sarahscott commented Oct 6, 2020

Why?

When we created Remote.svelte, we didn't have the option to type-check data in components. To enable its usage as we migrate from JS -> TS, I asserted an any type here:

  export let store: Readable<remote.Data<any>>;

...which essentially destroys any notion of type safety in the data value (YOLO🤪). While this is convenient, it doesn't allow us to use the magic of the type system in the most critical places - i.e. when we're rendering data that we expect to be of a certain shape.

The Remote.svelte component does make it very easy to load slots based on the remote store status (Loading/Success/Error), which I think is ergonomic and useful and can perhaps be its only function until we have generics in svelte. With this in mind, I'd like to transition away from the let:data={something} pattern and towards one where we know exactly what the T in Data<T> is before we render components.

To kick off this effort, I've typed the Project screen and its associated components, created a single source of truth for the project -> peer -> revisions -> commits data flow, and added a lot of comments to clarify what exactly these types are supposed to be.

Closes #970

@sarahscott sarahscott force-pushed the sos/typing-source-browsing branch from 92ac06f to 47f23ac Compare October 6, 2020 00:51
MeBrei
MeBrei previously requested changes Oct 6, 2020
Copy link
Contributor

@MeBrei MeBrei left a comment

Choose a reason for hiding this comment

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

Great effort tackling the refactoring of this code! When working on it, I also felt the need for it, but didn't quite know where to start.

I am a bit worried, changing this code while we are not able to test it properly. Tests related to the peer selector are currently skipped and we also can't test that in the app directly.

I also found the following regression:

  • when switching from one project to another the page of the second project does not load and errors with the following:

Screenshot 2020-10-06 at 10 46 46

cypress/integration/project_source_browsing.spec.js Outdated Show resolved Hide resolved
ui/src/source.ts Show resolved Hide resolved
@MeBrei
Copy link
Contributor

MeBrei commented Oct 6, 2020

It seems like your changes also solved #970

@sarahscott
Copy link
Contributor Author

@MeBrei fixed the regression! I'd say it's the perfect time to strongly type everything peer-related so it's easier to reason about when we have actual peers to test 😁

Copy link
Contributor

@MeBrei MeBrei 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 to me! Just added a comment for understanding the new way of using remote.

I think the tests are failing, because some contains have to be replaced with pick and using data-cy. The workaround for wait only works with get / pick. (One example is trying to do cy.contains(".i-am-well-hidden").click(); in the source browsing specs.

bind:currentRevision={$currentRevision}
{revisions} />
<Remote {store} context="project">
{#if project}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need this check? I thought that the slot (without name) in Remote is only rendered on Success.

Copy link
Contributor Author

@sarahscott sarahscott Oct 7, 2020

Choose a reason for hiding this comment

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

With the old patten (let:data={project}), that was the case, but now project is supplied by the store itself within the <script> tags, and its type is Project | undefined.

Also, Success doesn't necessarily mean there is data - it could be possible in some cases for endpoints to return empty arrays successfully (e.g. the projects/ endpoint could return [] if the user has no projects).

Copy link
Contributor

@FintanH FintanH left a comment

Choose a reason for hiding this comment

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

Mostly observing 👀

ui/src/identity.ts Show resolved Hide resolved
export interface Branch {
type: RevisionType.Branch;
name: string;
peerId?: string;
// The id of the project this branch belongs to
projectId: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
projectId: string;
projectUrn: string;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is worthy of its own pr because Project has an id in proxy - relevant to #840

ui/src/source.ts Show resolved Hide resolved
const defaultRevision =
defaultRevisions.branches.find(
branch => branch.name === defaultRevisions.defaultBranch
) || defaultRevisions.branches[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

And in the event that there are no branches?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this case, the revision selector won't show up but the project will still render. Before, the RevisionSelector would create a default revision that may or may not actually exist (https://github.com/radicle-dev/radicle-upstream/pull/995/files#diff-ac6e05ed01605cc8ea4ba88d402e6541L30).

Should we throw an error instead? I don't really like the idea of creating a revision in ui that we don't actually receive from proxy.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ya, I definitely agree that creating a made-up revision doesn't make sense. Could we have like an error window in the selector saying something like, "We couldn't find any revisions o.O"?

Again, some sort of error handling would be good to think about when we see partial functions like these :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Same question here about whether we'll address these here.

dispatch("select", { peerId });
};

$: currentPeer =
availablePeers.find(peer => peer.id === currentPeerId) || availablePeers[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, what happens if there are no availablePeers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The PeerSelector wouldn't render in that case - this would mean that proxy didn't return any Revisions, or that it returned Revisions without an Identity, which I don't think it's supposed to do 🤔 .

Alternatively we could throw an error, or display the disabled PeerSelector with some sort of 'No peers found" messaging.

Copy link
Contributor

Choose a reason for hiding this comment

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

which I don't think it's supposed to do .

Don't assume external resources will always do the thing they're supposed to. That's what I'm trying to get at here: we should think about failure cases and show appropriate errors when possible. Indexing arrays is a code smell in my eyes.

Copy link
Contributor

Choose a reason for hiding this comment

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

@xla do you plan to do anything about this in this PR, out of interest?

xla
xla previously requested changes Oct 7, 2020
Copy link
Contributor

@xla xla left a comment

Choose a reason for hiding this comment

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

Dope! Currently we can't just export let store: Readable<remote.Data<T>>; the situation?

ui/DesignSystem/Component/HorizontalMenu.svelte Outdated Show resolved Hide resolved
ui/DesignSystem/Component/HorizontalMenu/MenuItem.svelte Outdated Show resolved Hide resolved
ui/Screen/Project.svelte Outdated Show resolved Hide resolved
ui/src/transaction.ts Outdated Show resolved Hide resolved
@sarahscott
Copy link
Contributor Author

sarahscott commented Oct 7, 2020

Dope! Currently we can't just export let store: Readable<remote.Data>; the situation?

@xla we can't export generics from svelte components 😢
sveltejs/rfcs#38

@MeBrei MeBrei dismissed their stale review October 8, 2020 11:50

all points were addressed

@xla xla marked this pull request as draft October 14, 2020 12:38
@xla xla assigned xla and unassigned sarahscott Oct 14, 2020
@xla xla requested review from xla, MeBrei, FintanH and rudolfs October 18, 2020 12:57
@xla xla marked this pull request as ready for review October 18, 2020 12:57
@xla xla dismissed their stale review October 18, 2020 12:57

Adressed

@xla
Copy link
Contributor

xla commented Oct 18, 2020

Took this on and got it up-to-speed. PTAL.

@rudolfs
Copy link
Member

rudolfs commented Oct 19, 2020

Steps to repro:

  1. add radicle-upstream as a project
  2. click on a file in the file browser, for example CHANGELOG.md
  3. navigate back to your profile by clicking the profile icon in the sidebar
  4. go back to the project by clicking on radicle-upstream in the project list

Expected result: see the project source.
Actual result: exception in the console.

Screenshot 2020-10-19 at 09 19 06

dispatch("select", { peerId });
};

$: currentPeer =
availablePeers.find(peer => peer.id === currentPeerId) || availablePeers[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

@xla do you plan to do anything about this in this PR, out of interest?

}

export interface Sha {
type: RevisionType.Sha;
sha: string;
}

// Currently supported revision types in UI:
export type SupportedRevision = Branch | Tag;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is Sha not supported? 🤔 Or what's the issue here?

const defaultRevision =
defaultRevisions.branches.find(
branch => branch.name === defaultRevisions.defaultBranch
) || defaultRevisions.branches[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

Same question here about whether we'll address these here.

export const currentPeerId = writable(null);
export const resetCurrentPeerId = (): void => currentPeerId.set(null);

export const currentRevision = writable<Branch | Tag | undefined>(undefined);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
export const currentRevision = writable<Branch | Tag | undefined>(undefined);
export const currentRevision = writable<SupportedRevision | undefined>(undefined);

We could re-use the above type right?

@@ -170,12 +228,13 @@ interface FetchCommit extends event.Event<Kind> {
interface FetchCommits extends event.Event<Kind> {
kind: Kind.FetchCommits;
projectId: string;
revision: Branch;
revision: Branch | Tag;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
revision: Branch | Tag;
revision: SupportedRevision;


interface UpdateCurrentRevision extends event.Event<Kind> {
kind: Kind.UpdateCurrentRevision;
revision: Branch | Tag;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
revision: Branch | Tag;
revision: SupportedRevision;

@xla xla closed this Oct 24, 2020
@rudolfs rudolfs deleted the sos/typing-source-browsing branch February 10, 2021 11:01
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Project readme flickers on branch switch
5 participants