Skip to content

Commit

Permalink
fix: ux tweaks to ST Schema invites
Browse files Browse the repository at this point in the history
  • Loading branch information
rossiam committed Oct 30, 2023
1 parent 3629f07 commit e75b122
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 143 deletions.
8 changes: 8 additions & 0 deletions .changeset/eighty-knives-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@smartthings/cli": patch
"@smartthings/plugin-cli-edge": patch
"@smartthings/cli-lib": patch
"@smartthings/cli-testlib": patch
---

minor ux tweaks to new ST Schema Invites
28 changes: 14 additions & 14 deletions package-lock.json

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

40 changes: 0 additions & 40 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ that map to the API spec.
* [`smartthings installedschema [ID]`](#smartthings-installedschema-id)
* [`smartthings installedschema:delete [ID]`](#smartthings-installedschemadelete-id)
* [`smartthings invites:schema [IDORINDEX]`](#smartthings-invitesschema-idorindex)
* [`smartthings invites:schema:check-acceptance [ID]`](#smartthings-invitesschemacheck-acceptance-id)
* [`smartthings invites:schema:create`](#smartthings-invitesschemacreate)
* [`smartthings invites:schema:delete [ID]`](#smartthings-invitesschemadelete-id)
* [`smartthings locations [IDORINDEX]`](#smartthings-locations-idorindex)
Expand Down Expand Up @@ -4157,45 +4156,6 @@ EXAMPLES

_See code: [src/commands/invites/schema.ts](https://github.com/SmartThingsCommunity/smartthings-cli/blob/@smartthings/cli@1.8.0/packages/cli/src/commands/invites/schema.ts)_

## `smartthings invites:schema:check-acceptance [ID]`

check the acceptance status of a schema app invitation

```
USAGE
$ smartthings invites:schema:check-acceptance [ID] [-h] [-p <value>] [-t <value>] [--language <value>] [-j] [-y] [-o <value>]
[--schema-app <value>]
ARGUMENTS
ID the invitation id
FLAGS
--schema-app=<value> schema app id
COMMON FLAGS
-h, --help Show CLI help.
-j, --json use JSON format of input and/or output
-o, --output=<value> specify output file
-p, --profile=<value> [default: default] configuration profile
-t, --token=<value> the auth token to use
-y, --yaml use YAML format of input and/or output
--language=<value> ISO language code or "NONE" to not specify a language. Defaults to the OS locale
DESCRIPTION
check the acceptance status of a schema app invitation
EXAMPLES
prompt for an invitation and check its acceptance status
$ smartthings invites:schema:check-acceptance
check acceptance status for the specified invitation
$ smartthings invites:schema:check-acceptance 7bd4c5b6-e840-44b3-9933-549a342d95ce
```

_See code: [src/commands/invites/schema/check-acceptance.ts](https://github.com/SmartThingsCommunity/smartthings-cli/blob/@smartthings/cli@1.8.0/packages/cli/src/commands/invites/schema/check-acceptance.ts)_

## `smartthings invites:schema:create`

create an invitation to a schema app
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
"@oclif/plugin-not-found": "^2.3.1",
"@oclif/plugin-plugins": "^2.1.0",
"@smartthings/cli-lib": "^2.2.2",
"@smartthings/core-sdk": "^8.1.0",
"@smartthings/core-sdk": "^8.1.1",
"@smartthings/plugin-cli-edge": "^3.3.1",
"inquirer": "^8.2.4",
"js-yaml": "^4.1.0",
Expand Down
81 changes: 69 additions & 12 deletions packages/cli/src/__tests__/lib/commands/invites-util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SchemaApp, SchemaAppInvitation, SmartThingsClient } from '@smartthings/

import { APICommand, ValueTableFieldDefinition, chooseOptionsWithDefaults, selectFromList, stringTranslateToId } from '@smartthings/cli-lib'

import { chooseSchemaInvitation, getSingleInvite, inviteTableFieldDefinitions } from '../../../lib/commands/invites-utils'
import { addAppDetails, chooseSchemaInvitation, getSingleInvite, tableFieldDefinitions } from '../../../lib/commands/invites-utils'
import { chooseSchemaApp } from '../../../lib/commands/schema-util'


Expand Down Expand Up @@ -74,41 +74,82 @@ describe('chooseSchemaInvitation', () => {
})

test.each`
input | expected
${undefined} | ${'none'}
${1694617703} | ${'2023-09-13T15:08:23.000Z'}
input | expected
${undefined} | ${'none'}
${1694617703} | ${'2023-09-13T15:08:23.000Z'}
`('expiration displays $expected for $input', ({ input, expected }) => {
const value = (inviteTableFieldDefinitions[2] as
const value = (tableFieldDefinitions[2] as
ValueTableFieldDefinition<SchemaAppInvitation>).value as (input: SchemaAppInvitation) => string
expect(value({ expiration: input } as SchemaAppInvitation)).toBe(expected)
})

describe('addAppDetails', () => {
it('handles optional fields', () => {
expect(addAppDetails({
id: 'invitation-id',
schemaAppId: 'schema-app-id',
} as SchemaAppInvitation, {
} as SchemaApp)).toStrictEqual({
id: 'invitation-id',
schemaAppId: 'schema-app-id',
schemaAppName: undefined,
sort: ':schema-app-id :invitation-id',
})
})

it('handles populated optional fields', () => {
expect(addAppDetails({
id: 'invitation-id',
description: 'invitation-description',
schemaAppId: 'schema-app-id',
} as SchemaAppInvitation, {
appName: 'schema-app-name',
} as SchemaApp)).toStrictEqual({
id: 'invitation-id',
description: 'invitation-description',
schemaAppId: 'schema-app-id',
schemaAppName: 'schema-app-name',
sort: 'schema-app-name:schema-app-id invitation-description:invitation-id',
})
})
})

describe('getSingleInvite', () => {
const invitation1 = { id: 'invitation-id-1' } as SchemaAppInvitation
const invitation2 = { id: 'invitation-id-2' } as SchemaAppInvitation
const invitation2 = { id: 'invitation-id-2', schemaAppId: 'invite-2-app-id' } as SchemaAppInvitation
const invitation3 = { id: 'invitation-id-3' } as SchemaAppInvitation
const invitationList = [invitation1, invitation2, invitation3]

const schemaApp1 = { endpointAppId: 'schema-app-id-1' } as SchemaApp
const schemaApp2 = { endpointAppId: 'schema-app-id-2' } as SchemaApp
const schemaApp2 = { endpointAppId: 'schema-app-id-2', appName: 'Schema App 2' } as SchemaApp
const schemaApp3 = { endpointAppId: 'schema-app-id-3' } as SchemaApp
const schemaAppList = [schemaApp1, schemaApp2, schemaApp3]

const listInvitesMock = jest.fn().mockResolvedValue(invitationList)
const listSchemaMock = jest.fn().mockResolvedValue(schemaAppList)
const getSchemaMock = jest.fn()
const client = {
invitesSchema: {
list: listInvitesMock,
},
schema: {
get: getSchemaMock,
list: listSchemaMock,
},
} as unknown as SmartThingsClient

describe('with schemaAppId specified', () => {
it('returns invitation with matching id', async () => {
expect(await getSingleInvite(client, 'schema-app-id', 'invitation-id-2')).toBe(invitation2)
getSchemaMock.mockResolvedValueOnce(schemaApp2)

expect(await getSingleInvite(client, 'schema-app-id', 'invitation-id-2')).toStrictEqual({
...invitation2,
schemaAppName: 'Schema App 2',
sort: 'Schema App 2:invite-2-app-id :invitation-id-2',
})

expect(getSchemaMock).toHaveBeenCalledTimes(1)
expect(getSchemaMock).toHaveBeenCalledWith('invite-2-app-id')
expect(listInvitesMock).toHaveBeenCalledTimes(1)
expect(listInvitesMock).toHaveBeenCalledWith('schema-app-id')

Expand All @@ -118,38 +159,52 @@ describe('getSingleInvite', () => {
it('throws an error when no matching invite found', async () => {
await expect(getSingleInvite(client, 'schema-app-id', 'bad-invitation-id')).rejects.toThrow()

expect(listSchemaMock).toHaveBeenCalledTimes(0)
expect(listInvitesMock).toHaveBeenCalledTimes(1)
expect(listInvitesMock).toHaveBeenCalledWith('schema-app-id')

expect(getSchemaMock).toHaveBeenCalledTimes(0)
expect(listSchemaMock).toHaveBeenCalledTimes(0)
})
})

describe('with schemaAppId specified', () => {
describe('with schemaAppId not specified', () => {
it('searches schema apps when none specified', async () => {
listInvitesMock.mockResolvedValueOnce([invitation1])
listInvitesMock.mockResolvedValueOnce([invitation3, invitation2])

expect(await getSingleInvite(client, undefined, 'invitation-id-2')).toBe(invitation2)
expect(await getSingleInvite(client, undefined, 'invitation-id-2')).toStrictEqual({
...invitation2,
schemaAppName: 'Schema App 2',
sort: 'Schema App 2:invite-2-app-id :invitation-id-2',
})

expect(listSchemaMock).toHaveBeenCalledTimes(1)
expect(listSchemaMock).toHaveBeenCalledWith()
expect(listInvitesMock).toHaveBeenCalledTimes(2)
expect(listInvitesMock).toHaveBeenCalledWith('schema-app-id-1')
expect(listInvitesMock).toHaveBeenCalledWith('schema-app-id-2')

expect(getSchemaMock).toHaveBeenCalledTimes(0)
})

it('skips schema apps with no id', async () => {
listSchemaMock.mockResolvedValueOnce([{} as SchemaApp, schemaApp1, schemaApp2, schemaApp3])
listInvitesMock.mockResolvedValueOnce([invitation1])
listInvitesMock.mockResolvedValueOnce([invitation3, invitation2])

expect(await getSingleInvite(client, undefined, 'invitation-id-2')).toBe(invitation2)
expect(await getSingleInvite(client, undefined, 'invitation-id-2')).toStrictEqual({
...invitation2,
schemaAppName: 'Schema App 2',
sort: 'Schema App 2:invite-2-app-id :invitation-id-2',
})

expect(listSchemaMock).toHaveBeenCalledTimes(1)
expect(listSchemaMock).toHaveBeenCalledWith()
expect(listInvitesMock).toHaveBeenCalledTimes(2)
expect(listInvitesMock).toHaveBeenCalledWith('schema-app-id-1')
expect(listInvitesMock).toHaveBeenCalledWith('schema-app-id-2')

expect(getSchemaMock).toHaveBeenCalledTimes(0)
})

it('throws an error when no matching invite found', async () => {
Expand All @@ -161,6 +216,8 @@ describe('getSingleInvite', () => {
expect(listInvitesMock).toHaveBeenCalledWith('schema-app-id-1')
expect(listInvitesMock).toHaveBeenCalledWith('schema-app-id-2')
expect(listInvitesMock).toHaveBeenCalledWith('schema-app-id-3')

expect(getSchemaMock).toHaveBeenCalledTimes(0)
})
})
})
34 changes: 22 additions & 12 deletions packages/cli/src/commands/invites/schema.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { Flags } from '@oclif/core'

import { SchemaAppInvitation } from '@smartthings/core-sdk'
import { SmartThingsClient } from '@smartthings/core-sdk'

import {
APICommand,
outputItemOrList,
OutputItemOrListConfig,
} from '@smartthings/cli-lib'

import { getSingleInvite, inviteTableFieldDefinitions } from '../../lib/commands/invites-utils'
import { chooseSchemaApp } from '../../lib/commands/schema-util'
import { addAppDetails, getSingleInvite, InvitationWithAppDetails, tableFieldDefinitions } from '../../lib/commands/invites-utils'


export default class InvitesSchemaCommand extends APICommand<typeof InvitesSchemaCommand.flags> {
Expand Down Expand Up @@ -49,18 +48,29 @@ export default class InvitesSchemaCommand extends APICommand<typeof InvitesSchem
]

async run(): Promise<void> {
const config: OutputItemOrListConfig<SchemaAppInvitation> = {
type InvitationProviderFunction = () => Promise<InvitationWithAppDetails[]>
const listFn = (client: SmartThingsClient, appId?: string): InvitationProviderFunction =>
async (): Promise<InvitationWithAppDetails[]> => {
const apps = appId
? [await client.schema.get(appId)]
: await client.schema.list()
return (await Promise.all(apps.map(async app => {
return app.endpointAppId
? (await client.invitesSchema.list(app.endpointAppId))
.map(invite => addAppDetails(invite, app))
: []
}))).flat()
}

const config: OutputItemOrListConfig<InvitationWithAppDetails> = {
primaryKeyName: 'id',
sortKeyName: 'description',
sortKeyName: 'sort',
itemName: 'schema app invitation',
listTableFieldDefinitions: ['id', 'description', 'shortCode'],
tableFieldDefinitions: inviteTableFieldDefinitions,
}
const list = async (): Promise<SchemaAppInvitation[]> => {
const schemaAppId = await chooseSchemaApp(this, this.flags['schema-app'])
return this.client.invitesSchema.list(schemaAppId)
listTableFieldDefinitions: [{ prop: 'id', label: 'Invitation Id' }, 'schemaAppName', 'description'],
tableFieldDefinitions,
}
await outputItemOrList(this, config, this.args.idOrIndex,
list, id => getSingleInvite(this.client, this.flags['schema-app'], id))
listFn(this.client, this.flags['schema-app']),
id => getSingleInvite(this.client, this.flags['schema-app'], id))
}
}
Loading

0 comments on commit e75b122

Please sign in to comment.