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
4 changes: 1 addition & 3 deletions common/config/rush/pnpm-lock.yaml

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

34 changes: 34 additions & 0 deletions packages/integration-client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,4 +337,38 @@ export class IntegrationClientImpl implements IntegrationClient {
await this.client.addIntegrationSecret(data)
}
}

async setIntegrationEnabled (integrationKey: IntegrationKey, enabled: boolean): Promise<void> {
try {
const integration = await this.client.getIntegration(integrationKey)
if (integration == null) {
throw new Error(`Integration not found: ${JSON.stringify(integrationKey)}`)
}

const data = {
...integration.data,
disabled: !enabled
}

await this.client.updateIntegration({
...integration,
data
})

const eventData: IntegrationEventData = {
integration: { ...integration, data },
timestamp: Date.now()
}
this.emit('integration:updated', eventData)
} catch (error) {
const errorData: IntegrationErrorData = {
operation: 'setIntegrationEnabled',
error: error instanceof Error ? error.message : String(error),
integrationKey,
timestamp: Date.now()
}
this.emit('integration:error', errorData)
throw error
}
}
}
5 changes: 5 additions & 0 deletions packages/integration-client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ export interface IntegrationClient {
* Set or update integration secret
*/
setSecret: (data: IntegrationSecret) => Promise<void>

/**
* Disable or enable an integration
*/
setIntegrationEnabled: (integrationKey: IntegrationKey, enabled: boolean) => Promise<void>
}

