Skip to content

Commit

Permalink
Merge pull request #374 from PrefectHQ/devtools
Browse files Browse the repository at this point in the history
Add Devtools for `useSubscription`
  • Loading branch information
collincchoy authored Jan 17, 2024
2 parents 5f137a2 + cea529b commit 3f3eff4
Show file tree
Hide file tree
Showing 10 changed files with 367 additions and 8 deletions.
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.options": {
"extensions": [
"*.html",
"*.js",
"*.vue",
"*.jsx",
"*.json",
"*.ts"
]
},
"editor.tabSize": 2,
"editor.insertSpaces": true,
}
9 changes: 3 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
}
},
"dependencies": {
"@vue/devtools-api": "^6.1.4",
"jsdom": "^23.0.0"
}
}
24 changes: 24 additions & 0 deletions src/devtools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {
type App,
setupDevtoolsPlugin
} from '@vue/devtools-api'
import { type Plugin } from 'vue'
import * as useSubscriptionDevtools from '@/useSubscription/useSubscriptionDevtools'

export const plugin: Plugin = {
install(app: App): void {
setupDevtoolsPlugin({
id: 'prefect-vue-compositions-devtools',
label: 'Prefect Devtools',
packageName: '@prefecthq/vue-compositions',
homepage: 'https://www.prefect.io/',
settings: {
...useSubscriptionDevtools.SUBSCRIPTION_DEVTOOLS_SETTINGS,
},
enableEarlyProxy: true,
app,
}, (api) => {
useSubscriptionDevtools.init(api)
})
},
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ export * from './useStorage'
export * from './useSubscription'
export * from './useValidation'
export * from './useValidationObserver'
export * from './useVisibilityObserver'
export * from './useVisibilityObserver'
export * from './devtools'
17 changes: 17 additions & 0 deletions src/useSubscription/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,20 @@ When a subscription is removed the channel interval is recalculated. A subscript
| unsubscribe | `() => void` | | Remove the subscription from the channel |
| subscribe | `() => subscription<action>` | | Resubscribes to the channel using the same arguments |

## Debugging
`useSubscription` comes with its own Vue devtools plugin for debugging purposes.

To use, just install the Vue plugin onto your app:
```typescript
import { plugin as VueCompositionsDevtools } from '@prefecthq/vue-compositions'

const app = createApp(App)
if (/*not in production*/) {
app.use(VueCompositionsDevtools)
}
```

> Note: to limit runtime overhead, only install the plugin if in development
Once installed, open the Vue devtools and you should see a new tab and timeline layer
for `Subscriptions`. The devtool plugin tracks all active subscriptions and their underlying channels.
41 changes: 41 additions & 0 deletions src/useSubscription/models/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
ChannelSignature
} from '@/useSubscription/types/action'
import { SubscriptionOptions } from '@/useSubscription/types/subscription'
import * as useSubscriptionDevtools from '@/useSubscription/useSubscriptionDevtools'
import { unrefArgs } from '@/useSubscription/utilities/reactivity'

class ChannelSignatureManager {
Expand Down Expand Up @@ -60,6 +61,12 @@ export default class Channel<T extends Action = Action> {
this.args = args
}

public get actionName(): string {
const prefix = 'bound '
const sanitizedChannelActionName = this.action.name.startsWith(prefix) ? this.action.name.slice(prefix.length) : this.action.name
return sanitizedChannelActionName
}

private get interval(): number {
const intervals = Array
.from(this.subscriptions.values())
Expand All @@ -82,6 +89,12 @@ export default class Channel<T extends Action = Action> {
for (const subscription of this.subscriptions.values()) {
subscription.response.value = response
}

useSubscriptionDevtools.updateChannel(this, {
title: `${this.actionName} · Response`,
data: { channel: this, action: this.actionName, response },
groupId: this.signature,
})
}

public get executed(): boolean {
Expand All @@ -94,6 +107,12 @@ export default class Channel<T extends Action = Action> {
for (const subscription of this.subscriptions.values()) {
subscription.executed.value = executed
}

useSubscriptionDevtools.updateChannel(this, {
title: `${this.actionName} · Executed`,
data: { channel: this, action: this.actionName, executed },
groupId: this.signature,
})
}

public get loading(): boolean {
Expand All @@ -106,6 +125,14 @@ export default class Channel<T extends Action = Action> {
for (const subscription of this.subscriptions.values()) {
subscription.loading.value = loading
}

if (loading) {
useSubscriptionDevtools.updateChannel(this, {
title: `${this.actionName} · Loading`,
data: { channel: this, action: this.actionName, loading },
groupId: this.signature,
})
}
}

public get errored(): boolean {
Expand All @@ -130,6 +157,14 @@ export default class Channel<T extends Action = Action> {
for (const subscription of this.subscriptions.values()) {
subscription.error.value = error
}

if (error) {
useSubscriptionDevtools.updateChannel(this, {
title: `${this.actionName} · Error`,
data: { channel: this, action: this.actionName, error },
groupId: this.signature,
})
}
}

public subscribe(options: SubscriptionOptions): Subscription<T> {
Expand Down Expand Up @@ -189,6 +224,12 @@ export default class Channel<T extends Action = Action> {
this.scope = effectScope()
const response = this.execute()

useSubscriptionDevtools.updateChannel(this, {
title: `${this.actionName} · Refresh`,
data: { channel: this, action: this.actionName },
groupId: this.signature,
})

return response
}

Expand Down
16 changes: 15 additions & 1 deletion src/useSubscription/models/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ChannelSignature
} from '@/useSubscription/types/action'
import { SubscriptionOptions } from '@/useSubscription/types/subscription'
import * as useSubscriptionDevtools from '@/useSubscription/useSubscriptionDevtools'

export default class Manager {
private readonly channels: Map<ChannelSignature, Channel> = new Map()
Expand All @@ -18,10 +19,17 @@ export default class Manager {
const channel = this.getChannel(action, args)
const subscription = channel.subscribe(options)

useSubscriptionDevtools.registerChannelSubscription(channel, subscription.id)

return subscription
}

public deleteChannel(signature: ChannelSignature): void {
const channel = this.channels.get(signature)
if (channel) {
useSubscriptionDevtools.removeChannel(channel)
}

this.channels.delete(signature)
}

Expand All @@ -35,8 +43,14 @@ export default class Manager {
return this.channels.get(channel.signature)! as Channel<T>
}

this.channels.set(channel.signature, channel)
this.addChannel(channel)

return channel
}

private addChannel(channel: Channel): void {
this.channels.set(channel.signature, channel)

useSubscriptionDevtools.addChannel(channel)
}
}
2 changes: 2 additions & 0 deletions src/useSubscription/models/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ref, Ref, watch } from 'vue'
import Channel from '@/useSubscription/models/channel'
import { Action, ActionResponse } from '@/useSubscription/types/action'
import { SubscriptionOptions } from '@/useSubscription/types/subscription'
import * as useSubscriptionDevtools from '@/useSubscription/useSubscriptionDevtools'

class SubscriptionIdManager {
private static id: number = 0
Expand Down Expand Up @@ -41,6 +42,7 @@ export default class Subscription<T extends Action> {

public unsubscribe(): void {
this.channel.unsubscribe(this.id)
useSubscriptionDevtools.removeChannelSubscription(this.channel, this.id)
}

public isSubscribed(): boolean {
Expand Down
Loading

0 comments on commit 3f3eff4

Please sign in to comment.