strongly typed partial profiles wip

This commit is contained in:
Eugene Pankov
2021-07-13 23:44:23 +02:00
parent 5ddf36d4c1
commit 2f13f3a401
16 changed files with 118 additions and 107 deletions

View File

@@ -16,7 +16,7 @@ export { BootstrapData, PluginInfo, BOOTSTRAP_DATA } from './mainProcess'
export { HostWindowService } from './hostWindow'
export { HostAppService, Platform } from './hostApp'
export { FileProvider } from './fileProvider'
export { ProfileProvider, Profile, ProfileSettingsComponent } from './profileProvider'
export { ProfileProvider, Profile, PartialProfile, ProfileSettingsComponent } from './profileProvider'
export { PromptModalComponent } from '../components/promptModal.component'
export { AppService } from '../services/app.service'

View File

@@ -1,45 +1,56 @@
/* eslint-disable @typescript-eslint/no-type-alias */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-empty-function */
import { BaseTabComponent } from '../components/baseTab.component'
import { NewTabParameters } from '../services/tabs.service'
export interface Profile {
id?: string
id: string
type: string
name: string
group?: string
options: Record<string, any>
options: any
icon?: string
color?: string
disableDynamicTitle?: boolean
disableDynamicTitle: boolean
weight?: number
isBuiltin?: boolean
isTemplate?: boolean
weight: number
isBuiltin: boolean
isTemplate: boolean
}
export interface ProfileSettingsComponent {
profile: Profile
export type PartialProfile<T extends Profile> = Omit<Omit<Omit<{
[K in keyof T]?: T[K]
}, 'options'>, 'type'>, 'name'> & {
type: string
name: string
options?: {
[K in keyof T['options']]?: T['options'][K]
}
}
export interface ProfileSettingsComponent<P extends Profile> {
profile: P
save?: () => void
}
export abstract class ProfileProvider {
export abstract class ProfileProvider<P extends Profile> {
id: string
name: string
supportsQuickConnect = false
settingsComponent?: new (...args: any[]) => ProfileSettingsComponent
settingsComponent?: new (...args: any[]) => ProfileSettingsComponent<P>
configDefaults = {}
abstract getBuiltinProfiles (): Promise<Profile[]>
abstract getBuiltinProfiles (): Promise<PartialProfile<P>[]>
abstract getNewTabParameters (profile: Profile): Promise<NewTabParameters<BaseTabComponent>>
abstract getNewTabParameters (profile: PartialProfile<P>): Promise<NewTabParameters<BaseTabComponent>>
abstract getDescription (profile: Profile): string
abstract getDescription (profile: PartialProfile<P>): string
quickConnect (query: string): Profile|null {
quickConnect (query: string): PartialProfile<P>|null {
return null
}
deleteProfile (profile: Profile): void { }
deleteProfile (profile: P): void { }
}

View File

@@ -3,7 +3,7 @@ import { Injectable } from '@angular/core'
import { ToolbarButton, ToolbarButtonProvider } from './api/toolbarButtonProvider'
import { HostAppService, Platform } from './api/hostApp'
import { Profile } from './api/profileProvider'
import { PartialProfile, Profile } from './api/profileProvider'
import { ConfigService } from './services/config.service'
import { HotkeysService } from './services/hotkeys.service'
import { ProfilesService } from './services/profiles.service'
@@ -32,7 +32,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
}
}
async launchProfile (profile: Profile) {
async launchProfile (profile: PartialProfile<Profile>) {
await this.profilesService.openNewTabForProfile(profile)
let recentProfiles = this.config.store.recentProfiles

View File

@@ -1,7 +1,7 @@
import slugify from 'slugify'
import { v4 as uuidv4 } from 'uuid'
import { Injectable } from '@angular/core'
import { ConfigService, NewTabParameters, Profile, ProfileProvider } from './api'
import { ConfigService, NewTabParameters, PartialProfile, Profile, ProfileProvider } from './api'
import { SplitTabComponent, SplitTabRecoveryProvider } from './components/splitTab.component'
export interface SplitLayoutProfileOptions {
@@ -13,7 +13,7 @@ export interface SplitLayoutProfile extends Profile {
}
@Injectable({ providedIn: 'root' })
export class SplitLayoutProfilesService extends ProfileProvider {
export class SplitLayoutProfilesService extends ProfileProvider<SplitLayoutProfile> {
id = 'split-layout'
name = 'Saved layout'
configDefaults = {
@@ -29,7 +29,7 @@ export class SplitLayoutProfilesService extends ProfileProvider {
super()
}
async getBuiltinProfiles (): Promise<Profile[]> {
async getBuiltinProfiles (): Promise<PartialProfile<SplitLayoutProfile>[]> {
return []
}
@@ -43,7 +43,7 @@ export class SplitLayoutProfilesService extends ProfileProvider {
async createProfile (tab: SplitTabComponent, name: string): Promise<void> {
const token = await tab.getRecoveryToken()
const profile: SplitLayoutProfile = {
const profile: PartialProfile<SplitLayoutProfile> = {
id: `${this.id}:custom:${slugify(name)}:${uuidv4()}`,
type: this.id,
name,

View File

@@ -1,8 +1,8 @@
import { Injectable, Inject } from '@angular/core'
import { NewTabParameters } from './tabs.service'
import { BaseTabComponent } from '../components/baseTab.component'
import { Profile, ProfileProvider } from '../api/profileProvider'
import { SelectorOption } from '../api/selector'
import { PartialProfile, Profile, ProfileProvider } from '../api/profileProvider'
;import { SelectorOption } from '../api/selector'
import { AppService } from './app.service'
import { configMerge, ConfigProxy, ConfigService } from './config.service'
import { NotificationsService } from './notifications.service'
@@ -29,15 +29,18 @@ export class ProfilesService {
private config: ConfigService,
private notifications: NotificationsService,
private selector: SelectorService,
@Inject(ProfileProvider) private profileProviders: ProfileProvider[],
@Inject(ProfileProvider) private profileProviders: ProfileProvider<Profile>[],
) { }
async openNewTabForProfile (profile: Profile): Promise<BaseTabComponent|null> {
async openNewTabForProfile <P extends Profile> (profile: PartialProfile<P>): Promise<BaseTabComponent|null> {
const params = await this.newTabParametersForProfile(profile)
if (params) {
const tab = this.app.openNewTab(params)
;(this.app.getParentTab(tab) ?? tab).color = profile.color ?? null
tab.setTitle(profile.name)
if (profile.name) {
tab.setTitle(profile.name)
}
if (profile.disableDynamicTitle) {
tab['enableDynamicTitle'] = false
}
@@ -46,16 +49,16 @@ export class ProfilesService {
return null
}
async newTabParametersForProfile (profile: Profile): Promise<NewTabParameters<BaseTabComponent>|null> {
profile = this.getConfigProxyForProfile(profile)
return this.providerForProfile(profile)?.getNewTabParameters(profile) ?? null
async newTabParametersForProfile <P extends Profile> (profile: PartialProfile<P>): Promise<NewTabParameters<BaseTabComponent>|null> {
const fullProfile = this.getConfigProxyForProfile(profile)
return this.providerForProfile(fullProfile)?.getNewTabParameters(fullProfile) ?? null
}
getProviders (): ProfileProvider[] {
getProviders (): ProfileProvider<Profile>[] {
return [...this.profileProviders]
}
async getProfiles (): Promise<Profile[]> {
async getProfiles (): Promise<PartialProfile<Profile>[]> {
const lists = await Promise.all(this.config.enabledServices(this.profileProviders).map(x => x.getBuiltinProfiles()))
let list = lists.reduce((a, b) => a.concat(b), [])
list = [
@@ -68,28 +71,29 @@ export class ProfilesService {
return list
}
providerForProfile (profile: Profile): ProfileProvider|null {
return this.profileProviders.find(x => x.id === profile.type) ?? null
providerForProfile <T extends Profile> (profile: PartialProfile<T>): ProfileProvider<T>|null {
const provider = this.profileProviders.find(x => x.id === profile.type) ?? null
return provider as unknown as ProfileProvider<T>|null
}
getDescription (profile: Profile): string|null {
getDescription <P extends Profile> (profile: PartialProfile<P>): string|null {
profile = this.getConfigProxyForProfile(profile)
return this.providerForProfile(profile)?.getDescription(profile) ?? null
}
selectorOptionForProfile <T> (profile: Profile): SelectorOption<T> {
profile = this.getConfigProxyForProfile(profile)
selectorOptionForProfile <P extends Profile, T> (profile: PartialProfile<P>): SelectorOption<T> {
const fullProfile = this.getConfigProxyForProfile(profile)
return {
icon: profile.icon,
name: profile.group ? `${profile.group} / ${profile.name}` : profile.name,
description: this.providerForProfile(profile)?.getDescription(profile),
name: profile.group ? `${fullProfile.group} / ${fullProfile.name}` : fullProfile.name,
description: this.providerForProfile(fullProfile)?.getDescription(fullProfile),
}
}
showProfileSelector (): Promise<Profile|null> {
return new Promise<Profile|null>(async (resolve, reject) => {
showProfileSelector (): Promise<PartialProfile<Profile>|null> {
return new Promise<PartialProfile<Profile>|null>(async (resolve, reject) => {
try {
const recentProfiles: Profile[] = this.config.store.recentProfiles
const recentProfiles: PartialProfile<Profile>[] = this.config.store.recentProfiles
let options: SelectorOption<void>[] = recentProfiles.map(p => ({
...this.selectorOptionForProfile(p),
@@ -159,7 +163,7 @@ export class ProfilesService {
})
}
async quickConnect (query: string): Promise<Profile|null> {
async quickConnect (query: string): Promise<PartialProfile<Profile>|null> {
for (const provider of this.getProviders()) {
if (provider.supportsQuickConnect) {
const profile = provider.quickConnect(query)
@@ -172,9 +176,9 @@ export class ProfilesService {
return null
}
getConfigProxyForProfile (profile: Profile): Profile {
getConfigProxyForProfile <T extends Profile> (profile: PartialProfile<T>): T {
const provider = this.providerForProfile(profile)
const defaults = configMerge(this.profileDefaults, provider?.configDefaults ?? {})
return new ConfigProxy(profile, defaults) as unknown as Profile
return new ConfigProxy(profile, defaults) as unknown as T
}
}