refactor: initial iterations

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
jamesgeorge007
2024-01-31 11:20:24 +05:30
parent f8ac6dfeb1
commit 29e25b0ead
24 changed files with 2197 additions and 514 deletions

View File

@@ -0,0 +1,5 @@
import { Ref } from "vue"
export type HandleRef<T, InvalidateReason = unknown> = Ref<
{ type: "ok"; data: T } | { type: "invalid"; reason: InvalidateReason }
>

View File

@@ -0,0 +1,276 @@
import { Service } from "dioc"
import {
Component,
Ref,
computed,
markRaw,
shallowReactive,
shallowRef,
watch,
} from "vue"
import { WorkspaceProvider } from "./provider"
import { HandleRef } from "./handle"
import * as E from "fp-ts/Either"
import { Workspace, WorkspaceCollection } from "./workspace"
import { RESTCollectionChildrenView, RootRESTCollectionView } from "./view"
export type WorkspaceError<ServiceErr> =
| { type: "SERVICE_ERROR"; error: ServiceErr }
| { type: "PROVIDER_ERROR"; error: unknown }
export class NewWorkspaceService extends Service {
public static readonly ID = "NEW_WORKSPACE_SERVICE"
private registeredProviders = shallowReactive(
new Map<string, WorkspaceProvider>()
)
public activeWorkspaceHandle: Ref<HandleRef<Workspace> | undefined> =
shallowRef()
public activeWorkspaceDecor = computed(() => {
if (this.activeWorkspaceHandle.value?.value.type !== "ok") {
return undefined
}
return this.registeredProviders.get(
this.activeWorkspaceHandle.value.value.data.providerID
)!.workspaceDecor
})
public workspaceSelectorComponents = computed(() => {
const items: Component[] = []
const sortedProviders = Array.from(this.registeredProviders.values()).sort(
(a, b) =>
(b.workspaceDecor?.value.workspaceSelectorPriority ?? 0) -
(a.workspaceDecor?.value.workspaceSelectorPriority ?? 0)
)
for (const workspace of sortedProviders) {
if (workspace.workspaceDecor?.value?.workspaceSelectorComponent) {
items.push(workspace.workspaceDecor.value.workspaceSelectorComponent)
}
}
return items
})
constructor() {
super()
// Watch for situations where the handle is invalidated
// so the active workspace handle definition can be invalidated
watch(
() => {
return this.activeWorkspaceHandle.value
? [
this.activeWorkspaceHandle.value,
this.activeWorkspaceHandle.value.value,
]
: [this.activeWorkspaceHandle.value]
},
() => {
if (!this.activeWorkspaceHandle.value) return
if (this.activeWorkspaceHandle.value.value.type === "invalid") {
this.activeWorkspaceHandle.value = undefined
}
},
{ deep: true }
)
}
public async getWorkspaceHandle(
providerID: string,
workspaceID: string
): Promise<
E.Either<WorkspaceError<"INVALID_PROVIDER">, HandleRef<Workspace>>
> {
const provider = this.registeredProviders.get(providerID)
if (!provider) {
return Promise.resolve(
E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" as const })
)
}
const handleResult = await provider.getWorkspaceHandle(workspaceID)
if (E.isLeft(handleResult)) {
return E.left({ type: "PROVIDER_ERROR", error: handleResult.left })
}
return E.right(handleResult.right)
}
public async getCollectionHandle(
workspaceHandle: HandleRef<Workspace>,
collectionID: string
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (workspaceHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
workspaceHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.getCollectionHandle(
workspaceHandle,
collectionID
)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async createRESTRootCollection(
workspaceHandle: HandleRef<Workspace>,
collectionName: string
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (workspaceHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
workspaceHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.createRESTRootCollection(
workspaceHandle,
collectionName
)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async createRESTChildCollection(
parentCollHandle: HandleRef<WorkspaceCollection>,
collectionName: string
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (parentCollHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
parentCollHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.createRESTChildCollection(
parentCollHandle,
collectionName
)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async getRESTCollectionChildrenView(
collectionHandle: HandleRef<WorkspaceCollection>
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<RESTCollectionChildrenView>
>
> {
if (collectionHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
collectionHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result =
await provider.getRESTCollectionChildrenView(collectionHandle)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async getRESTRootCollectionView(
workspaceHandle: HandleRef<Workspace>
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<RootRESTCollectionView>
>
> {
if (workspaceHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
workspaceHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.getRESTRootCollectionView(workspaceHandle)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public registerWorkspaceProvider(provider: WorkspaceProvider) {
if (this.registeredProviders.has(provider.providerID)) {
console.warn(
"Ignoring attempt to re-register workspace provider that is already existing:",
provider
)
return
}
this.registeredProviders.set(provider.providerID, markRaw(provider))
}
}

View File

@@ -0,0 +1,35 @@
import { Ref } from "vue"
import * as E from "fp-ts/Either"
import { HandleRef } from "./handle"
import { Workspace, WorkspaceCollection, WorkspaceDecor } from "./workspace"
import { RESTCollectionChildrenView, RootRESTCollectionView } from "./view"
export interface WorkspaceProvider {
providerID: string
workspaceDecor?: Ref<WorkspaceDecor>
getWorkspaceHandle(
workspaceID: string
): Promise<E.Either<unknown, HandleRef<Workspace>>>
getCollectionHandle(
workspaceHandle: HandleRef<Workspace>,
collectionID: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
getRESTRootCollectionView(
workspaceHandle: HandleRef<Workspace>
): Promise<E.Either<unknown, HandleRef<RootRESTCollectionView>>>
getRESTCollectionChildrenView(
collectionHandle: HandleRef<WorkspaceCollection>
): Promise<E.Either<unknown, HandleRef<RESTCollectionChildrenView>>>
createRESTRootCollection(
workspaceHandle: HandleRef<Workspace>,
collectionName: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
createRESTChildCollection(
parentCollHandle: HandleRef<WorkspaceCollection>,
collectionName: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
}

View File

@@ -0,0 +1,400 @@
import {
HoppCollection,
HoppRESTRequest,
makeCollection,
} from "@hoppscotch/data"
import { Service } from "dioc"
import * as E from "fp-ts/Either"
import { get } from "lodash-es"
import { v4 as uuid } from "uuid"
import { Ref, computed, markRaw, ref, shallowReactive, shallowRef } from "vue"
import PersonalWorkspaceSelector from "~/components/workspace/PersonalWorkspaceSelector.vue"
import { useStreamStatic } from "~/composables/stream"
import { addRESTCollection, restCollectionStore } from "~/newstore/collections"
import { platform } from "~/platform"
import { HandleRef } from "~/services/new-workspace/handle"
import { WorkspaceProvider } from "~/services/new-workspace/provider"
import {
RESTCollectionChildrenView,
RESTCollectionViewItem,
RootRESTCollectionView,
} from "~/services/new-workspace/view"
import {
Workspace,
WorkspaceCollection,
WorkspaceDecor,
} from "~/services/new-workspace/workspace"
import IconUser from "~icons/lucide/user"
import { NewWorkspaceService } from ".."
export class PersonalWorkspaceProviderService
extends Service
implements WorkspaceProvider
{
public static readonly ID = "PERSONAL_WORKSPACE_PROVIDER_SERVICE"
public readonly providerID = "PERSONAL_WORKSPACE_PROVIDER"
private workspaceService = this.bind(NewWorkspaceService)
public workspaceDecor: Ref<WorkspaceDecor> = ref({
headerCurrentIcon: IconUser,
workspaceSelectorComponent: PersonalWorkspaceSelector,
workspaceSelectorPriority: 100,
})
private restCollectionState: Ref<{ state: HoppCollection[] }>
public constructor() {
super()
this.restCollectionState = useStreamStatic(
restCollectionStore.subject$,
{ state: [] },
() => {
/* noop */
}
)[0]
this.workspaceService.registerWorkspaceProvider(this)
}
private collectionIDMap = shallowReactive(
new WeakMap<HoppCollection, string>()
)
private reqIDMap = shallowReactive(new WeakMap<HoppRESTRequest, string>())
private collectionIDPathMap = shallowReactive(new Map<string, number[]>())
private generatedUUIDs = new Set<string>()
private generateUniqueUUID() {
let id = uuid()
while (this.generatedUUIDs.has(id)) {
id = uuid()
}
this.generatedUUIDs.add(id)
return id
}
private resolvePathFromCollectionID(id: string): number[] | undefined {
return this.collectionIDPathMap.get(id)
}
private resolveCollectionFromCollectionID(
id: string
): HoppCollection | undefined {
const path = this.resolvePathFromCollectionID(id)
if (path === undefined) return
const collPath = path.flatMap((x, i) =>
i === 0 ? [x.toString()] : ["folders", x.toString()]
)
const coll = get(this.restCollectionState.value.state, collPath) as
| HoppCollection
| undefined
return coll
}
private getIssuedInstanceIDForCollection(
coll: HoppCollection,
location: number[]
) {
const id = this.collectionIDMap.has(coll)
? this.collectionIDMap.get(coll)!
: this.generateUniqueUUID()
this.collectionIDPathMap.set(id, location)
this.collectionIDMap.set(coll, id)
return id
}
private getIssuedInstanceIDForRequest(req: HoppRESTRequest) {
const id = this.reqIDMap.get(req) ?? this.generateUniqueUUID()
this.reqIDMap.set(req, id)
return id
}
public createRESTChildCollection(
parentCollHandle: HandleRef<WorkspaceCollection>,
collectionName: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>> {
throw new Error("TODO: Method not implemented.")
}
public createRESTRootCollection(
workspaceHandle: HandleRef<Workspace>,
collectionName: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>> {
if (
workspaceHandle.value.type !== "ok" ||
workspaceHandle.value.data.providerID !== this.providerID ||
workspaceHandle.value.data.workspaceID !== "personal"
) {
return Promise.resolve(E.left("INVALID_WORKSPACE_HANDLE" as const))
}
return Promise.resolve(
E.right(
computed(() => {
if (
workspaceHandle.value.type !== "ok" ||
workspaceHandle.value.data.providerID !== this.providerID ||
workspaceHandle.value.data.workspaceID !== "personal"
) {
return {
type: "invalid",
reason: "WORKSPACE_INVALIDATED" as const,
}
}
addRESTCollection(
makeCollection({
name: collectionName,
folders: [],
requests: [],
headers: [],
auth: {
authType: "inherit",
authActive: false,
},
})
)
platform.analytics?.logEvent({
type: "HOPP_CREATE_COLLECTION",
platform: "rest",
workspaceType: "personal",
isRootCollection: true,
})
return {
type: "ok",
data: {
providerID: this.providerID,
workspaceID: workspaceHandle.value.data.workspaceID,
collectionID: "",
name: collectionName,
},
}
})
)
)
}
public getCollectionHandle(
workspaceHandle: HandleRef<Workspace>,
collectionID: string
): Promise<
E.Either<"INVALID_WORKSPACE_HANDLE", HandleRef<WorkspaceCollection>>
> {
if (
workspaceHandle.value.type !== "ok" ||
workspaceHandle.value.data.providerID !== this.providerID ||
workspaceHandle.value.data.workspaceID !== "personal"
) {
return Promise.resolve(E.left("INVALID_WORKSPACE_HANDLE" as const))
}
return Promise.resolve(
E.right(
computed(() => {
if (
workspaceHandle.value.type !== "ok" ||
workspaceHandle.value.data.providerID !== this.providerID ||
workspaceHandle.value.data.workspaceID !== "personal"
) {
return {
type: "invalid",
reason: "WORKSPACE_INVALIDATED" as const,
}
}
// TODO: The way the IDs are issued, this will make it so we need a view
// before the ID is issued correctly
const coll = this.resolveCollectionFromCollectionID(collectionID)
if (coll === undefined) {
return {
type: "invalid",
reason: "INVALID_COLL_ID" as const,
}
}
return {
type: "ok",
data: {
providerID: this.providerID,
workspaceID: workspaceHandle.value.data.workspaceID,
collectionID,
name: coll.name,
},
}
})
)
)
}
public getRESTCollectionChildrenView(
collectionHandle: HandleRef<WorkspaceCollection>
): Promise<E.Either<never, HandleRef<RESTCollectionChildrenView>>> {
return Promise.resolve(
E.right(
computed(() => {
if (
collectionHandle.value.type === "invalid" ||
collectionHandle.value.data.providerID !== this.providerID ||
collectionHandle.value.data.workspaceID !== "personal"
) {
return {
type: "invalid" as const,
reason: "INVALID_COLLECTION_HANDLE" as const,
}
}
const collectionID = collectionHandle.value.data.collectionID
return markRaw({
type: "ok" as const,
data: {
providerID: this.providerID,
workspaceID: collectionHandle.value.data.workspaceID,
collectionID: collectionHandle.value.data.collectionID,
loading: ref(false),
mayHaveMoreContent: ref(false),
content: computed(() => {
const path = this.resolvePathFromCollectionID(collectionID)
const coll =
this.resolveCollectionFromCollectionID(collectionID)
if (coll === undefined || path === undefined) {
console.warn("Collection against ID was not resolvable")
return []
}
const collections = coll.folders.map((childColl, i) => {
const id = this.getIssuedInstanceIDForCollection(childColl, [
...path,
i,
])
return <RESTCollectionViewItem>{
type: "collection",
value: {
collectionID: id,
name: coll.name,
},
}
})
const requests = coll.requests.map((req, i) => {
const id = this.getIssuedInstanceIDForRequest(req)
return <RESTCollectionViewItem>{
type: "request",
value: {
requestID: id,
name: req.name,
method: req.method,
},
}
})
return [...collections, ...requests]
}),
loadMore() {
return Promise.resolve()
},
},
})
})
)
)
}
public getRESTRootCollectionView(
workspaceHandle: HandleRef<Workspace>
): Promise<E.Either<never, HandleRef<RootRESTCollectionView>>> {
return Promise.resolve(
E.right(
computed(() => {
if (
workspaceHandle.value.type === "invalid" ||
workspaceHandle.value.data.providerID !== this.providerID ||
workspaceHandle.value.data.workspaceID !== "personal"
) {
return {
type: "invalid" as const,
reason: "INVALID_WORKSPACE_HANDLE" as const,
}
}
return markRaw({
type: "ok" as const,
data: {
providerID: this.providerID,
workspaceID: workspaceHandle.value.data.workspaceID,
loading: ref(false),
mayHaveMoreContent: ref(false),
collections: computed(() => {
return this.restCollectionState.value.state.map((coll, i) => {
const id = this.getIssuedInstanceIDForCollection(coll, [i])
return {
collectionID: id,
name: coll.name,
}
})
}),
loadMore() {
return Promise.resolve()
},
},
})
})
)
)
}
public getWorkspaceHandle(
workspaceID: string
): Promise<E.Either<unknown, HandleRef<Workspace>>> {
if (workspaceID !== "personal") {
return Promise.resolve(E.left("INVALID_WORKSPACE_ID" as const))
}
return Promise.resolve(E.right(this.getPersonalWorkspaceHandle()))
}
public getPersonalWorkspaceHandle(): HandleRef<Workspace> {
return shallowRef({
type: "ok" as const,
data: {
providerID: this.providerID,
workspaceID: "personal",
name: "Personal Workspace",
collectionsAreReadonly: false,
},
})
}
}

View File

@@ -0,0 +1,321 @@
import { computed, markRaw, reactive, ref } from "vue"
import { useTimestamp } from "@vueuse/core"
import { Service } from "dioc"
import { WorkspaceProvider } from "../provider"
import * as E from "fp-ts/Either"
import { HandleRef } from "../handle"
import { Workspace, WorkspaceCollection } from "../workspace"
import { NewWorkspaceService } from ".."
import TestWorkspaceSelector from "~/components/workspace/TestWorkspaceSelector.vue"
import { RESTCollectionChildrenView, RootRESTCollectionView } from "../view"
import IconUser from "~icons/lucide/user"
import { get } from "lodash-es"
type TestReqDef = {
name: string
}
type TestCollDef = {
name: string
collections: TestCollDef[]
requests: TestReqDef[]
}
const timestamp = useTimestamp({ interval: 3000 })
// const timestamp = ref(Date.now())
const testData = reactive({
workspaceA: {
name: computed(() => `Workspace A: ${timestamp.value}`),
collections: [
<TestCollDef>{
name: "Collection A",
collections: [
{
name: "Collection B",
collections: [
{ name: "Collection C", collections: [], requests: [] },
],
requests: [],
},
],
requests: [{ name: "Request C" }],
},
],
},
workspaceB: {
name: "Workspace B",
collections: [
<TestCollDef>{
name: "Collection D",
collections: [{ name: "Collection E", collections: [], requests: [] }],
requests: [{ name: "Request F" }],
},
],
},
})
;(window as any).testData = testData
export class TestWorkspaceProviderService
extends Service
implements WorkspaceProvider
{
public static readonly ID = "TEST_WORKSPACE_PROVIDER_SERVICE"
public providerID = "TEST_WORKSPACE_PROVIDER"
public workspaceDecor = ref({
workspaceSelectorComponent: markRaw(TestWorkspaceSelector),
headerCurrentIcon: markRaw(IconUser),
workspaceSelectorPriority: 10,
})
private readonly workspaceService = this.bind(NewWorkspaceService)
constructor() {
super()
this.workspaceService.registerWorkspaceProvider(this)
}
public createRESTRootCollection(
workspaceHandle: HandleRef<Workspace>,
collectionName: string
): Promise<
E.Either<"INVALID_WORKSPACE_HANDLE", HandleRef<WorkspaceCollection>>
> {
if (workspaceHandle.value.type !== "ok") {
return Promise.resolve(E.left("INVALID_WORKSPACE_HANDLE" as const))
}
const workspaceID = workspaceHandle.value.data.workspaceID
const newCollID =
testData[workspaceID as keyof typeof testData].collections.length
testData[workspaceID as keyof typeof testData].collections.push({
name: collectionName,
collections: [],
requests: [],
})
return this.getCollectionHandle(workspaceHandle, newCollID.toString())
}
public createRESTChildCollection(
parentCollHandle: HandleRef<WorkspaceCollection>,
collectionName: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>> {
// TODO: Implement
throw new Error("Method not implemented.")
}
public getWorkspaceHandle(
workspaceID: string
): Promise<E.Either<never, HandleRef<Workspace>>> {
return Promise.resolve(
E.right(
computed(() => {
if (!(workspaceID in testData)) {
return {
type: "invalid",
reason: "WORKSPACE_WENT_OUT" as const,
}
}
return {
type: "ok",
data: {
providerID: this.providerID,
workspaceID,
name: testData[workspaceID as keyof typeof testData].name,
collectionsAreReadonly: false,
},
}
})
)
)
}
public getCollectionHandle(
workspaceHandle: HandleRef<Workspace>,
collectionID: string
): Promise<
E.Either<"INVALID_WORKSPACE_HANDLE", HandleRef<WorkspaceCollection>>
> {
return Promise.resolve(
E.right(
computed(() => {
if (workspaceHandle.value.type !== "ok") {
return {
type: "invalid",
reason: "WORKSPACE_INVALIDATED" as const,
}
}
const workspaceID = workspaceHandle.value.data.workspaceID
const collectionPath = collectionID
.split("/")
.flatMap((x) => ["collections", x])
const result: TestCollDef | undefined = get(
testData[workspaceID as keyof typeof testData],
collectionPath
)
if (!result) {
return {
type: "invalid",
reason: "INVALID_COLL_ID",
}
}
return {
type: "ok",
data: {
providerID: this.providerID,
workspaceID,
collectionID,
name: result.name,
},
}
})
)
)
}
public getRESTCollectionChildrenView(
collectionHandle: HandleRef<WorkspaceCollection>
): Promise<E.Either<never, HandleRef<RESTCollectionChildrenView>>> {
return Promise.resolve(
E.right(
computed(() => {
if (collectionHandle.value.type === "invalid") {
return {
type: "invalid",
reason: "COLL_HANDLE_IS_INVALID" as const,
}
}
const workspaceID = collectionHandle.value.data.workspaceID
const collectionID = collectionHandle.value.data.collectionID
if (!(workspaceID in testData)) {
return {
type: "invalid",
reason: "WORKSPACE_NOT_PRESENT" as const,
}
}
const collectionPath = collectionID
.split("/")
.flatMap((x) => ["collections", x])
return markRaw({
type: "ok",
data: {
providerID: this.providerID,
workspaceID,
collectionID,
mayHaveMoreContent: ref(false),
loading: ref(false),
content: computed(() => [
...(
get(testData[workspaceID as keyof typeof testData], [
...collectionPath,
"collections",
]) as TestCollDef[]
).map((item, i) => ({
type: "collection" as const,
value: {
collectionID: `${collectionID}/${i}`,
name: item.name,
},
})),
...(
get(testData[workspaceID as keyof typeof testData], [
...collectionPath,
"requests",
]) as TestReqDef[]
).map((item, i) => ({
type: "request" as const,
value: {
requestID: `${collectionID}/${i}`,
name: item.name,
method: "get",
},
})),
]),
loadMore(_count: number) {
return Promise.resolve()
},
},
})
})
)
)
}
public getRESTRootCollectionView(
workspaceHandle: HandleRef<Workspace>
): Promise<E.Either<never, HandleRef<RootRESTCollectionView>>> {
return Promise.resolve(
E.right(
computed(() => {
if (workspaceHandle.value.type === "invalid") {
return {
type: "invalid",
reason: "WORKSPACE_IS_INVALID" as const,
}
}
const workspaceID = workspaceHandle.value.data.workspaceID
if (!(workspaceID in testData)) {
return {
type: "invalid",
reason: "WORKSPACE_NOT_PRESENT" as const,
}
}
return markRaw({
type: "ok",
data: {
providerID: this.providerID,
workspaceID,
mayHaveMoreContent: ref(false),
loading: ref(false),
collections: computed(() => {
return testData[
workspaceID as keyof typeof testData
].collections.map((x, i) => ({
collectionID: i.toString(),
name: x.name,
}))
}),
loadMore() {
return Promise.resolve()
},
},
})
})
)
)
}
public getWorkspaceCandidates() {
return computed(() =>
Object.keys(testData).map((workspaceID) => ({
id: workspaceID,
name: testData[workspaceID as keyof typeof testData].name,
}))
)
}
}

View File

@@ -0,0 +1,42 @@
import { Ref } from "vue"
export type RESTCollectionViewCollection = {
collectionID: string
name: string
}
export type RESTCollectionViewRequest = {
requestID: string
name: string
method: string
}
export type RESTCollectionViewItem =
| { type: "collection"; value: RESTCollectionViewCollection }
| { type: "request"; value: RESTCollectionViewRequest }
export interface RootRESTCollectionView {
providerID: string
workspaceID: string
mayHaveMoreContent: Ref<boolean>
loading: Ref<boolean>
collections: Ref<RESTCollectionViewCollection[]>
loadMore(count: number): Promise<void>
}
export interface RESTCollectionChildrenView {
providerID: string
workspaceID: string
collectionID: string
mayHaveMoreContent: Ref<boolean>
loading: Ref<boolean>
content: Ref<RESTCollectionViewItem[]>
loadMore(count: number): Promise<void>
}

View File

@@ -0,0 +1,27 @@
import { Component } from "vue"
export type Workspace = {
providerID: string
workspaceID: string
name: string
collectionsAreReadonly: boolean
}
export type WorkspaceCollection = {
providerID: string
workspaceID: string
collectionID: string
name: string
}
export type WorkspaceDecor = {
headerComponent?: Component
headerCurrentIcon?: Component | object
workspaceSelectorComponent?: Component
workspaceSelectorPriority?: number
}