mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-01 21:13:09 +00:00
Feature/shared refactor (#1176)
* refactor: move most of the shared entities to @start8labs/shared library
This commit is contained in:
@@ -6,11 +6,7 @@ import {
|
||||
renderPkgStatus,
|
||||
StatusRendering,
|
||||
} from '../services/pkg-status-rendering.service'
|
||||
import { isEmptyObject } from './misc.util'
|
||||
import {
|
||||
packageLoadingProgress,
|
||||
ProgressData,
|
||||
} from './package-loading-progress'
|
||||
import { packageLoadingProgress, ProgressData } from '@start9labs/shared'
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
export function getPackageInfo(entry: PackageDataEntry): PkgInfo {
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
import { OperatorFunction } from 'rxjs'
|
||||
import { map } from 'rxjs/operators'
|
||||
|
||||
export type Omit<ObjectType, KeysType extends keyof ObjectType> = Pick<ObjectType, Exclude<keyof ObjectType, KeysType>>
|
||||
export type PromiseRes<T> = { result: 'resolve', value: T } | { result: 'reject', value: Error }
|
||||
|
||||
export interface MappedBackupTarget<T> {
|
||||
id: string
|
||||
hasValidBackup: boolean
|
||||
entry: T
|
||||
}
|
||||
|
||||
export interface DependentInfo {
|
||||
id: string
|
||||
title: string
|
||||
version?: string
|
||||
}
|
||||
|
||||
export function trace<T> (t: T): T {
|
||||
console.log(`TRACE`, t)
|
||||
return t
|
||||
}
|
||||
|
||||
// curried description. This allows e.g somePromise.thentraceDesc('my result'))
|
||||
export function traceDesc<T> (description: string): (t: T) => T {
|
||||
return t => {
|
||||
console.log(`TRACE`, description, t)
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
// for use in observables. This allows e.g. someObservable.pipe(traceM('my result'))
|
||||
// the practical equivalent of `tap(t => console.log(t, description))`
|
||||
export function traceWheel<T> (description?: string): OperatorFunction<T, T> {
|
||||
return description ? map(traceDesc(description)) : map(trace)
|
||||
}
|
||||
|
||||
export function traceThrowDesc<T> (description: string, t: T | undefined): T {
|
||||
if (!t) throw new Error(description)
|
||||
return t
|
||||
}
|
||||
|
||||
export function thenReturn<T> (act1 : () => Promise<any>, t: T): Promise<T> {
|
||||
return act1().then(() => t)
|
||||
}
|
||||
|
||||
export function modulateTime (ts: Date, count: number, unit: 'days' | 'hours' | 'minutes' | 'seconds' ) {
|
||||
const ms = inMs(count, unit)
|
||||
const toReturn = new Date(ts)
|
||||
toReturn.setMilliseconds( toReturn.getMilliseconds() + ms)
|
||||
return toReturn
|
||||
}
|
||||
|
||||
export function inMs ( count: number, unit: 'days' | 'hours' | 'minutes' | 'seconds' ) {
|
||||
switch (unit){
|
||||
case 'seconds' : return count * 1000
|
||||
case 'minutes' : return inMs(count * 60, 'seconds')
|
||||
case 'hours' : return inMs(count * 60, 'minutes')
|
||||
case 'days' : return inMs(count * 24, 'hours')
|
||||
}
|
||||
}
|
||||
|
||||
export async function tryAll<T1, T2> ( promises: [Promise<T1>, Promise<T2>]): Promise<[PromiseRes<T1>, PromiseRes<T2>]>
|
||||
export async function tryAll ( promises: Promise<any>[] ): Promise<PromiseRes<any>[]> {
|
||||
return Promise.all(promises.map(
|
||||
p => p
|
||||
.then (r => ({ result: 'resolve' as 'resolve', value: r }))
|
||||
.catch(e => ({ result: 'reject' as 'reject', value: e })),
|
||||
))
|
||||
}
|
||||
|
||||
// arr1 - arr2
|
||||
export function diff<T> (arr1: T[], arr2: T[]): T[] {
|
||||
return arr1.filter(x => !arr2.includes(x))
|
||||
}
|
||||
|
||||
// arr1 & arr2
|
||||
export function both<T> (arr1: T[], arr2: T[]): T[] {
|
||||
return arr1.filter(x => arr2.includes(x))
|
||||
}
|
||||
|
||||
export async function doForAtLeast (promises: Promise<any>[], minTime: number): Promise<any[]> {
|
||||
const returned = await Promise.all(promises.concat(pauseFor(minTime)))
|
||||
returned.pop()
|
||||
return returned
|
||||
}
|
||||
|
||||
export function isObject (val: any): boolean {
|
||||
return val && typeof val === 'object' && !Array.isArray(val)
|
||||
}
|
||||
|
||||
export function isEmptyObject (obj: object): boolean {
|
||||
if (obj === undefined) return true
|
||||
return !Object.keys(obj).length
|
||||
}
|
||||
|
||||
export function pauseFor (ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
export type Valued<T> = { [s: string]: T }
|
||||
|
||||
export function toObject<T> (t: T[], map: (t0: T) => string): Valued<T> {
|
||||
return t.reduce( (acc, next) => {
|
||||
acc[map(next)] = next
|
||||
return acc
|
||||
}, { } as Valued<T>)
|
||||
}
|
||||
|
||||
export function toDedupObject<T> (t: T[], t2: T[], map: (t0: T) => string): Valued<T> {
|
||||
return toObject(t.concat(t2), map)
|
||||
}
|
||||
|
||||
export function update<T> (t: Valued<T>, u: Valued<T>): Valued<T> {
|
||||
return { ...t, ...u}
|
||||
}
|
||||
|
||||
export function fromObject<T> (o : Valued<T>): T[] {
|
||||
return Object.values(o)
|
||||
}
|
||||
|
||||
export function deepCloneUnknown<T> (value: T): T {
|
||||
if (typeof value !== 'object' || value === null) {
|
||||
return value
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return deepCloneArray(value)
|
||||
}
|
||||
return deepCloneObject(value)
|
||||
}
|
||||
|
||||
export function deepCloneObject<T> (source: T) {
|
||||
const result = { }
|
||||
Object.keys(source).forEach(key => {
|
||||
const value = source[key]
|
||||
result[key] = deepCloneUnknown(value)
|
||||
}, { })
|
||||
return result as T
|
||||
}
|
||||
|
||||
export function deepCloneArray (collection: any) {
|
||||
return collection.map(value => {
|
||||
return deepCloneUnknown(value)
|
||||
})
|
||||
}
|
||||
|
||||
export function partitionArray<T> (ts: T[], condition: (t: T) => boolean): [T[], T[]] {
|
||||
const yes = [] as T[]
|
||||
const no = [] as T[]
|
||||
ts.forEach(t => {
|
||||
if (condition(t)) {
|
||||
yes.push(t)
|
||||
} else {
|
||||
no.push(t)
|
||||
}
|
||||
})
|
||||
return [yes, no]
|
||||
}
|
||||
|
||||
export function uniqueBy<T> (ts: T[], uniqueBy: (t: T) => string, prioritize: (t1: T, t2: T) => T) {
|
||||
return Object.values(ts.reduce((acc, next) => {
|
||||
const previousValue = acc[uniqueBy(next)]
|
||||
if (previousValue) {
|
||||
acc[uniqueBy(next)] = prioritize(acc[uniqueBy(next)], previousValue)
|
||||
} else {
|
||||
acc[uniqueBy(next)] = previousValue
|
||||
}
|
||||
return acc
|
||||
}, { }))
|
||||
}
|
||||
|
||||
export function capitalizeFirstLetter (string: string): string {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1)
|
||||
}
|
||||
|
||||
export const exists = (t: any) => {
|
||||
return t !== undefined
|
||||
}
|
||||
|
||||
export type DeepPartial<T> = {
|
||||
[k in keyof T]?: DeepPartial<T[k]>
|
||||
}
|
||||
|
||||
export function debounce (delay: number = 300): MethodDecorator {
|
||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||
const timeoutKey = Symbol()
|
||||
|
||||
const original = descriptor.value
|
||||
|
||||
descriptor.value = function (...args) {
|
||||
clearTimeout(this[timeoutKey])
|
||||
this[timeoutKey] = setTimeout(() => original.apply(this, args), delay)
|
||||
}
|
||||
|
||||
return descriptor
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import { InstallProgress } from 'src/app/services/patch-db/data-model'
|
||||
import { isEmptyObject } from './misc.util'
|
||||
|
||||
export function packageLoadingProgress(
|
||||
loadData: InstallProgress,
|
||||
): ProgressData | null {
|
||||
if (isEmptyObject(loadData)) {
|
||||
return null
|
||||
}
|
||||
|
||||
let {
|
||||
downloaded,
|
||||
validated,
|
||||
unpacked,
|
||||
size,
|
||||
'download-complete': downloadComplete,
|
||||
'validation-complete': validationComplete,
|
||||
'unpack-complete': unpackComplete,
|
||||
} = loadData
|
||||
|
||||
// only permit 100% when "complete" == true
|
||||
downloaded = downloadComplete ? size : Math.max(downloaded - 1, 0)
|
||||
validated = validationComplete ? size : Math.max(validated - 1, 0)
|
||||
unpacked = unpackComplete ? size : Math.max(unpacked - 1, 0)
|
||||
|
||||
const downloadWeight = 1
|
||||
const validateWeight = 0.2
|
||||
const unpackWeight = 0.7
|
||||
|
||||
const numerator = Math.floor(
|
||||
downloadWeight * downloaded +
|
||||
validateWeight * validated +
|
||||
unpackWeight * unpacked,
|
||||
)
|
||||
|
||||
const denominator = Math.floor(
|
||||
size * (downloadWeight + validateWeight + unpackWeight),
|
||||
)
|
||||
const totalProgress = Math.floor((100 * numerator) / denominator)
|
||||
|
||||
return {
|
||||
totalProgress,
|
||||
downloadProgress: Math.floor((100 * downloaded) / size),
|
||||
validateProgress: Math.floor((100 * validated) / size),
|
||||
unpackProgress: Math.floor((100 * unpacked) / size),
|
||||
isComplete: downloadComplete && validationComplete && unpackComplete,
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProgressData {
|
||||
totalProgress: number
|
||||
downloadProgress: number
|
||||
validateProgress: number
|
||||
unpackProgress: number
|
||||
isComplete: boolean
|
||||
}
|
||||
@@ -2,11 +2,11 @@ import {
|
||||
DataModel,
|
||||
PackageDataEntry,
|
||||
RecoveredPackageDataEntry,
|
||||
} from '../services/patch-db/data-model'
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
|
||||
export function parseDataModel (data: DataModel): ParsedData {
|
||||
export function parseDataModel(data: DataModel): ParsedData {
|
||||
const all = JSON.parse(JSON.stringify(data['package-data'])) as {
|
||||
[id: string]: PackageDataEntry;
|
||||
[id: string]: PackageDataEntry
|
||||
}
|
||||
|
||||
const order = [...(data.ui['pkg-order'] || [])]
|
||||
@@ -19,7 +19,7 @@ export function parseDataModel (data: DataModel): ParsedData {
|
||||
}))
|
||||
|
||||
// add known packages in preferential order
|
||||
order.forEach((id) => {
|
||||
order.forEach(id => {
|
||||
if (all[id]) {
|
||||
pkgs.push(all[id])
|
||||
|
||||
@@ -28,7 +28,7 @@ export function parseDataModel (data: DataModel): ParsedData {
|
||||
})
|
||||
|
||||
// unshift unknown packages
|
||||
Object.values(all).forEach((pkg) => {
|
||||
Object.values(all).forEach(pkg => {
|
||||
pkgs.unshift(pkg)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user