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

Enhance catalog entry and code mode RHS panel to be able to create new catalog entry #1993

Merged
merged 44 commits into from
Jan 24, 2025

Conversation

tintinthong
Copy link
Contributor

@tintinthong tintinthong commented Dec 31, 2024

This PR allows a user to create a new catalog entry when focusing on a card declaration that can be used (exported card or field) to create a catalog entry

Screenshot 2024-12-31 at 11 15 48 Screenshot 2024-12-31 at 11 15 54 Screenshot 2024-12-31 at 11 16 09 Screenshot 2024-12-31 at 11 16 20 Screenshot_2024-12-31_at_11 17 38

@tintinthong tintinthong marked this pull request as draft December 31, 2024 12:34
Copy link

github-actions bot commented Dec 31, 2024

Host Test Results

    1 files  ±0      1 suites  ±0   23m 15s ⏱️ +59s
742 tests +5  740 ✔️ +5  2 💤 ±0  0 ±0 
747 runs  +5  745 ✔️ +5  2 💤 ±0  0 ±0 

Results for commit 4a32548. ± Comparison against base commit 006d4f6.

♻️ This comment has been updated with latest results.

@@ -30,46 +33,12 @@ export class CatalogEntry extends CardDef {
return new URL(this.ref.module, this[relativeTo]).href;
},
});
@field demo = contains(FieldDef);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed this for now and will treat adding examples of different boxel spec in separate PR

Copy link
Contributor

@habdelra habdelra Dec 31, 2024

Choose a reason for hiding this comment

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

this actually needed a lot more discussion in terms of how we render this as it should be a polymorphic card and not a field. but yeah, good to remove for now...

by: 'createdAt',
direction: 'desc',
},
],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Focus on the last newly created catalog entry, if there are more than one

@@ -765,6 +783,59 @@ export class ${className} extends ${exportName} {
this.saveError = `Error creating card instance: ${e.message}`;
}
});

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I make use of create-file-modal bcos other modals assume the existence of a catalog entry. This is not displayed in the top right for simplicity

</CatalogEntryContainer>
</template>
};
@field examples = linksToMany(CardDef);
Copy link
Contributor Author

@tintinthong tintinthong Dec 31, 2024

Choose a reason for hiding this comment

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

stub this for now. We need to consider ways to model examples for both fieldDef and cardDef. I think @demo used to be the way to do this but let's think about this in another PR. We may very well just re-include demo but we need to investigate its usage more carefully. But, given fields are mostly displayed in cards anyway, maybe we only want to link to cards for now

@tintinthong tintinthong requested a review from a team December 31, 2024 18:09
@tintinthong tintinthong marked this pull request as ready for review December 31, 2024 18:09
get showBoxelSpecPreview() {
return (
!this.moduleContentsResource.isLoading &&
this.selectedDeclaration?.exportName
Copy link
Contributor

Choose a reason for hiding this comment

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

Should boxel spec pane be present for any module, or just for cards? What does this logic say?

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 logic, it models the boxel spec as present in any selected code with an exportName (including defaults)

  • exported card
  • exported field

However, at the top-level, exported variable, function, class which are not card or fields, are ignored entirely by the RHS

Screenshot 2024-12-31 at 13 33 50

</BoxelButton>
{{else}}
<div class='boxel-spec-selector'>
<RadioInput
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it make sense to show a Radio button if there is only one spec instance?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There can be more than one boxel spec / catalog entry since the boxel spec is simply a card that points to a code ref.

A user can make this themselves. And I don't think we are in control of the user making an extra code spec

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand that there can be more than one. But I also think that in most cases there will be zero or one. So I wonder if radio input should be a special case and not the usual case.

packages/base/catalog-entry.gts Show resolved Hide resolved
@@ -765,6 +783,57 @@ export class ${className} extends ${exportName} {
this.saveError = `Error creating card instance: ${e.message}`;
}
});

