Skip to content

Commit

Permalink
Fix card catalog title
Browse files Browse the repository at this point in the history
  • Loading branch information
FadhlanR committed Mar 18, 2024
1 parent 2b28723 commit 4f09cfb
Show file tree
Hide file tree
Showing 5 changed files with 402 additions and 264 deletions.
17 changes: 13 additions & 4 deletions packages/host/app/components/card-catalog/modal.gts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
type CreateNewCard,
Deferred,
type RealmInfo,
Loader,
} from '@cardstack/runtime-common';

import type { Query, Filter } from '@cardstack/runtime-common/query';
Expand Down Expand Up @@ -327,7 +328,11 @@ export default class CardCatalogModal extends Component<Signature> {
} = {},
) => {
this.stateId++;
let title = chooseCardTitle(query.filter, opts?.multiSelect);
let title = await chooseCardTitle(
query.filter,
this.loaderService.loader,
opts?.multiSelect,
);
let request = new TrackedObject<Request>({
search: getSearchResults(this, () => query),
deferred: new Deferred(),
Expand Down Expand Up @@ -527,14 +532,18 @@ export default class CardCatalogModal extends Component<Signature> {
);
}

function chooseCardTitle(
async function chooseCardTitle(
filter: Filter | undefined,
loader: Loader,
multiSelect?: boolean,
): string {
): Promise<string> {
if (!filter) {
return DEFAULT_CHOOOSE_CARD_TITLE;
}
let suggestions = suggestCardChooserTitle(filter, 0, { multiSelect });
let suggestions = await suggestCardChooserTitle(filter, 0, {
loader,
multiSelect,
});
return (
getSuggestionWithLowestDepth(suggestions) ?? DEFAULT_CHOOOSE_CARD_TITLE
);
Expand Down
51 changes: 30 additions & 21 deletions packages/host/app/utils/text-suggestion.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import a from 'indefinite';

import { getPlural } from '@cardstack/runtime-common';
import {
CodeRef,
getPlural,
loadCard,
Loader,
} from '@cardstack/runtime-common';
import {
isCardTypeFilter,
isEveryFilter,
Expand All @@ -12,63 +17,67 @@ interface ChooseCardSuggestion {
depth: number;
}

interface TextOpts {
interface Opts {
loader: Loader;
multiSelect?: boolean;
}
export function suggestCardChooserTitle(
export async function suggestCardChooserTitle(
filter: Filter,
depth = 0, //lower the depth, higher the priority
textOpts?: TextOpts,
): ChooseCardSuggestion[] {
opts: Opts,
): Promise<ChooseCardSuggestion[]> {
let MAX_RECURSION_DEPTH = 2;
if (filter === undefined || depth + 1 > MAX_RECURSION_DEPTH) {
return [];
}
let suggestions: ChooseCardSuggestion[] = [];
//--base case--
if ('on' in filter && filter.on !== undefined) {
let cardRefName = (filter.on as { module: string; name: string }).name;
return [{ suggestion: titleText(cardRefName, 'card', textOpts), depth }];
let cardDisplayName = await getCardDisplayName(opts.loader, filter.on);
return [{ suggestion: titleText(cardDisplayName, 'card', opts), depth }];
}
if (isCardTypeFilter(filter)) {
let cardRefName = (filter.type as { module: string; name: string }).name;
if (cardRefName == 'CardDef') {
let cardDisplayName = await getCardDisplayName(opts.loader, filter.type);
if (cardDisplayName == 'Card') {
suggestions.push({
suggestion: titleText('Card', 'instance', textOpts),
suggestion: titleText('Card', 'instance', opts),
depth,
});
} else {
suggestions.push({
suggestion: titleText(cardRefName, 'card', textOpts),
suggestion: titleText(cardDisplayName, 'card', opts),
depth,
});
}
}
//--inductive case--
if (isEveryFilter(filter)) {
let nestedSuggestions = filter.every.flatMap((f) =>
suggestCardChooserTitle(f, depth + 1, textOpts),
);
let nestedSuggestions = await Promise.all(
filter.every.map(
async (f) => await suggestCardChooserTitle(f, depth + 1, opts),
),
).then((arrays) => arrays.flat());
suggestions = [...suggestions, ...nestedSuggestions];
}
return suggestions;
}

type CardNoun = 'instance' | 'type' | 'card';

function titleText(
cardRefName: string,
cardNoun: CardNoun,
textOpts?: TextOpts,
) {
let object = `${cardRefName} ${cardNoun}`;
if (textOpts?.multiSelect) {
function titleText(cardDisplayName: string, cardNoun: CardNoun, opts?: Opts) {
let object = `${cardDisplayName} ${cardNoun}`;
if (opts?.multiSelect) {
return `Select 1 or more ${getPlural(object)}`;
} else {
return `Choose ${a(object)}`;
}
}

async function getCardDisplayName(loader: Loader, codeRef: CodeRef) {
let card = await loadCard(codeRef, { loader });
return card.displayName;
}

export function getSuggestionWithLowestDepth(
items: ChooseCardSuggestion[],
): string | undefined {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ module('Integration | card-editor', function (hooks) {
let { default: StringField } = string;

class Pet extends CardDef {
static displayName = 'Pet';
@field name = contains(StringField);
static embedded = class Embedded extends Component<typeof this> {
<template>
Expand All @@ -94,6 +95,7 @@ module('Integration | card-editor', function (hooks) {
};
}
class FancyPet extends Pet {
static displayName = 'FancyPet';
@field favoriteToy = contains(StringField);
static embedded = class Embedded extends Component<typeof this> {
<template>
Expand All @@ -106,6 +108,7 @@ module('Integration | card-editor', function (hooks) {
};
}
class Person extends CardDef {
static displayName = 'Person';
@field firstName = contains(StringField);
@field pet = linksTo(Pet);
static isolated = class Embedded extends Component<typeof this> {
Expand Down
Loading

0 comments on commit 4f09cfb

Please sign in to comment.