Files
clash-verge-rev/src/components/proxy/proxy-empty-state-model.ts
T
Tunglies 6e08a77a84 refactor(backend): specta ipc bindings (#8195)
* refactor(ipc): generate bindings with Specta

* fix(profile): project IPC inputs to consumed fields

* fix(events): remove unused refresh payloads

* fix(webdav): return only consumed backup metadata

* fix(network): trim unused interface metadata

* fix(sysinfo): return only displayed system fields

* chore(knip): check generated runtime exports

* fix(proxy): confirm runtime chain updates before UI changes

* fix(clipboard): propagate proxy environment copy failures

* refactor(dns): remove ignored runtime patch

* refactor(core): trim unused upgrade response fields

* refactor(ipc): avoid redundant response copies

* refactor(proxy): clarify automatic proxy query naming

* chore(tests): remove added IPC regression tests

* refactor(ipc): enforce typed command boundaries

* chore(contract): check generated bindings before push

* refactor(ipc): remove unused proxy liveness payloads
2026-10-12 06:16:05 +00:00

74 lines
1.9 KiB
TypeScript

export type ProxyEmptyStateReason =
| 'no-subscriptions'
| 'inactive-subscription'
| 'core-unavailable'
| 'no-proxy-info'
type ProfileSummary = {
current?: string | null
items?: Array<{
uid?: string | null
type?: string | null
}> | null
}
interface ProxyListStateInput {
mode: string
profiles?: ProfileSummary
isProfilesPending: boolean
isProxyViewPending: boolean
isRunningModePending: boolean
}
const isSubscriptionProfile = (item: { type?: string | null }): boolean =>
item.type === 'remote' || item.type === 'local'
/** Decides only pre-render states; the built list owns whether it has renderable content. */
export type ProxyListState =
| { kind: 'direct' }
| { kind: 'loading' }
| { kind: 'empty'; reason: ProxyEmptyStateReason }
| { kind: 'render' }
export const resolveProxyListState = ({
mode,
profiles,
isProfilesPending,
isProxyViewPending,
isRunningModePending,
}: ProxyListStateInput): ProxyListState => {
if (mode === 'direct') return { kind: 'direct' }
if (isProfilesPending || isProxyViewPending || isRunningModePending) {
return { kind: 'loading' }
}
if (profiles) {
const subscriptions = (profiles.items ?? []).filter(isSubscriptionProfile)
if (subscriptions.length === 0) {
return { kind: 'empty', reason: 'no-subscriptions' }
}
const hasActiveSubscription = subscriptions.some(
(item) => item.uid === profiles.current,
)
if (!hasActiveSubscription) {
return { kind: 'empty', reason: 'inactive-subscription' }
}
}
return { kind: 'render' }
}
/** Explains an empty list only after the renderer observes it. */
export const resolveEmptyListReason = ({
runningMode,
isProxyViewError,
}: {
runningMode?: string
isProxyViewError: boolean
}): ProxyEmptyStateReason =>
runningMode === 'NotRunning' || isProxyViewError
? 'core-unavailable'
: 'no-proxy-info'