MS Teams integrations

This commit is contained in:
2026-06-07 23:32:31 -05:00
parent 3b56fb5c61
commit c164395915
8 changed files with 416 additions and 3 deletions

View File

@@ -0,0 +1,133 @@
<template>
<v-card class="span-12 panel-pad">
<h2 class="section-title mb-1">Microsoft Teams</h2>
<p class="quiet text-body-2 mb-3">
Post newly raised alerts to a Teams channel or chat via an incoming webhook. One digest card is sent per alert
cycle, alongside (or instead of) email. Create the webhook in Teams with a
<strong>Workflows</strong> "post to a channel when a webhook request is received" flow (recommended), or a legacy
<strong>Incoming Webhook</strong> connector, then paste the URL below.
</p>
<div class="form-grid">
<v-switch v-model="form.teams_enabled" label="Enable Teams delivery" color="primary" density="compact" hide-details />
<div />
<v-text-field
v-model="form.teams_webhook_url"
class="full"
label="Teams webhook URL"
placeholder="https://prod-00.westus.logic.azure.com:443/workflows/…/triggers/manual/paths/invoke?…"
type="url"
autocomplete="off"
/>
<v-select
v-model="form.teams_format"
:items="formatItems"
item-title="title"
item-value="value"
label="Card format"
hint="Adaptive Card for Workflows webhooks; MessageCard for legacy connectors"
persistent-hint
/>
<v-select
v-model="form.teams_min_severity"
:items="severityItems"
item-title="title"
item-value="value"
label="Minimum severity to post"
hint="Lower-severity alerts are skipped to keep the channel focused"
persistent-hint
/>
</div>
<div class="toolbar-row mt-3">
<v-btn variant="tonal" prepend-icon="mdi-microsoft-teams" :loading="testing" :disabled="!form.teams_webhook_url" @click="sendTest">Send test card</v-btn>
<v-spacer />
<v-btn color="primary" prepend-icon="mdi-content-save" :loading="saving" @click="save">Save Teams settings</v-btn>
</div>
<v-alert v-if="status" class="mt-3" density="compact" :type="statusType">{{ status }}</v-alert>
</v-card>
</template>
<script>
import { apiRequest } from '../services/api';
export default {
props: {
token: { type: String, required: true }
},
data() {
return {
form: {
teams_enabled: false,
teams_webhook_url: '',
teams_format: 'adaptive',
teams_min_severity: 'warning'
},
formatItems: [
{ title: 'Adaptive Card (Workflows)', value: 'adaptive' },
{ title: 'MessageCard (legacy connector)', value: 'messagecard' }
],
severityItems: [
{ title: 'Info and above (all alerts)', value: 'info' },
{ title: 'Warning and above', value: 'warning' },
{ title: 'Critical only', value: 'critical' }
],
saving: false,
testing: false,
status: '',
statusType: 'success'
};
},
mounted() {
this.load();
},
methods: {
async api(path, options = {}) {
return apiRequest(path, this.token, options);
},
async load() {
const data = await (await this.api('/api/teams/settings')).json();
this.form = {
teams_enabled: data.settings.teams_enabled,
teams_webhook_url: data.settings.teams_webhook_url,
teams_format: data.settings.teams_format,
teams_min_severity: data.settings.teams_min_severity
};
},
async save() {
this.saving = true;
this.status = '';
try {
const data = await (await this.api('/api/teams/settings', { method: 'PUT', body: JSON.stringify(this.form) })).json();
this.form = {
teams_enabled: data.settings.teams_enabled,
teams_webhook_url: data.settings.teams_webhook_url,
teams_format: data.settings.teams_format,
teams_min_severity: data.settings.teams_min_severity
};
this.statusType = 'success';
this.status = 'Teams settings saved.';
} catch (error) {
this.statusType = 'error';
this.status = error.message;
} finally {
this.saving = false;
}
},
async sendTest() {
this.testing = true;
this.status = '';
try {
// Persist the current URL/format first so the test hits what the user typed.
await this.save();
const result = await (await this.api('/api/teams/test', { method: 'POST', body: JSON.stringify({}) })).json();
this.statusType = 'success';
this.status = `Test card posted to Teams (HTTP ${result.status}).`;
} catch (error) {
this.statusType = 'error';
this.status = `Test failed: ${error.message}`;
} finally {
this.testing = false;
}
}
}
};
</script>

View File

@@ -215,6 +215,8 @@
<WebhookSettings :token="token" />
<TeamsSettings :token="token" />
<ServiceNowSettings :token="token" />
<v-card class="span-12 panel-pad">
@@ -304,10 +306,11 @@ import PartCategorySettings from '../components/PartCategorySettings.vue';
import PmCategorySettings from '../components/PmCategorySettings.vue';
import PmSettings from '../components/PmSettings.vue';
import ServiceNowSettings from '../components/ServiceNowSettings.vue';
import TeamsSettings from '../components/TeamsSettings.vue';
import WebhookSettings from '../components/WebhookSettings.vue';
export default {
components: { AssetClassSettings, AssetIdTemplateSettings, AuditTrailSettings, CategorySettings, DataTable, DepartmentSettings, DepreciationZoneSettings, NotificationSettings, PartCategorySettings, PasswordPolicySettings, PmCategorySettings, PmSettings, Section179LimitSettings, ServiceNowSettings, WebhookSettings },
components: { AssetClassSettings, AssetIdTemplateSettings, AuditTrailSettings, CategorySettings, DataTable, DepartmentSettings, DepreciationZoneSettings, NotificationSettings, PartCategorySettings, PasswordPolicySettings, PmCategorySettings, PmSettings, Section179LimitSettings, ServiceNowSettings, TeamsSettings, WebhookSettings },
props: {
token: { type: String, default: '' },
section: { type: String, default: 'admin-users' },