Add Nylas compose page block

This commit is contained in:
Jože Fortun
2022-12-06 17:07:45 +01:00
parent 59a7929721
commit 074f0f31aa
24 changed files with 485 additions and 77 deletions
@@ -17,7 +17,7 @@
</b-form-group>
<b-form-group
:label="$t('forbidden-roles.label')"
:label="$t('prohibited-roles.label')"
label-cols="3"
class="mb-0"
>
@@ -26,7 +26,7 @@
class="mb-3"
>
<template #description>
{{ $t('forbidden-roles.description') }}
{{ $t('prohibited-roles.description') }}
</template>
</c-role-picker>
</b-form-group>
@@ -3,24 +3,22 @@
<b-form-group label-cols="3">
<b-form-checkbox
v-model="value.enabled"
:value="true"
:unchecked-value="false"
>
{{ $t('enabled') }}
</b-form-checkbox>
</b-form-group>
<b-form-group
v-if="value.handle === 'nylas'"
label-cols="3"
>
<b-form-checkbox
v-model="providerUsage"
:value="true"
:unchecked-value="false"
>
{{ $t('apiAccess') }}
</b-form-checkbox>
</b-form-group>
<b-form-group
:label="$t('clientKey')"
label-cols="3"
@@ -32,6 +30,7 @@
/>
</b-input-group>
</b-form-group>
<b-form-group
:label="$t('clientSecret')"
label-cols="3"
@@ -4,78 +4,77 @@
header-bg-variant="white"
footer-bg-variant="white"
>
<b-form>
<b-form-group>
<b-form-checkbox
v-model="external.enabled"
:value="true"
:unchecked-value="false"
>
{{ $t('enabled') }}
</b-form-checkbox>
</b-form-group>
<b-button
class="float-right mb-3"
@click="newOIDC()"
<b-form-group>
<b-form-checkbox
v-model="external.enabled"
:value="true"
:unchecked-value="false"
>
{{ $t('oidc.add') }}
</b-button>
{{ $t('enabled') }}
</b-form-checkbox>
</b-form-group>
<b-table
:items="providers.items"
:fields="providers.fields"
:tbody-tr-class="(i) => i.rowBackground"
>
<template #cell(enabled)="{ item }">
<b-checkbox
:checked="item.enabled"
@change="item.enable($event)"
/>
</template>
<b-button
class="my-3"
variant="primary"
@click="newOIDC()"
>
{{ $t('oidc.add') }}
</b-button>
<template #cell(provider)="{ item }">
{{ item.provider }}
<b-badge
v-if="item.tag"
class="ml-1"
>
{{ item.tag }}
</b-badge>
</template>
<template #cell(editor)="{ item }">
<confirmation-toggle
v-if="item.delete"
cta-class="link"
@confirmed="item.delete()"
>
<font-awesome-icon :icon="['far', 'trash-alt']" />
</confirmation-toggle>
<b-button
variant="link"
@click="openEditor(item.editor)"
>
<font-awesome-icon
:icon="['fas', 'wrench']"
/>
</b-button>
</template>
</b-table>
<b-modal
v-model="modal.open"
:title="modal.title"
size="lg"
title-class="text-capitalize"
@ok="modal.updater(modal.data)"
>
<component
:is="modal.component"
v-model="modal.data"
<b-table
:items="providers.items"
:fields="providers.fields"
:tbody-tr-class="(i) => i.rowBackground"
>
<template #cell(enabled)="{ item }">
<b-checkbox
:checked="item.enabled"
@change="item.enable($event)"
/>
</b-modal>
</b-form>
</template>
<template #cell(provider)="{ item }">
{{ item.provider }}
<b-badge
v-if="item.tag"
class="ml-1"
>
{{ item.tag }}
</b-badge>
</template>
<template #cell(editor)="{ item }">
<confirmation-toggle
v-if="item.delete"
cta-class="link"
@confirmed="item.delete()"
>
<font-awesome-icon :icon="['far', 'trash-alt']" />
</confirmation-toggle>
<b-button
variant="link"
@click="openEditor(item.editor)"
>
<font-awesome-icon
:icon="['fas', 'wrench']"
/>
</b-button>
</template>
</b-table>
<b-modal
v-model="modal.open"
:title="modal.title"
size="lg"
title-class="text-capitalize"
@ok="modal.updater(modal.data)"
>
<component
:is="modal.component"
v-model="modal.data"
/>
</b-modal>
<template #header>
<h3 class="m-0">
+6
View File
@@ -44,6 +44,12 @@
"@fullcalendar/list": "^4.3.0",
"@fullcalendar/timegrid": "^4.3.0",
"@fullcalendar/vue": "^4.3.1",
"@nylas/components-agenda": "^1.1.7-canary.6",
"@nylas/components-composer": "^1.1.6-canary.20",
"@nylas/components-contact-list": "^1.1.4-canary.6",
"@nylas/components-conversation": "^1.1.6-canary.6",
"@nylas/components-email": "^1.1.7-canary.32",
"@nylas/components-mailbox": "^1.1.6-canary.27",
"@popperjs/core": "^2.4.0",
"axios": "^0.21.2",
"bootstrap-vue": "^2.21.2",
Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