export interface IntegrationEventData {
Expand Down
15 changes: 15 additions & 0 deletions packages/integration-client/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
//

import { Integration } from '@hcengineering/account-client'
import platform, { PlatformError } from '@hcengineering/platform'
import { IntegrationEventData } from './types'

export function isWorkspaceIntegration (integration: Integration): boolean {
Expand All @@ -34,3 +35,17 @@ export function isSameIntegrationEvent (event: IntegrationEventData, integration
export function getIntegrationConfig (integration: Integration): Record<string, any> | undefined {
return integration?.data?.config
}

export function isDisabled (integration: Integration): boolean {
return integration?.data?.disabled === true
}

export function isUnauthorizedError (error: any): boolean {
if (error instanceof PlatformError && error.status.code === platform.status.Unauthorized) {
return true
}
if (error?.status === 401 || error?.status?.code === 401) {
return true
}
return false
}
8 changes: 8 additions & 0 deletions packages/theme/styles/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,10 @@
--theme-label-blue-bg-color: rgba(59, 130, 246, .08);
--theme-label-blue-border-color: rgba(59, 130, 246, .2);

--theme-label-orange-color: rgba(249, 115, 22, .8);
--theme-label-orange-bg-color: rgba(249, 115, 22, .08);
--theme-label-orange-border-color: rgba(249, 115, 22, .2);

--theme-label-gray-color: rgba(255, 255, 255, .6);
--theme-label-gray-bg-color: rgba(255, 255, 255, .02);
--theme-label-gray-border-color: rgba(255, 255, 255, .09);
Expand Down Expand Up @@ -718,6 +722,10 @@
--theme-label-blue-bg-color: rgba(59, 130, 246, .08);
--theme-label-blue-border-color: rgba(59, 130, 246, .15);

--theme-label-orange-color: rgba(194, 65, 12, 0.9);
--theme-label-orange-bg-color: rgba(249, 115, 22, .08);
--theme-label-orange-border-color: rgba(249, 115, 22, .15);

--theme-label-gray-color: rgba(0, 0, 0, .6);
--theme-label-gray-bg-color: rgba(0, 0, 0, .02);
--theme-label-gray-border-color: rgba(0, 0, 0, .09);
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@
"ServiceIsUnavailable": "Služba není k dispozici",
"Integrated": "Integrované",
"Connected": "Připojené",
"Disconnected": "Odpojené",
"Available": "Dostupné",
"NotConnectedIntegration": "Účet {account} není integrován s pracovním prostorem",
"IntegrationIsUnstable": "Integrační služba má problémy. Některé funkce nemusí fungovat správně.",
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
"ServiceIsUnavailable": "Dienst ist nicht verfügbar",
"Integrated": "Integriert",
"Connected": "Verbunden",
"Disconnected": "Getrennt",
"Available": "Verfügbar",
"NotConnectedIntegration": "Das Konto {account} ist nicht mit dem Arbeitsbereich integriert",
"IntegrationIsUnstable": "Der Integrationsdienst hat Probleme. Einige Funktionen funktionieren möglicherweise nicht richtig.",
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
"ServiceIsUnavailable": "Service is unavailable",
"Integrated": "Integrated",
"Connected": "Connected",
"Disconnected": "Disconnected",
"Available": "Available",
"NotConnectedIntegration": "The account {account} is not integrated with the workspace",
"IntegrationIsUnstable": "Integration service is experiencing issues. Some features may not work properly.",
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
"ServiceIsUnavailable": "El servicio no está disponible",
"Integrated": "Integrado",
"Connected": "Conectado",
"Disconnected": "Desconectado",
"Available": "Disponible",
"NotConnectedIntegration": "La cuenta {account} no está integrada con el espacio de trabajo",
"IntegrationIsUnstable": "El servicio de integración está experimentando problemas. Es posible que algunas funciones no funcionen correctamente.",
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
"ServiceIsUnavailable": "Le service n'est pas disponible",
"Integrated": "Intégré",
"Connected": "Connecté",
"Disconnected": "Déconnecté",
"Available": "Disponible",
"NotConnectedIntegration": "Le compte {account} n'est pas intégré au workspace",
"IntegrationIsUnstable": "Le service d'intégration rencontre des problèmes. Certaines fonctionnalités peuvent ne pas fonctionner correctement.",
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
"ServiceIsUnavailable": "Il servizio non è disponibile",
"Integrated": "Integrato",
"Connected": "Connesso",
"Disconnected": "Disconnesso",
"Available": "Disponibile",
"NotConnectedIntegration": "L'account {account} non è integrato con il workspace",
"IntegrationIsUnstable": "L'integrazione è instabile. Alcune funzionalità potrebbero non funzionare correttamente.",
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
"ServiceIsUnavailable": "サービスは利用できません",
"Integrated": "統合済み",
"Connected": "接続済み",
"Disconnected": "切断済み",
"Available": "利用可能",
"NotConnectedIntegration": "アカウント {account} はワークスペースに統合されていません",
"IntegrationIsUnstable": "統合サービスに問題が発生しています。一部の機能が正しく動作しない可能性があります。",
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
"ServiceIsUnavailable": "Serviço indisponível",
"Integrated": "Integrado",
"Connected": "Conectado",
"Disconnected": "Desconectado",
"Available": "Disponível",
"NotConnectedIntegration": "A conta {account} não está integrada com o espaço de trabalho",
"IntegrationIsUnstable": "O serviço de integração está enfrentando problemas. Algumas funcionalidades podem não funcionar corretamente."
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
"ServiceIsUnavailable": "Сервис недоступен",
"Integrated": "Интегрировано",
"Connected": "Подключено",
"Disconnected": "Отключено",
"Available": "Доступно",
"NotConnectedIntegration": "Учетная запись {account} не интегрирована с рабочим пространством",
"IntegrationIsUnstable": "Сервис интеграции испытывает проблемы. Некоторые функции могут работать некорректно."
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
"ServiceIsUnavailable": "Servis kullanılamıyor",
"Integrated": "Entegre",
"Connected": "Bağlandı",
"Disconnected": "Bağlantı Kesildi",
"Available": "Kullanılabilir",
"NotConnectedIntegration": "{account} hesabı çalışma alanıyla entegre değil",
"IntegrationIsUnstable": "Entegrasyon servisi sorunlar yaşıyor. Bazı özellikler düzgün çalışmayabilir.",
Expand Down
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
"ServiceIsUnavailable": "服务不可用",
"Integrated": "已集成",
"Connected": "已连接",
"Disconnected": "已断开",
"Available": "可用",
"NotConnectedIntegration": "帐户 {account} 未与工作区集成",
"IntegrationIsUnstable": "集成服务出现问题。某些功能可能无法正常工作。",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@
// limitations under the License.
-->
<script lang="ts">
import { onMount, onDestroy } from 'svelte'
import { fade } from 'svelte/transition'
import { getCurrentAccount } from '@hcengineering/core'
import { getResource, translate } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation'
import type { IntegrationType } from '@hcengineering/setting'
import {
AnyComponent,
Expand All @@ -32,16 +31,49 @@
} from '@hcengineering/ui'
import { Analytics } from '@hcengineering/analytics'
import { type Integration } from '@hcengineering/account-client'
import {
IntegrationClient,
isDisabled,
onIntegrationEvent,
IntegrationUpdatedData
} from '@hcengineering/integration-client'
import IntegrationErrorNotification from './IntegrationErrorNotification.svelte'
import { getIntegrationClient } from '../../utils'

import IntegrationLabel from './IntegrationLabel.svelte'
import setting from '../../plugin'

export let integrationType: IntegrationType
export let integration: Integration | undefined
const client = getClient()
let integrationClient: IntegrationClient | undefined

let isDisconnecting = false
const unsubscribers: (() => void)[] = []

onMount(async () => {
integrationClient = await getIntegrationClient(integrationType.kind)
subscribe()
})

onDestroy(() => {
unsubscribers.forEach((unsubscribe) => {
unsubscribe()
})
})

function subscribe (): void {
unsubscribers.push(onIntegrationEvent<IntegrationUpdatedData>('integration:updated', onUpdateIntegration))
}

function onUpdateIntegration (data: IntegrationUpdatedData): void {
if (
integration !== undefined &&
data.integration?.socialId === integration.socialId &&
data.integration?.workspaceUuid === integration.workspaceUuid
) {
integration = { ...integration, ...data.integration }
}
}

async function close (res: any): Promise<void> {
/* TODO: if (res?.value && integration !== undefined) {
Expand All @@ -53,17 +85,8 @@
}

async function reconnect (res: any): Promise<void> {
if (res?.value) {
const current = await client.findOne(setting.class.Integration, {
createdBy: { $in: getCurrentAccount().socialIds },
type: integrationType._id
})
if (current === undefined) return
Analytics.handleEvent(`Reconnect integration: ${await translate(integrationType.label, {}, 'en')}`)
await client.update(current, {
disabled: false,
value: res.value
})
if (res?.connected === true && integration !== undefined) {
await integrationClient?.setIntegrationEnabled(integration, true)
}
}

Expand Down Expand Up @@ -126,8 +149,8 @@
Analytics.handleEvent(`Configure/create integration: ${await translate(integrationType.label, {}, 'en')}`)
showPopup(component, { integration }, 'top', close)
}
const handleReconnect = (e: any) => {
if (integrationType.reconnectComponent) {
const handleReconnect = (e: any): void => {
if (integrationType.reconnectComponent !== undefined) {
showPopup(integrationType.reconnectComponent, { integration }, eventToHTMLElement(e), reconnect)
}
}
Expand Down Expand Up @@ -177,7 +200,15 @@
on:click={(ev) => handleConfigure(integrationType.createComponent)}
/>
{:else if integration !== undefined}
{#if integrationType.configureComponent !== undefined && integration.workspaceUuid != null}
{#if isDisabled(integration) && integrationType.reconnectComponent !== undefined}
<Button
label={setting.string.Reconnect}
minWidth={'5rem'}
kind={'primary'}
disabled={isDisconnecting}
on:click={handleReconnect}
/>
{:else if integrationType.configureComponent !== undefined && integration.workspaceUuid != null}
<Button
label={setting.string.Configure}
minWidth={'5rem'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,50 @@
import { IntlString } from '@hcengineering/platform'
import setting from '@hcengineering/setting'
import { Label } from '@hcengineering/ui'
import { isDisabled } from '@hcengineering/integration-client'

export let integration: Integration | undefined

function getIntegrationLabel (): IntlString {
type IntegrationStatus = 'available' | 'disconnected' | 'connected' | 'integrated'

function getIntegrationStatus (integration: Integration | undefined): IntegrationStatus {
if (integration === undefined) {
return setting.string.Available
return 'available'
}
if (isDisabled(integration)) {
return 'disconnected'
}
if (integration.workspaceUuid == null) {
return setting.string.Connected
return 'connected'
}
return 'integrated'
}

function getIntegrationLabel (status: IntegrationStatus): IntlString {
switch (status) {
case 'available':
return setting.string.Available
case 'disconnected':
return setting.string.Disconnected
case 'connected':
return setting.string.Connected
case 'integrated':
return setting.string.Integrated
}
return setting.string.Integrated
}

$: status = getIntegrationStatus(integration)
$: label = getIntegrationLabel(status)
</script>

<span
class="integration-label"
class:new-connection={integration === undefined}
class:connected={integration !== undefined && integration.workspaceUuid == null}
class:integrated={integration?.workspaceUuid != null}
class:available={status === 'available'}
class:disconnected={status === 'disconnected'}
class:connected={status === 'connected'}
class:integrated={status === 'integrated'}
>
<Label label={getIntegrationLabel()} />
<Label {label} />
</span>

<style>
Expand All @@ -52,12 +75,18 @@
border: 1px solid;
}

.new-connection {
.available {
background-color: var(--theme-label-gray-bg-color);
color: var(--theme-label-gray-color);
border-color: var(--theme-label-gray-border-color);
}

.disconnected {
background-color: var(--theme-label-orange-bg-color);
color: var(--theme-label-orange-color);
border-color: var(--theme-label-orange-border-color);
}

.connected {
background-color: var(--theme-label-blue-bg-color);
color: var(--theme-label-blue-color);
Expand Down
Loading
Loading