Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 42 additions & 9 deletions catalog-app/listing/listing.gts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
Component,
instanceOf,
realmURL,
type GetCardMenuItemParams,
type GetMenuItemParams,
} from 'https://cardstack.com/base/card-api';
import { commandData } from 'https://cardstack.com/base/resources/command-data';
import MarkdownField from 'https://cardstack.com/base/markdown';
Expand All @@ -34,6 +34,7 @@ import {
import { eq, type MenuItemOptions } from '@cardstack/boxel-ui/helpers';
import Refresh from '@cardstack/boxel-icons/refresh';
import Wand from '@cardstack/boxel-icons/wand';
import Package from '@cardstack/boxel-icons/package';

import AppListingHeader from '../components/app-listing-header';
import ChooseRealmAction from '../components/choose-realm-action';
Expand All @@ -44,8 +45,9 @@ import { listingActions, isReady } from '../resources/listing-actions';
import GetAllRealmMetasCommand from '@cardstack/boxel-host/commands/get-all-realm-metas';
import ListingGenerateExampleCommand from '@cardstack/boxel-host/commands/listing-generate-example';
import ListingUpdateSpecsCommand from '@cardstack/boxel-host/commands/listing-update-specs';
import CreateListingPRCommand from '@cardstack/boxel-host/commands/create-listing-pr';

import { getCardMenuItems } from '@cardstack/runtime-common';
import { getMenuItems } from '@cardstack/runtime-common';

import { Publisher } from './publisher';
import { Category } from './category';
Expand Down Expand Up @@ -180,9 +182,9 @@ class EmbeddedTemplate extends Component<typeof Listing> {
<template>
<div class='app-listing-embedded'>
<AppListingHeader
@thumbnailUrl={{@model.thumbnailURL}}
@thumbnailUrl={{@model.cardThumbnailURL}}
@name={{this.appName}}
@description={{@model.description}}
@description={{@model.cardDescription}}
@publisher={{this.publisherName}}
>
<:action>
Expand Down Expand Up @@ -562,6 +564,7 @@ class EmbeddedTemplate extends Component<typeof Listing> {
export class Listing extends CardDef {
static displayName = 'Listing';
static headerColor = '#6638ff';

@field name = contains(StringField);
@field summary = contains(MarkdownField);
@field specs = linksToMany(() => Spec);
Expand All @@ -573,14 +576,14 @@ export class Listing extends CardDef {
@field examples = linksToMany(() => CardDef);
@field skills = linksToMany(() => Skill);

@field title = contains(StringField, {
@field cardTitle = contains(StringField, {
computeVia(this: Listing) {
return this.name;
},
});

protected getGenerateExampleMenuItem(
params: GetCardMenuItemParams,
params: GetMenuItemParams,
): MenuItemOptions | undefined {
if (!params.commandContext) {
return undefined;
Expand Down Expand Up @@ -613,7 +616,7 @@ export class Listing extends CardDef {
}

private getUpdateSpecsMenuItem(
params: GetCardMenuItemParams,
params: GetMenuItemParams,
): MenuItemOptions | undefined {
if (params.menuContext !== 'interact') {
return;
Expand All @@ -635,9 +638,9 @@ export class Listing extends CardDef {
};
}

[getCardMenuItems](params: GetCardMenuItemParams): MenuItemOptions[] {
[getMenuItems](params: GetMenuItemParams): MenuItemOptions[] {
let menuItems = super
[getCardMenuItems](params)
[getMenuItems](params)
.filter((item) => item.label?.toLowerCase() !== 'create listing with ai');
if (params.menuContext === 'interact') {
const extra = this.getGenerateExampleMenuItem(params);
Expand All @@ -648,10 +651,40 @@ export class Listing extends CardDef {
if (updateSpecs) {
menuItems = [...menuItems, updateSpecs];
}
const createPRMenuItem = this.getCreatePRMenuItem(params);
if (createPRMenuItem) {
menuItems = [...menuItems, createPRMenuItem];
}
}
return menuItems;
}

private getCreatePRMenuItem(
params: GetMenuItemParams,
): MenuItemOptions | undefined {
if (params.menuContext !== 'interact') {
return;
}
if (!this[realmURL]?.href) {
return;
}
const commandContext = params.commandContext;
if (!commandContext) {
return;
}

return {
label: 'Make a PR',
action: async () => {
await new CreateListingPRCommand(commandContext).execute({
listing: this,
realm: this[realmURL]!.href,
});
},
icon: Package,
};
}

static isolated = EmbeddedTemplate;
static embedded = EmbeddedTemplate;
static fitted = ListingFittedTemplate;
Expand Down
12 changes: 6 additions & 6 deletions system-card/model-configuration.gts
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ export class ModelConfiguration extends BaseModelConfiguration {
},
});

// Override inherited title to respect cardInfo.title
@field title = contains(StringField, {
// Override inherited title to respect cardInfo.name
@field cardTitle = contains(StringField, {
computeVia: function (this: ModelConfiguration) {
return (
this.cardInfo?.title ||
this.cardInfo?.name ||
this.name ||
this.modelId ||
'Model Configuration'
Expand Down Expand Up @@ -114,7 +114,7 @@ export class ModelConfiguration extends BaseModelConfiguration {
<div class='strip-title'>{{if
@model.name
@model.name
(if @model.title @model.title 'Model')
(if @model.cardTitle @model.cardTitle 'Model')
}}</div>
</div>
<div class='strip-spacer'></div>
Expand Down Expand Up @@ -204,7 +204,7 @@ export class ModelConfiguration extends BaseModelConfiguration {
<h4 class='tile-title'>{{if
@model.name
@model.name
(if @model.title @model.title 'Model')
(if @model.cardTitle @model.cardTitle 'Model')
}}</h4>
{{#if @model.modelId}}
<div class='tile-id'>{{@model.modelId}}</div>
Expand Down Expand Up @@ -301,7 +301,7 @@ export class ModelConfiguration extends BaseModelConfiguration {
<h4 class='card-title'>{{if
@model.name
@model.name
(if @model.title @model.title 'Model')
(if @model.cardTitle @model.cardTitle 'Model')
}}</h4>
{{#if @model.modelId}}
<div class='card-id'>{{@model.modelId}}</div>
Expand Down
10 changes: 5 additions & 5 deletions system-card/model-updater.gts
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ class Isolated extends Component<typeof ModelUpdater> {
workingModelCard.canonicalSlug = apiModel.canonical_slug;
workingModelCard.name = apiModel.name;
workingModelCard.created = apiModel.created;
workingModelCard.description = apiModel.description || '';
workingModelCard.cardDescription = apiModel.description || '';
workingModelCard.contextLength = apiModel.context_length;

if (apiModel.pricing) {
Expand Down Expand Up @@ -346,7 +346,7 @@ class Isolated extends Component<typeof ModelUpdater> {
canonicalSlug: workingModelCard.canonicalSlug,
name: workingModelCard.name,
created: workingModelCard.created,
description: workingModelCard.description,
description: workingModelCard.cardDescription,
pricing: workingModelCard.pricing
? {
prompt: workingModelCard.pricing.prompt,
Expand Down Expand Up @@ -477,7 +477,7 @@ class Isolated extends Component<typeof ModelUpdater> {
<template>
<article class='model-updater'>
<header class='header'>
<h1>{{if @model.title @model.title 'OpenRouter Model Updater'}}</h1>
<h1>{{if @model.cardTitle @model.cardTitle 'OpenRouter Model Updater'}}</h1>
<p class='subtitle'>Fetch and update OpenRouter model data</p>
</header>

Expand Down Expand Up @@ -879,9 +879,9 @@ export class ModelUpdater extends CardDef {
description: 'Status of the last update operation',
});

@field title = contains(StringField, {
@field cardTitle = contains(StringField, {
computeVia: function (this: ModelUpdater) {
return this.cardInfo?.title || 'OpenRouter Model Updater';
return this.cardInfo?.name || 'OpenRouter Model Updater';
},
});
static isolated = Isolated;
Expand Down
24 changes: 12 additions & 12 deletions system-card/openrouter-model.gts
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ class Isolated extends Component<typeof OpenRouterModel> {
}

get truncatedDescription(): string {
if (!this.args.model.description) return '';
if (!this.args.model.cardDescription) return '';
const maxLength = 200;
if (this.args.model.description.length <= maxLength)
return this.args.model.description;
return this.args.model.description.substring(0, maxLength) + '...';
if (this.args.model.cardDescription.length <= maxLength)
return this.args.model.cardDescription;
return this.args.model.cardDescription.substring(0, maxLength) + '...';
}

<template>
Expand Down Expand Up @@ -203,16 +203,16 @@ class Isolated extends Component<typeof OpenRouterModel> {
{{/if}}
</div>

{{#if @model.description}}
{{#if @model.cardDescription}}
<div class='description-block'>
<p class='description-text'>
{{#if this.showFullDescription}}
{{@model.description}}
{{@model.cardDescription}}
{{else}}
{{this.truncatedDescription}}
{{/if}}
</p>
{{#if (gt @model.description.length 200)}}
{{#if (gt @model.cardDescription.length 200)}}
<button
class='show-more-btn'
{{on 'click' this.toggleDescription}}
Expand Down Expand Up @@ -776,7 +776,7 @@ export class OpenRouterModel extends ModelConfiguration {
// Identification (modelId and canonicalSlug inherited from parent)
@field name = contains(StringField); // e.g., "GPT-4"
@field created = contains(NumberField); // epoch seconds
@field description = contains(StringField);
@field cardDescription = contains(StringField);

// Pricing
@field pricing = contains(OpenRouterPricing);
Expand All @@ -800,10 +800,10 @@ export class OpenRouterModel extends ModelConfiguration {
@field defaultParameters = contains(OpenRouterDefaultParameters);

// Override inherited title to use name or modelId
@field title = contains(StringField, {
@field cardTitle = contains(StringField, {
computeVia: function (this: OpenRouterModel) {
return (
this.cardInfo?.title || this.name || this.modelId || 'OpenRouter Model'
this.cardInfo?.name || this.name || this.modelId || 'OpenRouter Model'
);
},
});
Expand Down Expand Up @@ -887,8 +887,8 @@ export class OpenRouterModel extends ModelConfiguration {
{{/if}}
</div>

{{#if @model.description}}
<p class='embedded-description'>{{@model.description}}</p>
{{#if @model.cardDescription}}
<p class='embedded-description'>{{@model.cardDescription}}</p>
{{/if}}

<div class='model-stats'>
Expand Down
6 changes: 3 additions & 3 deletions system-card/recommended-model.gts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class RecommendedModel extends ModelConfiguration {
},
});

@field title = contains(StringField, {
@field cardTitle = contains(StringField, {
computeVia: function (this: RecommendedModel) {
// Get the full model name (e.g., "OpenAI: GPT-5.1 Chat" or "Google: Gemini 2.5 Flash")
let fullModelName = '';
Expand Down Expand Up @@ -132,8 +132,8 @@ export class RecommendedModel extends ModelConfiguration {
// Non-role-specific: ✓ OpenAI: GPT-5.1 Chat
const autoTitle = `${purposeSegment}${modelSegment}${thinkingSuffix}`;

// Allow manual override via cardInfo.title
return this.cardInfo?.title || autoTitle;
// Allow manual override via cardInfo.name
return this.cardInfo?.name || autoTitle;
},
});

Expand Down