Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lib/agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Channel } from './channel'
import { MemoizedSignal, Signal } from './signal'
import { AgentAPI, AgentContext, ConnectMessage, ToolbarAction } from './types'

export default function createAgent(
channel: Channel,
contextData: ConnectMessage['agent'],
): AgentAPI {
if (!contextData) {
throw new Error('Context data is required')
}

const contextChanged = new MemoizedSignal<[AgentContext]>(contextData)

const toolbarActionSignal = new Signal<[ToolbarAction]>()

channel.addHandler('contextChanged', (newContext: AgentContext) => {
contextChanged.dispatch(newContext)
})

channel.addHandler('toolbarAction', (action: ToolbarAction) => {
toolbarActionSignal.dispatch(action)
})

return {
onContextChange: (handler) => contextChanged.attach(handler),
onToolbarAction: (handler) => toolbarActionSignal.attach(handler),
}
}
8 changes: 8 additions & 0 deletions lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import createDialogs from './dialogs'
import createEditor from './editor'
import createNavigator from './navigator'
import createApp from './app'
import createAgent from './agent'
import locations from './locations'
import {
EntryFieldInfo,
Expand Down Expand Up @@ -45,6 +46,7 @@ const LOCATION_TO_API_PRODUCERS: { [location: string]: ProducerFunc[] } = {
[locations.LOCATION_PAGE]: [makeSharedAPI],
[locations.LOCATION_HOME]: [makeSharedAPI],
[locations.LOCATION_APP_CONFIG]: [makeSharedAPI, makeAppAPI],
[locations.LOCATION_AGENT]: [makeSharedAPI, makeAgentAPI],
}

export default function createAPI(
Expand Down Expand Up @@ -166,3 +168,9 @@ function makeAppAPI(channel: Channel) {
app,
}
}

function makeAgentAPI(channel: Channel, { agent }: ConnectMessage) {
return {
agent: createAgent(channel, agent),
}
}
1 change: 1 addition & 0 deletions lib/locations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const locations: Locations = {
LOCATION_PAGE: 'page',
LOCATION_APP_CONFIG: 'app-config',
LOCATION_HOME: 'home',
LOCATION_AGENT: 'agent',
}

export default locations
20 changes: 20 additions & 0 deletions lib/types/agent.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export interface AgentContext {
view: string
metadata: {
entryId?: string
contentTypeId?: string
lastFocusedFieldId?: string
}
}

export type ToolbarActionName = 'chat.history' | 'chat.back' | 'chat.close'

export interface ToolbarAction {
name: ToolbarActionName
action: 'click'
}

export interface AgentAPI {
onContextChange: (handler: (context: AgentContext) => void) => VoidFunction
onToolbarAction: (handler: (action: ToolbarAction) => void) => VoidFunction
}
12 changes: 12 additions & 0 deletions lib/types/api.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { NavigatorAPI } from './navigator.types'
import { EntryFieldInfo, FieldInfo } from './field.types'
import { Adapter, KeyValueMap } from 'contentful-management/types'
import { CMAClient } from './cmaClient.types'
import { AgentAPI, AgentContext } from './agent.types'

/* User API */

Expand Down Expand Up @@ -342,6 +343,14 @@ export type ConfigAppSDK<InstallationParameters extends KeyValueMap = KeyValueMa
app: AppConfigAPI
}

export type AgentAppSDK<InstallationParameters extends KeyValueMap = KeyValueMap> = BaseAppSDK<
InstallationParameters,
never,
never
> & {
agent: AgentAPI
}

export type KnownAppSDK<
InstallationParameters extends KeyValueMap = KeyValueMap,
InstanceParameters extends KeyValueMap = KeyValueMap,
Expand All @@ -354,6 +363,7 @@ export type KnownAppSDK<
| PageAppSDK<InstallationParameters>
| ConfigAppSDK<InstallationParameters>
| HomeAppSDK<InstallationParameters>
| AgentAppSDK<InstallationParameters>

/** @deprecated consider using {@link BaseAppSDK} */
export type BaseExtensionSDK = BaseAppSDK
Expand Down Expand Up @@ -392,6 +402,7 @@ export interface Locations {
LOCATION_PAGE: 'page'
LOCATION_HOME: 'home'
LOCATION_APP_CONFIG: 'app-config'
LOCATION_AGENT: 'agent'
}

export interface ConnectMessage {
Expand Down Expand Up @@ -421,4 +432,5 @@ export interface ConnectMessage {
hostnames: HostnamesAPI
release?: Release
uiLanguageLocale: string
agent?: AgentContext
}
3 changes: 3 additions & 0 deletions lib/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ export type {
UserAPI,
JSONPatchItem,
HostnamesAPI,
AgentAppSDK,
} from './api.types'

export type { AgentAPI, AgentContext, ToolbarAction, ToolbarActionName } from './agent.types'

export type {
AppConfigAPI,
AppState,
Expand Down
22 changes: 22 additions & 0 deletions test/mocks/agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { AgentContext } from '../../lib/types'

export const mockAgentContext: AgentContext = {
view: 'entry-editor',
metadata: {
entryId: 'test-entry-123',
contentTypeId: 'test-content-type-456',
lastFocusedFieldId: 'test-field-789',
},
}

export const mockAgentContextMinimal: AgentContext = {
view: 'home',
metadata: {},
}

export const mockAgentContextWithPartialMetadata: AgentContext = {
view: 'page',
metadata: {
entryId: 'entry-abc',
},
}
7 changes: 7 additions & 0 deletions test/mocks/connectMessage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ConnectMessage } from '../../lib/types'
import { mockAgentContext } from './agent'

export const baseConnectMessage: ConnectMessage = {
id: 'test-app-id',
Expand Down Expand Up @@ -207,4 +208,10 @@ export const baseConnectMessage: ConnectMessage = {
uiLanguageLocale: 'en-US',
} as any // Type assertion to work with complex nested types in testing

export const connectMessageWithAgent: ConnectMessage = {
...baseConnectMessage,
location: 'agent',
agent: mockAgentContext,
} as any

export default baseConnectMessage
Loading