feat: publish HoloLake model-native living system source
This commit is contained in:
parent
6ad10edde1
commit
c395dd3a99
2467 changed files with 615073 additions and 0 deletions
170
product-source/hololake-platform/src/utils/pulledVaultRefresh.ts
Normal file
170
product-source/hololake-platform/src/utils/pulledVaultRefresh.ts
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
import type { VaultEntry } from '../types'
|
||||
import { findByNotePath, joinVaultPath, normalizeNotePathForIdentity, notePathsMatch } from './notePathIdentity'
|
||||
|
||||
interface PulledVaultRefreshOptions {
|
||||
activeTabPath: string | null
|
||||
getActiveTabPath?: () => string | null
|
||||
closeAllTabs: () => void
|
||||
hasUnsavedChanges: (path: string) => boolean
|
||||
reloadFolders: () => Promise<unknown> | unknown
|
||||
reloadVault: () => Promise<VaultEntry[]>
|
||||
reloadViews: () => Promise<unknown> | unknown
|
||||
replaceActiveTab: (entry: VaultEntry) => Promise<void>
|
||||
refocusActiveEditor?: (path: string) => void
|
||||
shouldRefocusActiveEditor?: () => boolean
|
||||
updatedFiles: string[]
|
||||
vaultPath: string
|
||||
}
|
||||
|
||||
function resolveUpdatedFilePath(options: { path: string; vaultPath: string }): string {
|
||||
const { path, vaultPath } = options
|
||||
if (path.startsWith('/')) return normalizeNotePathForIdentity(path)
|
||||
return normalizeNotePathForIdentity(joinVaultPath(vaultPath, path))
|
||||
}
|
||||
|
||||
function didPullUpdateActiveNote(options: {
|
||||
updatedFiles: string[]
|
||||
vaultPath: string
|
||||
activeTabPath: string
|
||||
}): boolean {
|
||||
const { activeTabPath, updatedFiles, vaultPath } = options
|
||||
return updatedFiles.some((path) => notePathsMatch(resolveUpdatedFilePath({ path, vaultPath }), activeTabPath))
|
||||
}
|
||||
|
||||
function didActivePathChange(options: { initialPath: string; latestPath: string }): boolean {
|
||||
const { initialPath, latestPath } = options
|
||||
return !notePathsMatch(initialPath, latestPath)
|
||||
}
|
||||
|
||||
function findExternallyMovedActiveEntry(options: {
|
||||
activeTabPath: string
|
||||
entries: VaultEntry[]
|
||||
updatedFiles: string[]
|
||||
vaultPath: string
|
||||
}): VaultEntry | null {
|
||||
const { activeTabPath, entries, updatedFiles, vaultPath } = options
|
||||
if (updatedFiles.length === 0) return null
|
||||
const activeFilename = normalizeNotePathForIdentity(activeTabPath).split('/').pop()
|
||||
const updatedPaths = new Set(updatedFiles.map((path) => resolveUpdatedFilePath({ path, vaultPath })))
|
||||
const candidates = entries.filter((entry) =>
|
||||
!notePathsMatch(entry.path, activeTabPath)
|
||||
&& entry.filename === activeFilename
|
||||
&& updatedPaths.has(normalizeNotePathForIdentity(entry.path)),
|
||||
)
|
||||
|
||||
const [candidate] = candidates
|
||||
return candidates.length === 1 && candidate ? candidate : null
|
||||
}
|
||||
|
||||
function isActivePathBlocked(options: {
|
||||
activeTabPath: string | null
|
||||
latestActiveTabPath: string | null
|
||||
hasUnsavedChanges: PulledVaultRefreshOptions['hasUnsavedChanges']
|
||||
}): boolean {
|
||||
const { activeTabPath, latestActiveTabPath, hasUnsavedChanges } = options
|
||||
if (!activeTabPath) return true
|
||||
if (!latestActiveTabPath) return true
|
||||
if (didActivePathChange({ initialPath: activeTabPath, latestPath: latestActiveTabPath })) return true
|
||||
return hasUnsavedChanges(latestActiveTabPath)
|
||||
}
|
||||
|
||||
function shouldReplaceActiveEntry(options: {
|
||||
activePath: string
|
||||
movedEntry: VaultEntry | null
|
||||
refreshedEntry: VaultEntry | null
|
||||
updatedFiles: string[]
|
||||
vaultPath: string
|
||||
}): boolean {
|
||||
const {
|
||||
activePath,
|
||||
movedEntry,
|
||||
refreshedEntry,
|
||||
updatedFiles,
|
||||
vaultPath,
|
||||
} = options
|
||||
if (movedEntry) return true
|
||||
if (!refreshedEntry) return false
|
||||
return didPullUpdateActiveNote({ updatedFiles, vaultPath, activeTabPath: activePath })
|
||||
}
|
||||
|
||||
async function applyActiveEntryReplacement(options: {
|
||||
closeAllTabs: PulledVaultRefreshOptions['closeAllTabs']
|
||||
replaceActiveTab: PulledVaultRefreshOptions['replaceActiveTab']
|
||||
refocusActiveEditor?: PulledVaultRefreshOptions['refocusActiveEditor']
|
||||
replacementEntry: VaultEntry | null
|
||||
shouldRefocusActiveEditor?: PulledVaultRefreshOptions['shouldRefocusActiveEditor']
|
||||
shouldReplace: boolean | null
|
||||
}): Promise<boolean> {
|
||||
const {
|
||||
closeAllTabs,
|
||||
replaceActiveTab,
|
||||
refocusActiveEditor,
|
||||
replacementEntry,
|
||||
shouldRefocusActiveEditor,
|
||||
shouldReplace,
|
||||
} = options
|
||||
if (!replacementEntry || !shouldReplace) return false
|
||||
|
||||
const shouldRefocus = shouldRefocusActiveEditor?.() === true
|
||||
closeAllTabs()
|
||||
await replaceActiveTab(replacementEntry)
|
||||
if (shouldRefocus) refocusActiveEditor?.(replacementEntry.path)
|
||||
return true
|
||||
}
|
||||
|
||||
export async function refreshPulledVaultState(options: PulledVaultRefreshOptions): Promise<VaultEntry[]> {
|
||||
const {
|
||||
activeTabPath,
|
||||
closeAllTabs,
|
||||
getActiveTabPath,
|
||||
hasUnsavedChanges,
|
||||
reloadFolders,
|
||||
reloadVault,
|
||||
reloadViews,
|
||||
replaceActiveTab,
|
||||
refocusActiveEditor,
|
||||
shouldRefocusActiveEditor,
|
||||
updatedFiles,
|
||||
vaultPath,
|
||||
} = options
|
||||
|
||||
const [entries] = await Promise.all([
|
||||
reloadVault(),
|
||||
Promise.resolve(reloadFolders()),
|
||||
Promise.resolve(reloadViews()),
|
||||
])
|
||||
|
||||
const latestActiveTabPath = getActiveTabPath?.() ?? activeTabPath
|
||||
if (isActivePathBlocked({ activeTabPath, latestActiveTabPath, hasUnsavedChanges })) return entries
|
||||
|
||||
const activePath = latestActiveTabPath as string
|
||||
const refreshedEntry = findByNotePath(entries, activePath) ?? null
|
||||
const movedEntry = refreshedEntry ? null : findExternallyMovedActiveEntry({
|
||||
activeTabPath: activePath,
|
||||
entries,
|
||||
updatedFiles,
|
||||
vaultPath,
|
||||
})
|
||||
const replacementEntry = refreshedEntry ?? movedEntry
|
||||
|
||||
const shouldReplace = replacementEntry && shouldReplaceActiveEntry({
|
||||
activePath,
|
||||
movedEntry,
|
||||
refreshedEntry,
|
||||
updatedFiles,
|
||||
vaultPath,
|
||||
})
|
||||
|
||||
const handledReplacement = await applyActiveEntryReplacement({
|
||||
closeAllTabs,
|
||||
replaceActiveTab,
|
||||
refocusActiveEditor,
|
||||
replacementEntry,
|
||||
shouldRefocusActiveEditor,
|
||||
shouldReplace,
|
||||
})
|
||||
if (handledReplacement) return entries
|
||||
|
||||
if (!replacementEntry) closeAllTabs()
|
||||
return entries
|
||||
}
|
||||
Loading…
Reference in a new issue