private createBoxelSpecInstance = restartableTask(async () => {
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 its probably time to split the different files that can be created into different modules. right now this module is doing a lot. perhaps we can use a strategy pattern to figure out how to create the right type of file.

Copy link
Contributor

Choose a reason for hiding this comment

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

it could be a simple as having a module that exports an async function that is the meat of this task, and then setting up a map of file types to functions to make the file type and then just executing the async function that makes the file.

Copy link
Contributor Author

@tintinthong tintinthong Jan 6, 2025

Choose a reason for hiding this comment

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

it could be a simple as having a module that exports an async function that is the meat of this task, and then setting up a map of file types to functions to make the file type and then just executing the async function that makes the file.

Im not sure that I went overkill on this but I have done some work which might be a little bit of a restructuring. Tho particularly, I shud not include this in as part of this PR to ensure there are no regressions independently.

The refactor is essentially

  • Use a service to store the state of the modal createFileService. The service is responsible for triggering the open of the modal and deciding the strategy based upon the api call. So consumers are expected to inject this into them to open the modal.
  • create separate strategies that will have an interface of create()
  • the strategies CreateCardInstance, CreateCardDefinition, IneritCardDefinition, CreateCardInstanceFromDefinition, CreateFieldDefinition`. Each of these strategies will require different things but the service will validate this when opening.
  • the strategies will take in a composition of FileNameHandling (fileName, displayName) and CatalogEntryHandling (catalogEntry). Each of these classes should handle the edit and default state internally. eg catalogEntry will hold the dropdown state within itself. Each of these tend to within itself check whether its the treatment for a card or a field, eg gts vs json or adoptsFrom vs inherit.
  • the createFileModal then just relay the strategy within it. The create button would just be a single button that will call create from the strategy. A lot of the displays in the modal should be displayed based upon isCatalogEntryHandling and isFileNameHandling. So, those compositions are key to the UI.

What do you think so far?

I feel there are some issues I run into but not too major

  • I think I have instantiated the strategies as classes but I seem to want to include services inside that strategy but can't inject them by default it in unless I use some EmberObject stuff. I decided to pass it down using a context object into the instantiation of the class.
  • When opening the modal and creating a card, there is a redirect of the codePath and it sets everything to edit mode. The function setPreview is all the way up the top in code-submode that means consumers will actually want to call this action on code-submode perhaps this is fine since the preview-format exists on code-submode itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Im going to push a PR out for this separately

@tintinthong tintinthong force-pushed the introduce-boxel-spec branch from 99656e6 to c7e7122 Compare January 1, 2025 15:37
@tintinthong
Copy link
Contributor Author

tintinthong commented Jan 6, 2025

Im currently working on this design.

Screenshot 2025-01-06 at 08 27 12 Screenshot 2025-01-06 at 08 34 37

The changes are

  • having a dropdown
  • in each dropdown item, cut the path and use realm icon. in the plural case, I notice there is no tag of the spec anywhere.. I am clarifying with chris now
  • the accordion will display the n instances if there are any
  • if there are n = 1, the dropdown arrow shud not be there
  • there shud be a create button at the accordion (but shud wait for example from ian on how to implement them)

@tintinthong tintinthong force-pushed the introduce-boxel-spec branch from c7e7122 to 1c1e596 Compare January 8, 2025 18:09
@tintinthong tintinthong marked this pull request as draft January 9, 2025 14:56
@burieberry
Copy link
Contributor

burieberry commented Jan 14, 2025

Some observations -- if these are outside of the scope of this PR, we should split up the work on linear:
I clicked on "Create" on Boxel Spec on app-card to create a spec for Tab fieldDef:

  • "Create" on Boxel Spec panel only allows me to create a single spec
  • Boxel Spec panel is only showing me the spec for Tab and not for AppCard
  • The newly created spec does not know its type (it's null). isField is also marked as false even though I created it from a Field Def.
  • "Add Cards" for Examples button displays everything, even when the ref is known.
  • The new specs I published did not appear when I clicked on Create New from interact mode cards grid

Visual design:

  • The spacing and alignments can use some tidying up.
  • The pill with the highlighted arrow on exported name looks like it will be a button, but it's not.

Comment on lines 56 to 60
@field title = contains(StringField, {
computeVia: function (this: CatalogEntry) {
return this[realmInfo]?.name;
return this.name || this.ref.name;
},
});
Copy link
Contributor

Choose a reason for hiding this comment

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

This won't work well for default exports. The ref name will be 'default' for each one

Copy link
Contributor

@burieberry burieberry left a comment

Choose a reason for hiding this comment

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

I came across a couple of issues as I wrote in my comment. I think you need a test that covers the case for a module with a default export and multiple FieldDef and CardDef exports and make sure it works as expected

@tintinthong
Copy link
Contributor Author

tintinthong commented Jan 14, 2025

Some observations -- if these are outside of the scope of this PR, we should split up the work on linear: I clicked on "Create" on Boxel Spec on app-card to create a spec for Tab fieldDef:

  • "Create" on Boxel Spec panel only allows me to create a single spec

That is intended to encourage users not to create more than one spec per code ref

  • Boxel Spec panel is only showing me the spec for Tab and not for AppCard

This dependes on the code you have selected on the LHS definition picker. You need to choose AppCard as the selected export

  • The newly created spec does not know its type (it's null). isField is also marked as false even though I created it from a Field Def.

Good catch.

  • "Add Cards" for Examples button displays everything, even when the ref is known.

I think this can be useful to have.

  • The new specs I published did not appear when I clicked on Create New from interact mode cards grid

Hmmm weird. I think this is unexpected behaviour. I will look into it

Visual design:

  • The spacing and alignments can use some tidying up.
  • The pill with the highlighted arrow on exported name looks like it will be a button, but it's not.

Let me get the behaviour complete first and then maybe we can pair on this

@tintinthong
Copy link
Contributor Author

The new specs I published did not appear when I clicked on Create New from interact mode cards grid

I can't seem to re-create this behaviour

@tintinthong
Copy link
Contributor Author

"Add Cards" for Examples button displays everything, even when the ref is known.

this seems more involved than I anticipate. I have filed this here https://linear.app/cardstack/issue/CS-7831/link-to-examples-pertaining-to-code-ref

@burieberry
Copy link
Contributor

Tried this again and the spec type and isCard/isField logic is now working as expected. I was also able to use the newly generated card def catalog entry to create new instances. 👍

@tintinthong tintinthong merged commit 4edc5d9 into main Jan 24, 2025
51 checks passed
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