@@ -13,3 +13,4 @@ export const Metric = require('./Metric.png')
export const Comment = require('./Comment.png')
export const Report = require('./Report.png')
export const Progress = require('./Progress.png')
export const Nylas = require('./Nylas.jpg')
@@ -139,6 +139,11 @@ export default {
block: new compose.PageBlockProgress(),
image: images.Progress,
},
{
label: this.$t('nylas.label'),
block: new compose.PageBlockNylas(),
image: images.Nylas,
},
],
}
},
@@ -0,0 +1,16 @@
<template>
<nylas-agenda
:id="componentID"
:access_token="accessToken"
theme="light"
/>
</template>
<script>
import base from './base'
import '@nylas/components-agenda'
export default {
extends: base,
}
</script>
@@ -0,0 +1,16 @@
<template>
<nylas-composer
:id="componentID"
:access_token="accessToken"
theme="light"
/>
</template>
<script>
import base from './base'
import '@nylas/components-composer'
export default {
extends: base,
}
</script>
@@ -0,0 +1,16 @@
<template>
<nylas-contact-list
:id="componentID"
:access_token="accessToken"
theme="light"
/>
</template>
<script>
import base from './base'
import '@nylas/components-contact-list'
export default {
extends: base,
}
</script>
@@ -0,0 +1,16 @@
<template>
<nylas-conversation
:id="componentID"
:access_token="accessToken"
theme="light"
/>
</template>
<script>
import base from './base'
import '@nylas/components-conversation'
export default {
extends: base,
}
</script>
@@ -0,0 +1,16 @@
<template>
<nylas-email
:id="componentID"
:access_token="accessToken"
theme="light"
/>
</template>
<script>
import base from './base'
import '@nylas/components-email'
export default {
extends: base,
}
</script>
@@ -0,0 +1,16 @@
<template>
<nylas-mailbox
:id="componentID"
:access_token="accessToken"
theme="light"
/>
</template>
<script>
import base from './base'
import '@nylas/components-mailbox'
export default {
extends: base,
}
</script>
@@ -0,0 +1,15 @@
<script>
export default {
props: {
componentID: {
type: String,
required: true,
},
accessToken: {
type: String,
required: true,
},
},
}
</script>
@@ -0,0 +1,6 @@
export { default as Agenda } from './Agenda'
export { default as Composer } from './Composer'
export { default as ContactList } from './ContactList'
export { default as Conversation } from './Conversation'
export { default as Email } from './Email'
export { default as Mailbox } from './Mailbox'
@@ -0,0 +1,127 @@
<template>
<wrap
v-bind="$props"
v-on="$listeners"
>
<div
v-if="hideComponent"
class="d-flex flex-column align-items-center justify-content-center h-100 overflow-hidden"
>
<b-spinner
v-if="processing"
/>
<span
v-else-if="!isExternalConfigured"
>
{{ $t('noExternal') }}
</span>
<b-button
v-else-if="!accessToken"
:href="`${$auth.cortezaAuthURL}/external/nylas`"
target="_blank"
>
{{ $t('connect') }}
</b-button>
<span
v-else-if="!options.componentID"
>
{{ $t('noComponentID') }}
</span>
</div>
<component
:is="nylasComponent"
v-else
:component-i-d="options.componentID"
:access-token="accessToken"
/>
</wrap>
</template>
<script>
import base from '../base'
import * as Components from './Components/loader'
export default {
i18nOptions: {
namespaces: 'block',
keyPrefix: 'nylas.viewer',
},
extends: base,
data () {
return {
processing: false,
isExternalConfigured: false,
accessToken: '',
tokenCheckInterval: undefined,
}
},
computed: {
nylasComponent () {
return Components[this.options.kind]
},
hideComponent () {
return this.processing || !this.isExternalConfigured || !this.accessToken || !this.options.componentID
},
},
watch: {
'record.recordID': {
immediate: true,
async handler () {
this.processing = true
// Check if nylas is configured as a provider
const { enabled: externalEnabled = false, providers = [] } = this.$Settings.get('auth.external', {})
const { enabled: nylasEnabled = false, usage = [] } = providers.find(({ handle }) => handle === 'nylas') || {}
if (!externalEnabled || !nylasEnabled || !usage || !usage.includes('api')) {
this.isExternalConfigured = false
this.processing = false
return
}
this.isExternalConfigured = true
// Check if token exists, if yes get it, otherwise check it every 3 seconds
await this.checkNylasAccessToken()
.finally(() => {
this.processing = false
})
},
},
},
methods: {
checkNylasAccessToken () {
return this.$SystemAPI.userListCredentials({ userID: this.$auth.user.userID })
.then(credentials => {
if (!credentials || !credentials.length) {
return
}
this.accessToken = (credentials.find(({ kind }) => kind === 'access-nylas') || {}).credentials
if (this.accessToken) {
if (this.tokenCheckInterval) {
clearInterval(this.tokenCheckInterval)
}
} else if (!this.tokenCheckInterval) {
this.tokenCheckInterval = setInterval(() => {
this.checkNylasAccessToken()
}, 3000)
}
})
},
},
}
</script>
@@ -0,0 +1,45 @@
<template>
<b-tab :title="$t('label')">
<b-form-group
:label="$t('kind')"
>
<b-form-select
v-model="options.kind"
:options="nylasComponentKinds"
/>
</b-form-group>
<b-form-group
:label="$t('componentID')"
>
<b-form-input
v-model="options.componentID"
/>
</b-form-group>
</b-tab>
</template>
<script>
import base from '../base'
export default {
i18nOptions: {
namespaces: 'block',
keyPrefix: 'nylas.configurator',
},
extends: base,
data () {
return {
nylasComponentKinds: [
{ value: 'Agenda', text: this.$t('kinds.agenda') },
{ value: 'Composer', text: this.$t('kinds.composer') },
{ value: 'ContactList', text: this.$t('kinds.contactList') },
{ value: 'Conversation', text: this.$t('kinds.conversation') },
{ value: 'Email', text: this.$t('kinds.email') },
{ value: 'Mailbox', text: this.$t('kinds.mailbox') },
],
}
},
}
</script>
@@ -65,8 +65,14 @@ export default {
},
computed: {
options () {
return this.block.options
options: {
get () {
return this.block.options
},
set (options) {
this.block.options = options
},
},
allowsRefresh () {
@@ -32,6 +32,8 @@ import ReportBase from './Report/Base'
import ReportConfigurator from './Report/Configurator'
import ProgressBase from './ProgressBase'
import ProgressConfigurator from './ProgressConfigurator'
import NylasBase from './Nylas/NylasBase'
import NylasConfigurator from './Nylas/NylasConfigurator'
/**
* List of all known page block components
@@ -69,6 +71,8 @@ const Registry = {
CommentConfigurator,
ProgressBase,
ProgressConfigurator,
NylasBase,
NylasConfigurator,
}
const defaultMode = 'Base'
+43
View File
@@ -1095,6 +1095,44 @@
consola "^2.15.0"
node-fetch "^2.6.1"
"@nylas/components-agenda@^1.1.7-canary.6":
version "1.1.7-canary.6"
resolved "https://registry.yarnpkg.com/@nylas/components-agenda/-/components-agenda-1.1.7-canary.6.tgz#5e4b83b466b2de7e8aa72b315473d9adf1f63e88"
integrity sha512-L8bapefbzDsGpjkJGFYF9tgGdJlWPgpJlJsdqtU1Gssuy42fTB3/h0APIaPNV57DAGnd4OJpaWt0mraVky+LNA==
dependencies:
dompurify "^2.3.3"
"@nylas/components-composer@^1.1.6-canary.20":
version "1.1.6-canary.20"
resolved "https://registry.yarnpkg.com/@nylas/components-composer/-/components-composer-1.1.6-canary.20.tgz#6c33ee5faba822bc7957dbcab982b659e837a294"
integrity sha512-Tgd79o3qvnFvtk6omgePrwVIePPvAmrZ3k+mWq5vPzY8n21wo5tbXxoalJbEqIeKbrGz918PDwqNkoitwbqa9Q==
"@nylas/components-contact-list@^1.1.4-canary.6":
version "1.1.4-canary.6"
resolved "https://registry.yarnpkg.com/@nylas/components-contact-list/-/components-contact-list-1.1.4-canary.6.tgz#3421ad88912131f71c4fe97194153d6a2393e650"
integrity sha512-czCSEWk1CJo4yDHiGCM8xjkKwA6u1+obR4yDkiIhDJSoFX6TVib+oFHXrNfVRnucV20GkZD4a7H6h6BhKf7T7Q==
"@nylas/components-conversation@^1.1.6-canary.6":
version "1.1.6-canary.6"
resolved "https://registry.yarnpkg.com/@nylas/components-conversation/-/components-conversation-1.1.6-canary.6.tgz#fe15b960f35a207b98efa70f451ec4aec2a65d91"
integrity sha512-LpXvVJPjh+/YPFQCyKToZdJU3ylGrbbMqkQcNhRNQKN+LoYHGyjrmEYVSL/hp3Lcta5SFXlquQtK2wZlIUuz4Q==
dependencies:
dompurify "^2.3.3"
"@nylas/components-email@^1.1.7-canary.32":
version "1.1.7-canary.32"
resolved "https://registry.yarnpkg.com/@nylas/components-email/-/components-email-1.1.7-canary.32.tgz#feb9b801a399c59408af06b44f90a7cc30d2c47c"
integrity sha512-LaFWCYbMjPXQTL+n/T7fWtoogy4HmL38/0agl0nspHxIS5Eegw5L5QxRSrktWBZD+bh0tilP41/fia6zf+VF2g==
dependencies:
dompurify "^2.3.3"
"@nylas/components-mailbox@^1.1.6-canary.27":
version "1.1.6-canary.27"
resolved "https://registry.yarnpkg.com/@nylas/components-mailbox/-/components-mailbox-1.1.6-canary.27.tgz#44bc96b7d50adfcc82c8be21bd8303b421e1b68b"
integrity sha512-dfH05mBnxLf74tJKXB4/lPq58v8ecdjyQdEXNElM7fV9xT+Ua+lD4Mi/owshOLgo/r4wvFF7K/jStPr/m27NQg==
dependencies:
dompurify "^2.3.3"
"@panter/vue-i18next@^0.15.0":
version "0.15.2"
resolved "https://registry.yarnpkg.com/@panter/vue-i18next/-/vue-i18next-0.15.2.tgz#814f6774237e444eb9b69156e9c507d41b7fbd32"
@@ -4256,6 +4294,11 @@ domhandler@^2.3.0:
dependencies:
domelementtype "1"
dompurify@^2.3.3:
version "2.4.1"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.1.tgz#f9cb1a275fde9af6f2d0a2644ef648dd6847b631"
integrity sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==
domutils@^1.5.1, domutils@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
@@ -14,6 +14,7 @@ export { PageBlockMetric } from './metric'
export { PageBlockComment } from './comment'
export { PageBlockReport } from './report'
export { PageBlockProgress } from './progress'
export { PageBlockNylas } from './nylas'
export function PageBlockMaker<T extends PageBlock> (i: { kind: string }): T {
const PageBlockTemp = Registry.get(i.kind)
@@ -0,0 +1,33 @@
import { PageBlock, PageBlockInput, Registry } from './base'
import { Apply } from '../../../cast'
const kind = 'Nylas'
interface Options {
kind: string,
componentID: string;
}
const defaults: Readonly<Options> = Object.freeze({
kind: 'Composer', // Default kind of nylas component
componentID: '',
})
export class PageBlockNylas extends PageBlock {
readonly kind = kind
options: Options = { ...defaults }
constructor (i?: PageBlockInput) {
super(i)
this.applyOptions(i?.options as Partial<Options>)
}
applyOptions (o?: Partial<Options>): void {
if (!o) return
Apply(this.options, o, String, 'kind', 'componentID')
}
}
Registry.set(kind, PageBlockNylas)
@@ -56,9 +56,9 @@ editor:
provider: Provider
info: Issuer, client ID
standard:
enabled: Enabled
apiAccess: Api access
clientKey: Client key
clientSecret: Secret
@@ -538,3 +538,25 @@ progress:
secondary: Secondary
success: Success
warning: Warning
nylas:
label: Nylas Component
viewer:
connect: Connect with Nylas
noExternal: Nylas external provider is not configured
noComponentID: Nylas component ID is not configured
configurator:
label: Nylas
kind: Component kind
componentID: Component ID
kinds:
agenda: Agenda
composer: Composer
contactList: Contact List
conversation: Conversation
email: Email
mailbox: Mailbox