Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-intelligent-assistant': patch
---

Fix singular/plural handling for notebook card and document sidebar resource count using i18next `_one`/`_other` suffix keys.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ test.describe('Intelligent assistant notebooks conversation', () => {
const boot = await bootstrapLightspeedE2ePage(browser);
sharedPage = boot.page;
translations = boot.translations;
notebooks = new NotebookSurfacePage(sharedPage, translations);
notebooks = new NotebookSurfacePage(sharedPage, translations, boot.locale);
});

test.afterAll(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ test.describe('Intelligent assistant notebooks', () => {
const boot = await bootstrapLightspeedE2ePage(browser);
sharedPage = boot.page;
translations = boot.translations;
notebooks = new NotebookSurfacePage(sharedPage, translations);
notebooks = new NotebookSurfacePage(sharedPage, translations, boot.locale);
});

test('fullscreen list: header and empty state', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ export const NOTEBOOK_UNTITLED_GRID_NAME = 'Untitled Notebook';
* Same role as {@link ./LightspeedPage.ts}: shared locators/assertions keep specs short.
*/
export class NotebookSurfacePage {
private readonly pluralRules: Intl.PluralRules;

constructor(
private readonly page: Page,
private readonly t: LightspeedMessages,
) {}
locale = 'en',
) {
this.pluralRules = new Intl.PluralRules(locale);
}

/**
* Scoped to the fullscreen chatbot region that contains notebooks (list + notebook editor).
Expand Down Expand Up @@ -342,11 +347,16 @@ export class NotebookSurfacePage {
}

/**
* Shown on each card as count + plural label (same pattern as NotebookCard.tsx:
* `{ document_count } { t('notebooks.documents') }`, not `notebook.view.documents.count`).
* Shown on each card as a pluralized count label (same pattern as NotebookCard.tsx:
* `t('notebooks.documents', { count })` with `_one`/`_other` suffixes).
*/
formatNotebookCardDocumentsSummary(documentCount: number): string {
return `${documentCount} ${this.t['notebooks.documents']}`;
const category = this.pluralRules.select(documentCount);
const key =
category === 'one'
? 'notebooks.documents_one'
: 'notebooks.documents_other';
return (this.t[key] as string).replace('{{count}}', String(documentCount));
}

async expectUntitledNotebookCardCount(expected: number): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ export const intelligentAssistantTranslationRef: TranslationRef<
readonly 'notebooks.empty.title': string;
readonly 'notebooks.empty.description': string;
readonly 'notebooks.empty.action': string;
readonly 'notebooks.documents': string;
readonly 'notebooks.documents_one': string;
readonly 'notebooks.documents_other': string;
readonly 'notebooks.actions.rename': string;
readonly 'notebooks.actions.delete': string;
readonly 'notebooks.rename.inline.tooltip': string;
Expand All @@ -66,7 +67,8 @@ export const intelligentAssistantTranslationRef: TranslationRef<
readonly 'notebooks.card.openAria': string;
readonly 'notebook.view.title': string;
readonly 'notebook.view.close': string;
readonly 'notebook.view.documents.count': string;
readonly 'notebook.view.documents.count_one': string;
readonly 'notebook.view.documents.count_other': string;
readonly 'notebook.view.documents.add': string;
readonly 'notebook.view.upload.heading': string;
readonly 'notebook.view.upload.action': string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,23 @@ describe('DocumentSidebar', () => {
expect(screen.getByText('config.yaml')).toBeInTheDocument();
});

it('should use singular form for single document count', () => {
const documents = [mockDocument('doc-1', 'readme.md')];
render(<DocumentSidebar {...defaultProps} documents={documents} />);

expect(screen.getByText('1 Resource')).toBeInTheDocument();
});

it('should use plural form for multiple document count', () => {
const documents = [
mockDocument('doc-1', 'readme.md'),
mockDocument('doc-2', 'config.yaml'),
];
render(<DocumentSidebar {...defaultProps} documents={documents} />);

expect(screen.getByText('2 Resources')).toBeInTheDocument();
});

it('should display FileTypeIcon badges for documents', () => {
const documents = [mockDocument('doc-1', 'report.pdf')];
render(<DocumentSidebar {...defaultProps} documents={documents} />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,15 @@ describe('NotebookCard', () => {
expect(screen.getByText('My Notebook')).toBeInTheDocument();
});

it('should render the document count', () => {
it('should use singular form for single document count', () => {
const singleDocNotebook = { ...mockNotebook, document_count: 1 };
render(<NotebookCard {...defaultProps} notebook={singleDocNotebook} />);
expect(screen.getByText('1 Resource')).toBeInTheDocument();
});

it('should use plural form for multiple document count', () => {
render(<NotebookCard {...defaultProps} />);
expect(screen.getByText(/2/)).toBeInTheDocument();
expect(screen.getByText('2 Resources')).toBeInTheDocument();
});

it('should call onClick with notebook when card is clicked', () => {
Expand Down Expand Up @@ -223,8 +229,9 @@ describe('NotebookCard', () => {
});
});

it('should render document_count from the notebook session', () => {
render(<NotebookCard {...defaultProps} />);
expect(screen.getByText(/2/)).toBeInTheDocument();
it('should use plural form for zero document count', () => {
const zeroDocNotebook = { ...mockNotebook, document_count: 0 };
render(<NotebookCard {...defaultProps} notebook={zeroDocNotebook} />);
expect(screen.getByText('0 Resources')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,9 @@ export const DocumentSidebar = ({

<div className={classes.documentsRow}>
<Typography className={classes.documentCount}>
{t('notebook.view.documents.count', {
{(t as Function)('notebook.view.documents.count', {
count: totalCount,
} as any)}
})}
</Typography>
{isAddDisabled ? (
<Tooltip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ export const NotebookCard = ({
<div>
<div className={classes.notebookDocuments}>
<Typography variant="body2">
{notebook.document_count ?? 0} {t('notebooks.documents')}
{(t as Function)('notebooks.documents', {
count: notebook.document_count ?? 0,
})}
</Typography>
</div>
<div className={classes.notebookUpdated}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ const intelligentAssistantTranslationDe = createTranslationMessages({
'notebook.upload.modal.title': 'Ressource zum Notizbuch hinzufügen',
'notebook.view.close': 'Notizbuch schließen',
'notebook.view.documents.add': 'Hinzufügen',
'notebook.view.documents.count': '{{count}} Ressourcen',
'notebook.view.documents.count_one': '{{count}} Ressource',
'notebook.view.documents.count_other': '{{count}} Ressourcen',
'notebook.view.documents.maxReached':
'Maximal 10 Ressourcen sind erlaubt. Löschen Sie eine Ressource, um eine neue hochzuladen.',
'notebook.view.documents.uploading': 'Ressource wird hochgeladen',
Expand All @@ -257,7 +258,8 @@ const intelligentAssistantTranslationDe = createTranslationMessages({
'Dieses Notizbuch wird hier nicht mehr angezeigt. Dadurch werden auch zugehörige Aktivitäten wie Eingaben, Antworten und Feedback aus Ihrer Aktivität gelöscht.',
'notebooks.delete.title': '{{name}} löschen?',
'notebooks.delete.toast': 'Notizbuch gelöscht!',
'notebooks.documents': 'Ressourcen',
'notebooks.documents_one': '{{count}} Ressource',
'notebooks.documents_other': '{{count}} Ressourcen',
'notebooks.empty.action': 'Neues Notizbuch erstellen',
'notebooks.empty.description':
'Erstellen Sie ein neues Notizbuch, um Ihre Quellen zu organisieren und KI-gestützte Erkenntnisse zu gewinnen.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ const intelligentAssistantTranslationEs = createTranslationMessages({
'notebook.upload.modal.title': 'Agregar un recurso al cuaderno',
'notebook.view.close': 'Cerrar cuaderno',
'notebook.view.documents.add': 'Agregar',
'notebook.view.documents.count': '{{count}} Recursos',
'notebook.view.documents.count_one': '{{count}} Recurso',
'notebook.view.documents.count_other': '{{count}} Recursos',
'notebook.view.documents.maxReached':
'Se permiten un máximo de 10 recursos. Elimina un recurso para subir uno nuevo.',
'notebook.view.documents.uploading': 'Subiendo recurso',
Expand All @@ -253,7 +254,8 @@ const intelligentAssistantTranslationEs = createTranslationMessages({
'Ya no verás este cuaderno aquí. Esto también eliminará actividad relacionada como solicitudes, respuestas y comentarios de tu actividad.',
'notebooks.delete.title': '¿Eliminar {{name}}?',
'notebooks.delete.toast': '¡Cuaderno eliminado!',
'notebooks.documents': 'Recursos',
'notebooks.documents_one': '{{count}} Recurso',
'notebooks.documents_other': '{{count}} Recursos',
'notebooks.empty.action': 'Crear un cuaderno nuevo',
'notebooks.empty.description':
'Crea un nuevo cuaderno para organizar tus fuentes y generar información con IA.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ const intelligentAssistantTranslationFr = createTranslationMessages({
'notebook.upload.modal.title': 'Ajouter une ressource au carnet',
'notebook.view.close': 'Fermer le carnet',
'notebook.view.documents.add': 'Ajouter',
'notebook.view.documents.count': '{{count}} Ressources',
'notebook.view.documents.count_one': '{{count}} Ressource',
'notebook.view.documents.count_other': '{{count}} Ressources',
'notebook.view.documents.maxReached':
'Maximum 10 ressources autorisées. Supprimez une ressource pour en charger une nouvelle.',
'notebook.view.documents.uploading': 'Chargement de la ressource',
Expand All @@ -256,7 +257,8 @@ const intelligentAssistantTranslationFr = createTranslationMessages({
'Vous ne verrez plus ce carnet ici. Cela supprimera également l’activité associée comme les requêtes, réponses et retours depuis votre activité.',
'notebooks.delete.title': 'Supprimer {{name}} ?',
'notebooks.delete.toast': 'Carnet supprimé !',
'notebooks.documents': 'Ressources',
'notebooks.documents_one': '{{count}} Ressource',
'notebooks.documents_other': '{{count}} Ressources',
'notebooks.empty.action': 'Créer un nouveau carnet',
'notebooks.empty.description':
'Créez un nouveau carnet pour organiser vos sources et générer des informations alimentées par l’IA.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ const intelligentAssistantTranslationIt = createTranslationMessages({
'notebook.upload.modal.title': 'Aggiungi una risorsa al quaderno',
'notebook.view.close': 'Chiudi quaderno',
'notebook.view.documents.add': 'Aggiungi',
'notebook.view.documents.count': '{{count}} Risorse',
'notebook.view.documents.count_one': '{{count}} Risorsa',
'notebook.view.documents.count_other': '{{count}} Risorse',
'notebook.view.documents.maxReached':
'Sono consentite al massimo 10 risorse. Elimina una risorsa per caricarne una nuova.',
'notebook.view.documents.uploading': 'Caricamento risorsa',
Expand All @@ -254,7 +255,8 @@ const intelligentAssistantTranslationIt = createTranslationMessages({
'Non vedrai più questo quaderno qui. Questo eliminerà anche le attività correlate come prompt, risposte e feedback dalla tua attività.',
'notebooks.delete.title': 'Eliminare {{name}}?',
'notebooks.delete.toast': 'Quaderno eliminato!',
'notebooks.documents': 'Risorse',
'notebooks.documents_one': '{{count}} Risorsa',
'notebooks.documents_other': '{{count}} Risorse',
'notebooks.empty.action': 'Crea un nuovo quaderno',
'notebooks.empty.description':
'Crea un nuovo quaderno per organizzare le tue fonti e generare insight basati su IA.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ const intelligentAssistantTranslationJa = createTranslationMessages({
'notebook.upload.modal.title': 'ノートブックにリソースを追加',
'notebook.view.close': 'ノートブックを閉じる',
'notebook.view.documents.add': '追加',
'notebook.view.documents.count': '{{count}} 件のリソース',
'notebook.view.documents.count_one': '{{count}} 件のリソース',
'notebook.view.documents.count_other': '{{count}} 件のリソース',
'notebook.view.documents.maxReached':
'最大10個のリソースが許可されています。新しいリソースをアップロードするには、リソースを削除してください。',
'notebook.view.documents.uploading': 'リソースをアップロード中',
Expand All @@ -250,7 +251,8 @@ const intelligentAssistantTranslationJa = createTranslationMessages({
'このノートブックはここに表示されなくなります。アクティビティに関連するプロンプト、応答、フィードバックも削除されます。',
'notebooks.delete.title': '{{name}} を削除しますか?',
'notebooks.delete.toast': 'ノートブックを削除しました!',
'notebooks.documents': 'リソース',
'notebooks.documents_one': '{{count}} 件のリソース',
'notebooks.documents_other': '{{count}} 件のリソース',
'notebooks.empty.action': '新しいノートブックを作成',
'notebooks.empty.description':
'新しいノートブックを作成してソースを整理し、AI による洞察を生成します。',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export const intelligentAssistantMessages = {
'notebooks.empty.description':
'Start a new notebook to organize your sources and generate AI-powered insights.',
'notebooks.empty.action': 'Create a new notebook',
'notebooks.documents': 'Resources',
'notebooks.documents_one': '{{count}} Resource',
'notebooks.documents_other': '{{count}} Resources',
'notebooks.actions.rename': 'Rename',
'notebooks.actions.delete': 'Delete',
'notebooks.rename.inline.tooltip': 'Click to rename',
Expand All @@ -59,7 +60,8 @@ export const intelligentAssistantMessages = {
// Notebook view
'notebook.view.title': 'Untitled notebook',
'notebook.view.close': 'Close notebook',
'notebook.view.documents.count': '{{count}} Resources',
'notebook.view.documents.count_one': '{{count}} Resource',
'notebook.view.documents.count_other': '{{count}} Resources',
'notebook.view.documents.add': 'Add',
'notebook.view.upload.heading': 'Upload a resource to get started',
'notebook.view.upload.action': 'Upload a resource',
Expand Down
Loading