Desktop: folders keep claiming their store records before the config read returns; a store app with a folder's id is never listed twice
This commit is contained in:
parent
5e82010ace
commit
7c769c18f4
3 changed files with 38 additions and 2 deletions
|
|
@ -224,11 +224,18 @@ export function DataProvider({ children }: { children: ReactNode }) {
|
|||
setStoreApps(Object.fromEntries((Array.isArray(s) ? s : []).filter(x => x && typeof x.account === 'string').map(x => [x.account, x.entry ?? null])));
|
||||
}, []);
|
||||
|
||||
// the last config summary seen per folder: a folder whose read has not come back yet (start) or failed this time keeps
|
||||
// claiming its store records, so its App Store / Play entries never show up a second time as store-only apps
|
||||
const lastSummary = useRef(new Map<string, NonNullable<PortfolioResult['apps'][number]['summary']>>());
|
||||
const apps = useMemo(() => buildApps({
|
||||
projects, accounts, overrides,
|
||||
summaryOf: p => portfolio?.apps.find(a => a.project === p.path)?.summary ?? liveRef.current?.value.apps.find(a => a.project === p.path)?.summary,
|
||||
summaryOf: p => {
|
||||
const fresh = portfolio?.apps.find(a => a.project === p.path)?.summary ?? live?.value.apps.find(a => a.project === p.path)?.summary;
|
||||
if (fresh) lastSummary.current.set(p.path, fresh);
|
||||
return fresh ?? lastSummary.current.get(p.path);
|
||||
},
|
||||
storeApps: Object.entries(storeApps).filter(([, e]) => !!e).map(([account, e]) => ({ account, apps: e!.value.apps })),
|
||||
}), [projects, accounts, overrides, portfolio, storeApps]);
|
||||
}), [projects, accounts, overrides, portfolio, live, storeApps]);
|
||||
const appsRef = useRef(apps);
|
||||
appsRef.current = apps;
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,21 @@ describe('identity pairing', () => {
|
|||
const apps2 = buildApps({ projects: [prism], accounts, storeApps: twin, overrides: NO_OVERRIDES, summaryOf: () => summary('com.example.prism', 'com.example.prism') });
|
||||
expect(apps2[0]!.ios?.account).toBe(A1);
|
||||
});
|
||||
test('a folder with a config summary claims its iOS and Android records; ignore flags do not break it', () => {
|
||||
for (const o of [NO_OVERRIDES, withIgnored(NO_OVERRIDES, ['project:p1:ios'], true), withIgnored(NO_OVERRIDES, ['project:p1:android'], true)]) {
|
||||
const apps = build(o);
|
||||
expect(apps.filter(a => a.ios?.app.bundleId === 'com.example.prism' || a.android?.app.id === 'com.example.prism').length).toBeLessThanOrEqual(1);
|
||||
expect(apps.filter(a => a.name === 'Prism' && !a.project)).toEqual([]);
|
||||
}
|
||||
});
|
||||
test('without a summary the folder claims nothing (the start-up race); a store app of a folder bundle id is never shown separately', () => {
|
||||
const none = buildApps({ projects: [prism], accounts, storeApps, overrides: NO_OVERRIDES, summaryOf: () => null });
|
||||
expect(none.filter(a => !a.project && a.name === 'Prism')).toHaveLength(1);
|
||||
// guard: the folder is linked to other records, its summary's ids still hide the duplicates
|
||||
const linked = { ...NO_OVERRIDES, links: [{ key: `ios:${A1}:102`, project: 'p1' }] };
|
||||
const apps = build(linked);
|
||||
expect(apps.filter(a => !a.project && (a.ios?.app.bundleId === 'com.example.prism' || a.android?.app.id === 'com.example.prism'))).toEqual([]);
|
||||
});
|
||||
test('unpair blocks the automatic pair; manual pair beats it', () => {
|
||||
const o1 = withUnpair(NO_OVERRIDES, `ios:${A1}:102`, `android:${P1}:com.example.orbit`);
|
||||
const apps1 = build(o1);
|
||||
|
|
|
|||
|
|
@ -134,6 +134,20 @@ export function buildApps<P extends IdProject>(i: BuildInput<P>): UnifiedApp<P>[
|
|||
});
|
||||
}
|
||||
|
||||
// guard: a store app with the same App Store id / bundle id / package name as a folder is that folder's record, never a
|
||||
// second entry (the folder could not take it above, e.g. it is linked elsewhere); it is dropped, not shown separately
|
||||
const folderIds = new Set<string>();
|
||||
for (const p of i.projects) {
|
||||
const s = i.summaryOf(p);
|
||||
if (s?.apple?.appId) folderIds.add(`ios:id:${s.apple.appId}`);
|
||||
if (s?.apple?.bundleId) folderIds.add(`ios:bundle:${s.apple.bundleId}`);
|
||||
if (s?.play?.packageName) folderIds.add(`android:${s.play.packageName}`);
|
||||
}
|
||||
for (const r of refs) {
|
||||
if (used.has(r.key)) continue;
|
||||
if (r.store === 'ios' ? folderIds.has(`ios:id:${r.app.id}`) || folderIds.has(`ios:bundle:${r.app.bundleId}`) : folderIds.has(`android:${r.app.id}`)) used.add(r.key);
|
||||
}
|
||||
|
||||
// 2. pairs among the remaining store apps
|
||||
const freeIos = () => refs.filter(r => r.store === 'ios' && !used.has(r.key));
|
||||
const freeAndroid = () => refs.filter(r => r.store === 'android' && !used.has(r.key));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue