Desktop D3 UI: studios and store accounts (health checks with fixes, import apps), one card per app across studios (automatic iOS / Android pairing, manual pair / unpair, links, studio moves), store-only apps read-only, ignore list, portfolio search / studio filter / sort / grouping, collapsible studio sidebar, complete Settings, notifications, fixtures with 3 studios and 5 accounts
This commit is contained in:
parent
e058d09683
commit
7b2cc8da0a
24 changed files with 2225 additions and 312 deletions
66
apps/desktop/src/screens/Ignored.tsx
Normal file
66
apps/desktop/src/screens/Ignored.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// Ignored: apps and whole store accounts left out of the portfolio, the sidebar and store reads. Restore brings them
|
||||
// back (nothing on the stores changes either way).
|
||||
import { t } from '../i18n';
|
||||
import { withIgnored } from '../lib/identity';
|
||||
import { useNav } from '../nav';
|
||||
import { useData } from '../store';
|
||||
import { Icon, StoreGlyph } from '../ui/icons';
|
||||
import { AppIcon, Card, Empty, StoreOnlyTag, StudioMark } from '../ui/kit';
|
||||
|
||||
export function Ignored() {
|
||||
const d = useData();
|
||||
const nav = useNav();
|
||||
const apps = d.apps.filter(a => a.ignored).sort((a, b) => a.name.localeCompare(b.name));
|
||||
const accounts = d.accounts.filter(a => d.overrides.ignored.includes(`account:${a.id}`));
|
||||
const restoreAll = () => d.updateOverrides(o => ({ ...o, ignored: [] }));
|
||||
const empty = !apps.length && !accounts.length;
|
||||
return (
|
||||
<div className="page">
|
||||
<div className="ph">
|
||||
<div><h1>{t('nav.ignored')}</h1><p>{t('ignored.lead')}</p></div>
|
||||
{!empty && <div className="actions"><button className="btn" onClick={restoreAll}><Icon name="eye" />{t('ignored.restoreAll')}</button></div>}
|
||||
</div>
|
||||
{empty ? <Card pad={false}><Empty compact illo="shield" title={t('ignored.emptyTitle')}>{t('ignored.emptyText')}</Empty></Card> : (
|
||||
<>
|
||||
<Card title={t('ignored.apps')} icon="layers" sub={t('ignored.appsSub', { count: apps.length })} pad={false}>
|
||||
{apps.length ? (
|
||||
<div className="list">
|
||||
{apps.map(a => {
|
||||
const s = d.studios.find(x => x.id === a.studio) ?? null;
|
||||
return (
|
||||
<div className="li" key={a.key}>
|
||||
<AppIcon name={a.name} src={d.iconFor(a)} />
|
||||
<div className="li-main">
|
||||
<span className="li-title row" style={{ gap: 8 }}>{a.name}{!a.project && <StoreOnlyTag />}</span>
|
||||
<span className="li-sub row" style={{ gap: 8 }}>
|
||||
<StudioMark studio={s} size="sm" />{s?.name ?? t('studio.none')}
|
||||
{a.ios && <span className="row" style={{ gap: 4 }}><StoreGlyph store="ios" className="ic13" /><span className="mono-id">{a.ios.app.bundleId}</span></span>}
|
||||
{a.android && <span className="row" style={{ gap: 4 }}><StoreGlyph store="android" className="ic13" /><span className="mono-id">{a.android.app.id}</span></span>}
|
||||
</span>
|
||||
</div>
|
||||
<button className="btn btn-sm" onClick={() => d.updateOverrides(o => withIgnored(o, a.ignoreKeys, false))}><Icon name="eye" />{t('ignored.restore')}</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : <div className="card-body"><p className="small muted">{t('ignored.noApps')}</p></div>}
|
||||
</Card>
|
||||
<Card title={t('ignored.accounts')} icon="key" sub={t('ignored.accountsSub')} pad={false}>
|
||||
{accounts.length ? (
|
||||
<div className="list">
|
||||
{accounts.map(a => (
|
||||
<div className="li" key={a.id}>
|
||||
<span className="li-icon tone-bg-neutral"><StoreGlyph store={a.kind === 'play' ? 'android' : 'ios'} /></span>
|
||||
<div className="li-main"><span className="li-title">{a.label}</span><span className="li-sub">{a.kind === 'play' ? t('acct.kindPlay') : t('acct.kindApple')} · {t('ignored.accountApps', { count: d.storeApps[a.id]?.value.apps.length ?? 0 })}</span></div>
|
||||
<button className="btn btn-sm" onClick={() => d.updateOverrides(o => withIgnored(o, [`account:${a.id}`], false))}><Icon name="eye" />{t('ignored.restore')}</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : <div className="card-body"><p className="small muted">{t('ignored.noAccounts')}</p></div>}
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
<p className="small muted">{t('ignored.howTo')} <button className="link" onClick={() => nav.go({ screen: 'settings', section: 'pairing' })}>{t('ignored.toPairing')}</button></p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue