Skip to content

Commit 4fed4f3

Browse files
SF-3043 Update tab header localizations when locale updated (#3303)
1 parent 8e3cea2 commit 4fed4f3

15 files changed

+154
-133
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export abstract class TabFactoryService<TType, T> {
2-
abstract createTab(tabType: TType, tabOptions?: Partial<T>): Promise<T>;
2+
abstract createTab(tabType: TType, tabOptions?: Partial<T>): T;
33
}

src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,23 @@ describe('TabGroupComponent', () => {
5858
expect(component.addTab).toHaveBeenCalledWith(newTabType, tabOptions);
5959
});
6060

61-
it('should add tab using TabFactory and TabStateService when addTab is called', async () => {
61+
it('should add tab using TabFactory and TabStateService when addTab is called', () => {
6262
const newTabType = 'test';
6363
const tab: TabInfo<string> = {
6464
id: uuid(),
6565
type: 'test',
66-
headerText: 'Tab Header',
66+
headerText$: of('Tab Header'),
6767
closeable: false,
6868
movable: true
6969
};
7070

7171
const tabFactory = TestBed.inject(TabFactoryService);
7272
const tabStateService = TestBed.inject(TabStateService);
7373

74-
spyOn(tabFactory, 'createTab').and.returnValue(Promise.resolve(tab));
74+
spyOn(tabFactory, 'createTab').and.returnValue(tab);
7575
spyOn(tabStateService, 'addTab');
7676

77-
await component.addTab(newTabType);
77+
component.addTab(newTabType);
7878

7979
expect(tabFactory.createTab).toHaveBeenCalledWith(newTabType, {});
8080
expect(tabStateService.addTab).toHaveBeenCalledWith(component.groupId, tab);

src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ export class TabGroupComponent implements OnChanges {
7272
});
7373
}
7474

75-
async addTab(newTabType: string, tabOptions: any = {}): Promise<void> {
76-
const tab = await this.tabFactory.createTab(newTabType, tabOptions);
75+
addTab(newTabType: string, tabOptions: any = {}): void {
76+
const tab = this.tabFactory.createTab(newTabType, tabOptions);
7777
this.tabState.addTab(this.groupId, tab);
7878
}
7979

src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.stories.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ import {
3636
>
3737
@for (tab of tabGroup.value.tabs; track tab.id) {
3838
<app-tab [closeable]="tab.closeable" [movable]="tab.movable">
39-
<ng-template sf-tab-header><div [innerHTML]="tab.headerText"></div></ng-template>
40-
<p><span [innerHTML]="tab.headerText"></span> in {{ tabGroup.key }}</p>
39+
<ng-template sf-tab-header><div [innerHTML]="tab.headerText$ | async"></div></ng-template>
40+
<p><span [innerHTML]="tab.headerText$ | async"></span> in {{ tabGroup.key }}</p>
4141
</app-tab>
4242
}
4343
</app-tab-group>
@@ -95,7 +95,7 @@ export default {
9595
tab = {
9696
id: uuid(),
9797
type: 'blank',
98-
headerText: 'New tab',
98+
headerText$: of('New tab'),
9999
closeable: true,
100100
movable: true
101101
};
@@ -104,7 +104,7 @@ export default {
104104
tab = {
105105
id: uuid(),
106106
type: 'type-a',
107-
headerText: 'Tab A',
107+
headerText$: of('Tab A'),
108108
closeable: true,
109109
movable: true
110110
};
@@ -114,7 +114,7 @@ export default {
114114
tab = {
115115
id: uuid(),
116116
type: 'type-b',
117-
headerText: 'Tab B',
117+
headerText$: of('Tab B'),
118118
closeable: true,
119119
movable: true
120120
};
@@ -137,21 +137,21 @@ const tabGroups: TabGroup<string, TabInfo<string>>[] = [
137137
{
138138
id: uuid(),
139139
type: 'type-a',
140-
headerText: 'Uncloseable, unmovable Tab 1 is great!',
140+
headerText$: of('Uncloseable, unmovable Tab 1 is great!'),
141141
closeable: false,
142142
movable: false
143143
},
144144
{
145145
id: uuid(),
146146
type: 'type-b',
147-
headerText: 'Tab 2 <em>wow!</em>',
147+
headerText$: of('Tab 2 <em>wow!</em>'),
148148
closeable: true,
149149
movable: true
150150
},
151151
{
152152
id: uuid(),
153153
type: 'type-c',
154-
headerText: 'Tab 3',
154+
headerText$: of('Tab 3'),
155155
icon: 'book',
156156
closeable: true,
157157
movable: true
@@ -189,13 +189,13 @@ export const TabReorderAndMove: Story = {
189189
{
190190
id: uuid(),
191191
type: 'type-a',
192-
headerText: 'Uncloseable, unmovable Tab 1',
192+
headerText$: of('Uncloseable, unmovable Tab 1'),
193193
closeable: false,
194194
movable: false
195195
},
196-
{ id: uuid(), type: 'type-b', headerText: 'Tab 2', closeable: true, movable: true },
197-
{ id: uuid(), type: 'type-c', headerText: 'Tab 3', closeable: true, movable: true },
198-
{ id: uuid(), type: 'type-c', headerText: 'Tab 4', closeable: true, movable: true }
196+
{ id: uuid(), type: 'type-b', headerText$: of('Tab 2'), closeable: true, movable: true },
197+
{ id: uuid(), type: 'type-c', headerText$: of('Tab 3'), closeable: true, movable: true },
198+
{ id: uuid(), type: 'type-c', headerText$: of('Tab 4'), closeable: true, movable: true }
199199
])
200200
]
201201
}

src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-state/tab-state.service.spec.ts

Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { TestBed } from '@angular/core/testing';
2-
import { take } from 'rxjs';
2+
import { of, take } from 'rxjs';
33
import { v4 as uuid } from 'uuid';
44
import { TabGroup } from './tab-group';
55
import { TabInfo, TabStateService } from './tab-state.service';
@@ -8,8 +8,8 @@ describe('TabStateService', () => {
88
let service: TabStateService<string, TabInfo<string>>;
99
const groupId = 'testGroup';
1010
const tabs: TabInfo<string>[] = [
11-
{ id: uuid(), type: 'tab1', headerText: 'Tab 1', closeable: true, movable: true },
12-
{ id: uuid(), type: 'tab2', headerText: 'Tab 2', closeable: false, movable: true }
11+
{ id: uuid(), type: 'tab1', headerText$: of('Tab 1'), closeable: true, movable: true },
12+
{ id: uuid(), type: 'tab2', headerText$: of('Tab 2'), closeable: false, movable: true }
1313
];
1414

1515
beforeEach(() => {
@@ -49,8 +49,8 @@ describe('TabStateService', () => {
4949
const groupId1: string = 'group1';
5050
const groupId2: string = 'group2';
5151
const tabs: TabInfo<string>[] = [
52-
{ id: uuid(), type: 'type-a', headerText: 'Header 1', closeable: true, movable: true },
53-
{ id: uuid(), type: 'type-b', headerText: 'Header 2', closeable: true, movable: true }
52+
{ id: uuid(), type: 'type-a', headerText$: of('Header 1'), closeable: true, movable: true },
53+
{ id: uuid(), type: 'type-b', headerText$: of('Header 2'), closeable: true, movable: true }
5454
];
5555
service['groups'].set(groupId1, new TabGroup<string, any>(groupId1, tabs));
5656
service['groups'].set(groupId2, new TabGroup<string, any>(groupId2, tabs));
@@ -72,12 +72,12 @@ describe('TabStateService', () => {
7272
const groupId1: string = 'group1';
7373
const groupId2: string = 'group2';
7474
const tabs1: TabInfo<string>[] = [
75-
{ id: uuid(), type: 'type-a', headerText: 'Header 1', closeable: true, movable: true },
76-
{ id: uuid(), type: 'type-b', headerText: 'Header 2', closeable: true, movable: true }
75+
{ id: uuid(), type: 'type-a', headerText$: of('Header 1'), closeable: true, movable: true },
76+
{ id: uuid(), type: 'type-b', headerText$: of('Header 2'), closeable: true, movable: true }
7777
];
7878
const tabs2: TabInfo<string>[] = [
79-
{ id: uuid(), type: 'type-b', headerText: 'Header 2', closeable: true, movable: true },
80-
{ id: uuid(), type: 'type-a', headerText: 'Header 1', closeable: true, movable: true }
79+
{ id: uuid(), type: 'type-b', headerText$: of('Header 2'), closeable: true, movable: true },
80+
{ id: uuid(), type: 'type-a', headerText$: of('Header 1'), closeable: true, movable: true }
8181
];
8282
service['groups'].set(groupId1, new TabGroup<string, any>(groupId1, tabs1));
8383
service['groups'].set(groupId2, new TabGroup<string, any>(groupId2, tabs2));
@@ -90,8 +90,8 @@ describe('TabStateService', () => {
9090
const groupId1: string = 'group1';
9191
const groupId2: string = 'group2';
9292
const tabs: TabInfo<string>[] = [
93-
{ id: uuid(), type: 'type-a', headerText: 'Header 1', closeable: true, movable: true },
94-
{ id: uuid(), type: 'type-b', headerText: 'Header 2', closeable: true, movable: true }
93+
{ id: uuid(), type: 'type-a', headerText$: of('Header 1'), closeable: true, movable: true },
94+
{ id: uuid(), type: 'type-b', headerText$: of('Header 2'), closeable: true, movable: true }
9595
];
9696
service['groups'].set(groupId1, new TabGroup<string, any>(groupId1, tabs));
9797
service['groups'].set(groupId2, new TabGroup<string, any>(groupId2, tabs));
@@ -107,7 +107,7 @@ describe('TabStateService', () => {
107107
const tab: TabInfo<string> = {
108108
id: uuid(),
109109
type: 'type-a',
110-
headerText: 'Header',
110+
headerText$: of('Header'),
111111
closeable: true,
112112
movable: true
113113
};
@@ -121,7 +121,7 @@ describe('TabStateService', () => {
121121
const tab: TabInfo<string> = {
122122
id: uuid(),
123123
type: 'type-a',
124-
headerText: 'Header',
124+
headerText$: of('Header'),
125125
closeable: true,
126126
movable: true
127127
};
@@ -137,14 +137,14 @@ describe('TabStateService', () => {
137137
{
138138
id: uuid(),
139139
type: 'type-a',
140-
headerText: 'Header 1',
140+
headerText$: of('Header 1'),
141141
closeable: true,
142142
movable: true
143143
},
144144
{
145145
id: uuid(),
146146
type: 'type-a',
147-
headerText: 'Header 2',
147+
headerText$: of('Header 2'),
148148
closeable: true,
149149
movable: true
150150
}
@@ -158,9 +158,9 @@ describe('TabStateService', () => {
158158
it('should move a tab within the same group', () => {
159159
const groupId: string = 'source';
160160
const tabs: TabInfo<string>[] = [
161-
{ id: uuid(), type: 'type-a', headerText: 'Header 1', closeable: true, movable: true },
162-
{ id: uuid(), type: 'type-b', headerText: 'Header 2', closeable: true, movable: true },
163-
{ id: uuid(), type: 'type-c', headerText: 'Header 3', closeable: true, movable: true }
161+
{ id: uuid(), type: 'type-a', headerText$: of('Header 1'), closeable: true, movable: true },
162+
{ id: uuid(), type: 'type-b', headerText$: of('Header 2'), closeable: true, movable: true },
163+
{ id: uuid(), type: 'type-c', headerText$: of('Header 3'), closeable: true, movable: true }
164164
];
165165
service['groups'].set(groupId, new TabGroup<string, any>(groupId, tabs));
166166
service.moveTab({ groupId, index: 0 }, { groupId, index: 2 });
@@ -170,9 +170,9 @@ describe('TabStateService', () => {
170170
it('should update selected index when moving a tab within the same group', () => {
171171
const groupId: string = 'source';
172172
const tabs: TabInfo<string>[] = [
173-
{ id: uuid(), type: 'type-a', headerText: 'Header 1', closeable: true, movable: true },
174-
{ id: uuid(), type: 'type-b', headerText: 'Header 2', closeable: true, movable: true },
175-
{ id: uuid(), type: 'type-c', headerText: 'Header 3', closeable: true, movable: true }
173+
{ id: uuid(), type: 'type-a', headerText$: of('Header 1'), closeable: true, movable: true },
174+
{ id: uuid(), type: 'type-b', headerText$: of('Header 2'), closeable: true, movable: true },
175+
{ id: uuid(), type: 'type-c', headerText$: of('Header 3'), closeable: true, movable: true }
176176
];
177177
const group = new TabGroup<string, any>(groupId, tabs);
178178
service['groups'].set(groupId, group);
@@ -198,12 +198,12 @@ describe('TabStateService', () => {
198198
const fromGroupId: string = 'source';
199199
const toGroupId: string = 'target';
200200
const fromTabs: TabInfo<string>[] = [
201-
{ id: uuid(), type: 'type-a', headerText: 'Header 1', closeable: true, movable: true },
202-
{ id: uuid(), type: 'type-b', headerText: 'Header 2', closeable: true, movable: true }
201+
{ id: uuid(), type: 'type-a', headerText$: of('Header 1'), closeable: true, movable: true },
202+
{ id: uuid(), type: 'type-b', headerText$: of('Header 2'), closeable: true, movable: true }
203203
];
204204
const toTabs: TabInfo<string>[] = [
205-
{ id: uuid(), type: 'type-c', headerText: 'Header 3', closeable: true, movable: true },
206-
{ id: uuid(), type: 'type-d', headerText: 'Header 4', closeable: true, movable: true }
205+
{ id: uuid(), type: 'type-c', headerText$: of('Header 3'), closeable: true, movable: true },
206+
{ id: uuid(), type: 'type-d', headerText$: of('Header 4'), closeable: true, movable: true }
207207
];
208208
service['groups'].set(fromGroupId, new TabGroup<string, any>(fromGroupId, fromTabs));
209209
service['groups'].set(toGroupId, new TabGroup<string, any>(toGroupId, toTabs));
@@ -216,14 +216,14 @@ describe('TabStateService', () => {
216216
const fromGroupId: string = 'source';
217217
const toGroupId: string = 'target';
218218
const fromTabs: TabInfo<string>[] = [
219-
{ id: uuid(), type: 'type-a', headerText: 'Header 1', closeable: true, movable: true },
220-
{ id: uuid(), type: 'type-b', headerText: 'Header 2', closeable: true, movable: true },
221-
{ id: uuid(), type: 'type-b', headerText: 'Header 3', closeable: true, movable: true },
222-
{ id: uuid(), type: 'type-b', headerText: 'Header 4', closeable: true, movable: true }
219+
{ id: uuid(), type: 'type-a', headerText$: of('Header 1'), closeable: true, movable: true },
220+
{ id: uuid(), type: 'type-b', headerText$: of('Header 2'), closeable: true, movable: true },
221+
{ id: uuid(), type: 'type-b', headerText$: of('Header 3'), closeable: true, movable: true },
222+
{ id: uuid(), type: 'type-b', headerText$: of('Header 4'), closeable: true, movable: true }
223223
];
224224
const toTabs: TabInfo<string>[] = [
225-
{ id: uuid(), type: 'type-c', headerText: 'Header 3', closeable: true, movable: true },
226-
{ id: uuid(), type: 'type-d', headerText: 'Header 4', closeable: true, movable: true }
225+
{ id: uuid(), type: 'type-c', headerText$: of('Header 3'), closeable: true, movable: true },
226+
{ id: uuid(), type: 'type-d', headerText$: of('Header 4'), closeable: true, movable: true }
227227
];
228228
const fromGroup = new TabGroup<string, any>(fromGroupId, fromTabs);
229229
const toGroup = new TabGroup<string, any>(toGroupId, toTabs);
@@ -251,17 +251,17 @@ describe('TabStateService', () => {
251251

252252
beforeEach(() => {
253253
sourceTabs = [
254-
{ id: uuid(), type: 'type-a', headerText: 'Source Header 1', closeable: true, movable: true },
255-
{ id: uuid(), type: 'type-b', headerText: 'Source Header 2', closeable: true, movable: true },
256-
{ id: uuid(), type: 'type-b', headerText: 'Source Header 3', closeable: true, movable: true },
257-
{ id: uuid(), type: 'type-b', headerText: 'Source Header 4', closeable: true, movable: true }
254+
{ id: uuid(), type: 'type-a', headerText$: of('Source Header 1'), closeable: true, movable: true },
255+
{ id: uuid(), type: 'type-b', headerText$: of('Source Header 2'), closeable: true, movable: true },
256+
{ id: uuid(), type: 'type-b', headerText$: of('Source Header 3'), closeable: true, movable: true },
257+
{ id: uuid(), type: 'type-b', headerText$: of('Source Header 4'), closeable: true, movable: true }
258258
];
259259

260260
targetTabs = [
261-
{ id: uuid(), type: 'type-a', headerText: 'Target Header 1', closeable: true, movable: true },
262-
{ id: uuid(), type: 'type-b', headerText: 'Target Header 2', closeable: true, movable: true },
263-
{ id: uuid(), type: 'type-b', headerText: 'Target Header 3', closeable: true, movable: true },
264-
{ id: uuid(), type: 'type-b', headerText: 'Target Header 4', closeable: true, movable: true }
261+
{ id: uuid(), type: 'type-a', headerText$: of('Target Header 1'), closeable: true, movable: true },
262+
{ id: uuid(), type: 'type-b', headerText$: of('Target Header 2'), closeable: true, movable: true },
263+
{ id: uuid(), type: 'type-b', headerText$: of('Target Header 3'), closeable: true, movable: true },
264+
{ id: uuid(), type: 'type-b', headerText$: of('Target Header 4'), closeable: true, movable: true }
265265
];
266266

267267
service['groups'].set('source', new TabGroup<string, any>('source', sourceTabs));
@@ -295,8 +295,20 @@ describe('TabStateService', () => {
295295

296296
it('should add tabs to restore list and consolidated group when tabs are added after consolidation and before deconsolidation', () => {
297297
const tabsToAdd: TabInfo<string>[] = [
298-
{ id: uuid(), type: 'type-c', headerText: 'added source Source Header 5', closeable: true, movable: true },
299-
{ id: uuid(), type: 'type-c', headerText: 'added source Source Header 6', closeable: true, movable: true }
298+
{
299+
id: uuid(),
300+
type: 'type-c',
301+
headerText$: of('added source Source Header 5'),
302+
closeable: true,
303+
movable: true
304+
},
305+
{
306+
id: uuid(),
307+
type: 'type-c',
308+
headerText$: of('added source Source Header 6'),
309+
closeable: true,
310+
movable: true
311+
}
300312
];
301313

302314
service.consolidateTabGroups('target');
@@ -313,7 +325,7 @@ describe('TabStateService', () => {
313325
const tabToAdd: TabInfo<string> = {
314326
id: uuid(),
315327
type: 'type-c',
316-
headerText: 'added source Source Header 5',
328+
headerText$: of('added source Source Header 5'),
317329
closeable: true,
318330
movable: true
319331
};

src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-state/tab-state.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type FlatTabInfo<TGroupId extends string, T extends TabInfo<string>> = T
1313
export interface TabInfo<TType extends string> {
1414
id: string;
1515
type: TType;
16-
headerText: string;
16+
headerText$: Observable<string>;
1717

1818
/** Optional text to display on hover of the tab header. */
1919
tooltip?: string;

src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
} @else if (tab.icon) {
6969
<mat-icon>{{ tab.icon }}</mat-icon>
7070
}
71-
{{ tab.headerText }}
71+
{{ tab.headerText$ | async }}
7272
</ng-template>
7373
@switch (tab.type) {
7474
@case ("biblical-terms") {

src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3878,7 +3878,7 @@ describe('EditorComponent', () => {
38783878
env.wait();
38793879
expect(spyCreateTab).toHaveBeenCalledWith('project-source', {
38803880
projectId: projectDoc.data?.translateConfig.source?.projectRef,
3881-
headerText: projectDoc.data?.translateConfig.source?.shortName,
3881+
headerText$: jasmine.any(Object),
38823882
tooltip: projectDoc.data?.translateConfig.source?.name
38833883
});
38843884
discardPeriodicTasks();
@@ -3892,7 +3892,7 @@ describe('EditorComponent', () => {
38923892
env.wait();
38933893
expect(spyCreateTab).not.toHaveBeenCalledWith('project-source', {
38943894
projectId: projectDoc.data?.translateConfig.source?.projectRef,
3895-
headerText: projectDoc.data?.translateConfig.source?.shortName,
3895+
headerText$: jasmine.any(Object),
38963896
tooltip: projectDoc.data?.translateConfig.source?.name
38973897
});
38983898
discardPeriodicTasks();
@@ -3915,7 +3915,7 @@ describe('EditorComponent', () => {
39153915
env.wait();
39163916
expect(spyCreateTab).toHaveBeenCalledWith('project-target', {
39173917
projectId: projectDoc.id,
3918-
headerText: projectDoc.data?.shortName,
3918+
headerText$: jasmine.any(Object),
39193919
tooltip: projectDoc.data?.name
39203920
});
39213921
discardPeriodicTasks();
@@ -4066,11 +4066,11 @@ describe('EditorComponent', () => {
40664066
env.dispose();
40674067
}));
40684068

4069-
it('should not add draft tab if draft exists and draft tab is already present', fakeAsync(async () => {
4069+
it('should not add draft tab if draft exists and draft tab is already present', fakeAsync(() => {
40704070
const env = new TestEnvironment();
40714071
env.wait();
40724072

4073-
env.component.tabState.addTab('target', await env.tabFactory.createTab('draft'));
4073+
env.component.tabState.addTab('target', env.tabFactory.createTab('draft'));
40744074
const addTab = spyOn(env.component.tabState, 'addTab');
40754075

40764076
env.routeWithParams({ projectId: 'project01', bookId: 'LUK', chapter: '1' });

0 commit comments

Comments
 (0)