mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 06:37:15 +00:00
feat: Teams communication adapter (#4968)
Co-authored-by: Dimitri POSTOLOV <en3m@ya.ru> Co-authored-by: Kamil Kisiela <kamil.kisiela@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
eec6c9c15d
commit
e74722d9d9
33 changed files with 731 additions and 476 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -130,6 +130,7 @@ packages/web/app/environment-*.mjs
|
|||
packages/web/app/src/gql/*.ts
|
||||
packages/web/app/src/gql/*.json
|
||||
packages/web/app/src/graphql/*.ts
|
||||
packages/web/docs/public/feed.xml
|
||||
# Changelog
|
||||
packages/web/app/src/components/ui/changelog/generated-changelog.ts
|
||||
|
||||
|
|
@ -142,6 +143,4 @@ deployment/utils/contour.types.ts
|
|||
schema.graphql
|
||||
resolvers.generated.ts
|
||||
|
||||
# generated by tsup
|
||||
configs/tsup/dev.config.*.mjs
|
||||
packages/web/docs/public/feed.xml
|
||||
docker/docker-compose.override.yml
|
||||
|
|
|
|||
1
.nvmrc
Normal file
1
.nvmrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
v22
|
||||
15
README.md
15
README.md
|
|
@ -1,3 +1,11 @@
|
|||
<!-- Graphql logo readme banner START -->
|
||||
<p style="float: right; margin: 0 0 10px 10px;">
|
||||
<a href="https://the-guild.dev">
|
||||
<img src="https://the-guild-org.github.io/press-kit/full-dark-logo.svg" alt="Created by The guild" style="width: 100px;"/>
|
||||
</a>
|
||||
</p>
|
||||
<!-- Graphql logo readme banner END -->
|
||||
|
||||
# GraphQL Hive
|
||||
|
||||
GraphQL Hive provides all the tools the get visibility of your GraphQL architecture at all stages,
|
||||
|
|
@ -51,10 +59,11 @@ GraphQL Hive helps you get a global overview of the usage of your GraphQL API wi
|
|||
|
||||
### Integrations
|
||||
|
||||
GraphQL Hive is well integrated with **Slack** and most **CI/CD** systems to get you up and running
|
||||
as smoothly as possible!
|
||||
GraphQL Hive is well integrated with **Slack**, **MS Teams** and most **CI/CD** systems to get you
|
||||
up and running as smoothly as possible!
|
||||
|
||||
GraphQL Hive can notify your team when schema changes occur, either via Slack or a custom webhook.
|
||||
GraphQL Hive can notify your team when schema changes occur, either via Slack, MS Teams or a custom
|
||||
webhook.
|
||||
|
||||
Also, the Hive CLI allows integration of the schema checks mechanism to all CI/CD systems (GitHub,
|
||||
BitBucket, Azure, and others). The same applies to schema publishing and operations checks.
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ const config: CodegenConfig = {
|
|||
AlertChannel: '../modules/alerts/module.graphql.mappers#AlertChannelMapper',
|
||||
AlertSlackChannel: '../modules/alerts/module.graphql.mappers#AlertSlackChannelMapper',
|
||||
AlertWebhookChannel: '../modules/alerts/module.graphql.mappers#AlertWebhookChannelMapper',
|
||||
TeamsWebhookChannel: '../modules/alerts/module.graphql.mappers#TeamsWebhookChannelMapper',
|
||||
Alert: '../modules/alerts/module.graphql.mappers#AlertMapper',
|
||||
AdminQuery: '../modules/admin/module.graphql.mappers#AdminQueryMapper',
|
||||
AdminStats: '../modules/admin/module.graphql.mappers#AdminStatsMapper',
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@
|
|||
Developing Hive locally requires you to have the following software installed locally:
|
||||
|
||||
- Node.js 21 (or `nvm` or `fnm`)
|
||||
- pnpm v8
|
||||
- Docker
|
||||
- pnpm v9
|
||||
- Docker version 26.1.1 or later(previous versions will not work correctly on arm64)
|
||||
- make sure these ports are free: 5432, 6379, 9000, 9001, 8123, 9092, 8081, 8082, 9644, 3567, 7043
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
"build:web": "pnpm prebuild && pnpm turbo build --filter=./packages/web/* --color",
|
||||
"cargo:fix": "bash ./scripts/fix-symbolic-link.sh",
|
||||
"docker:build": "docker buildx bake -f docker/docker.hcl --load build",
|
||||
"docker:override-up": "docker compose -f ./docker/docker-compose.override.yml up -d --remove-orphans",
|
||||
"env:sync": "tsx scripts/sync-env-files.ts",
|
||||
"generate": "pnpm --filter @hive/storage db:generate && pnpm graphql:generate",
|
||||
"graphql:generate": "graphql-codegen --config codegen.mts",
|
||||
|
|
@ -33,7 +34,7 @@
|
|||
"lint:env-template": "tsx scripts/check-env-template.ts",
|
||||
"lint:fix": "pnpm lint --fix",
|
||||
"lint:prettier": "prettier --cache --check .",
|
||||
"local:setup": "docker-compose -f ./docker/docker-compose.dev.yml up -d --remove-orphans && pnpm --filter @hive/migrations db:init",
|
||||
"local:setup": "docker compose -f ./docker/docker-compose.dev.yml up -d --remove-orphans && pnpm --filter @hive/migrations db:init",
|
||||
"postinstall": "node ./scripts/patch-manifests.js && pnpm env:sync && node ./scripts/turborepo-cleanup.js && pnpm cargo:fix",
|
||||
"pre-commit": "exit 0 && lint-staged",
|
||||
"prebuild": "rimraf deploy-tmp && rimraf packages/**/deploy-tmp",
|
||||
|
|
|
|||
19
packages/libraries/cli/examples/single.with.mutation.graphql
Normal file
19
packages/libraries/cli/examples/single.with.mutation.graphql
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
type Query {
|
||||
foo: Int!
|
||||
bar: String
|
||||
test: String
|
||||
last: Boolean
|
||||
fooTwo: Int!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
addFooAnother(foo: Int!): Int!
|
||||
addBar(bar: String): String
|
||||
addTest(test: String): String
|
||||
}
|
||||
|
||||
schema {
|
||||
query: Query
|
||||
mutation: Mutation
|
||||
}
|
||||
# test 3
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { type MigrationExecutor } from '../pg-migrator';
|
||||
|
||||
export default {
|
||||
name: '2024.06.11T10-10-00.ms-teams-webhook.ts',
|
||||
run: ({ sql }) => sql`
|
||||
ALTER TYPE alert_channel_type ADD VALUE 'MSTEAMS_WEBHOOK';
|
||||
`,
|
||||
} satisfies MigrationExecutor;
|
||||
|
|
@ -63,6 +63,7 @@ import migration_2024_01_12_01T00_00_00_contracts from './actions/2024.01.26T00.
|
|||
import migration_2024_01_12_01T00_00_00_schema_check_pagination_index_update from './actions/2024.01.26T00.00.01.schema-check-pagination-index-update';
|
||||
import migration_2024_02_19_01T00_00_00_schema_check_store_breaking_change_metadata from './actions/2024.02.19T00.00.01.schema-check-store-breaking-change-metadata';
|
||||
import migration_2024_04_09T10_10_00_check_approval_comment from './actions/2024.04.09T10-10-00.check-approval-comment';
|
||||
import migration_2024_06_11T10_10_00_ms_teams_webhook from './actions/2024.06.11T10-10-00.ms-teams-webhook';
|
||||
import { runMigrations } from './pg-migrator';
|
||||
|
||||
export const runPGMigrations = (args: { slonik: DatabasePool; runTo?: string }) =>
|
||||
|
|
@ -134,5 +135,6 @@ export const runPGMigrations = (args: { slonik: DatabasePool; runTo?: string })
|
|||
migration_2024_01_12_01T00_00_00_schema_check_pagination_index_update,
|
||||
migration_2024_02_19_01T00_00_00_schema_check_store_breaking_change_metadata,
|
||||
migration_2024_04_09T10_10_00_check_approval_comment,
|
||||
migration_2024_06_11T10_10_00_ms_teams_webhook,
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
"slonik": "30.4.4",
|
||||
"supertokens-node": "15.2.1",
|
||||
"tslib": "2.6.3",
|
||||
"vitest": "1.6.0",
|
||||
"zod": "3.23.8",
|
||||
"zod-validation-error": "3.3.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { createModule } from 'graphql-modules';
|
||||
import { TeamsCommunicationAdapter } from './providers/adapters/msteams';
|
||||
import { SlackCommunicationAdapter } from './providers/adapters/slack';
|
||||
import { WebhookCommunicationAdapter } from './providers/adapters/webhook';
|
||||
import { AlertsManager } from './providers/alerts-manager';
|
||||
|
|
@ -10,5 +11,10 @@ export const alertsModule = createModule({
|
|||
dirname: __dirname,
|
||||
typeDefs,
|
||||
resolvers,
|
||||
providers: [AlertsManager, SlackCommunicationAdapter, WebhookCommunicationAdapter],
|
||||
providers: [
|
||||
AlertsManager,
|
||||
SlackCommunicationAdapter,
|
||||
WebhookCommunicationAdapter,
|
||||
TeamsCommunicationAdapter,
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ import type { Alert, AlertChannel } from '../../shared/entities';
|
|||
export type AlertChannelMapper = AlertChannel;
|
||||
export type AlertSlackChannelMapper = AlertChannel;
|
||||
export type AlertWebhookChannelMapper = AlertChannel;
|
||||
export type TeamsWebhookChannelMapper = AlertChannel;
|
||||
export type AlertMapper = Alert;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export default gql`
|
|||
enum AlertChannelType {
|
||||
SLACK
|
||||
WEBHOOK
|
||||
MSTEAMS_WEBHOOK
|
||||
}
|
||||
|
||||
enum AlertType {
|
||||
|
|
@ -140,6 +141,13 @@ export default gql`
|
|||
endpoint: String!
|
||||
}
|
||||
|
||||
type TeamsWebhookChannel implements AlertChannel {
|
||||
id: ID!
|
||||
name: String!
|
||||
type: AlertChannelType!
|
||||
endpoint: String!
|
||||
}
|
||||
|
||||
type Alert {
|
||||
id: ID!
|
||||
type: AlertType!
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ import type {
|
|||
Target,
|
||||
} from '../../../../shared/entities';
|
||||
|
||||
interface NotificationIntegrations {
|
||||
slack: {
|
||||
token: string | null | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SchemaChangeNotificationInput {
|
||||
event: {
|
||||
organization: Pick<Organization, 'id' | 'cleanId' | 'name'>;
|
||||
|
|
@ -25,11 +31,7 @@ export interface SchemaChangeNotificationInput {
|
|||
};
|
||||
alert: Alert;
|
||||
channel: AlertChannel;
|
||||
integrations: {
|
||||
slack: {
|
||||
token: string;
|
||||
};
|
||||
};
|
||||
integrations: NotificationIntegrations;
|
||||
}
|
||||
|
||||
export interface ChannelConfirmationInput {
|
||||
|
|
@ -39,11 +41,7 @@ export interface ChannelConfirmationInput {
|
|||
project: Pick<Project, 'id' | 'cleanId' | 'name'>;
|
||||
};
|
||||
channel: AlertChannel;
|
||||
integrations: {
|
||||
slack: {
|
||||
token: string;
|
||||
};
|
||||
};
|
||||
integrations: NotificationIntegrations;
|
||||
}
|
||||
|
||||
export interface CommunicationAdapter {
|
||||
|
|
@ -59,9 +57,13 @@ export function quotesTransformer(msg: string, symbols = '**') {
|
|||
const findSingleQuotes = /'([^']+)'/gim;
|
||||
const findDoubleQuotes = /"([^"]+)"/gim;
|
||||
|
||||
function transformm(_: string, value: string) {
|
||||
function transform(_: string, value: string) {
|
||||
return `${symbols}${value}${symbols}`;
|
||||
}
|
||||
|
||||
return msg.replace(findSingleQuotes, transformm).replace(findDoubleQuotes, transformm);
|
||||
return msg.replace(findSingleQuotes, transform).replace(findDoubleQuotes, transform);
|
||||
}
|
||||
|
||||
export const createMDLink = ({ text, url }: { text: string; url: string }) => {
|
||||
return `[${text}](${url})`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,255 @@
|
|||
import { AlertChannel } from 'packages/services/api/src/shared/entities';
|
||||
import { vi } from 'vitest';
|
||||
import { SchemaChangeType } from '@hive/storage';
|
||||
import { ChannelConfirmationInput, SchemaChangeNotificationInput } from './common';
|
||||
import { TeamsCommunicationAdapter } from './msteams';
|
||||
|
||||
const logger = {
|
||||
child: () => ({
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
}),
|
||||
};
|
||||
|
||||
const appBaseUrl = 'app-base-url';
|
||||
const webhookUrl = 'webhook-url';
|
||||
|
||||
describe('TeamsCommunicationAdapter', () => {
|
||||
describe('sendSchemaChangeNotification', () => {
|
||||
it('should send schema change notification', async () => {
|
||||
const changes = [
|
||||
{
|
||||
id: 'id-1',
|
||||
type: 'FIELD_REMOVED',
|
||||
approvalMetadata: null,
|
||||
criticality: 'BREAKING',
|
||||
message: "Field 'addFoo' was removed from object type 'Mutation'",
|
||||
meta: {
|
||||
typeName: 'Mutation',
|
||||
removedFieldName: 'addFoo',
|
||||
isRemovedFieldDeprecated: false,
|
||||
typeType: 'object type',
|
||||
},
|
||||
path: 'Mutation.addFoo',
|
||||
isSafeBasedOnUsage: false,
|
||||
reason:
|
||||
'Removing a field is a breaking change. It is preferable to deprecate the field before removing it.',
|
||||
usageStatistics: null,
|
||||
breakingChangeSchemaCoordinate: 'Mutation.addFoo',
|
||||
},
|
||||
{
|
||||
id: 'id-2',
|
||||
type: 'FIELD_REMOVED',
|
||||
approvalMetadata: null,
|
||||
criticality: 'BREAKING',
|
||||
message: "Field 'foo3' was removed from object type 'Query'",
|
||||
meta: {
|
||||
typeName: 'Query',
|
||||
removedFieldName: 'foo3',
|
||||
isRemovedFieldDeprecated: false,
|
||||
typeType: 'object type',
|
||||
},
|
||||
path: 'Query.foo3',
|
||||
isSafeBasedOnUsage: false,
|
||||
reason:
|
||||
'Removing a field is a breaking change. It is preferable to deprecate the field before removing it.',
|
||||
usageStatistics: null,
|
||||
breakingChangeSchemaCoordinate: 'Query.foo3',
|
||||
},
|
||||
{
|
||||
id: 'id-3',
|
||||
type: 'FIELD_ADDED',
|
||||
approvalMetadata: null,
|
||||
criticality: 'NON_BREAKING',
|
||||
message: "Field 'addFooT' was added to object type 'Mutation'",
|
||||
meta: {
|
||||
typeName: 'Mutation',
|
||||
addedFieldName: 'addFooT',
|
||||
typeType: 'object type',
|
||||
},
|
||||
path: 'Mutation.addFooT',
|
||||
isSafeBasedOnUsage: false,
|
||||
reason: null,
|
||||
usageStatistics: null,
|
||||
breakingChangeSchemaCoordinate: null,
|
||||
},
|
||||
{
|
||||
id: 'id-4',
|
||||
type: 'FIELD_ADDED',
|
||||
approvalMetadata: null,
|
||||
criticality: 'NON_BREAKING',
|
||||
message: "Field 'foo4' was added to object type 'Query'",
|
||||
meta: {
|
||||
typeName: 'Query',
|
||||
addedFieldName: 'foo4',
|
||||
typeType: 'object type',
|
||||
},
|
||||
path: 'Query.foo4',
|
||||
isSafeBasedOnUsage: false,
|
||||
reason: null,
|
||||
usageStatistics: null,
|
||||
breakingChangeSchemaCoordinate: null,
|
||||
},
|
||||
] as Array<SchemaChangeType>;
|
||||
const messages = [] as string[];
|
||||
const input = {
|
||||
alert: {
|
||||
id: 'alert-id',
|
||||
type: 'SCHEMA_CHANGE_NOTIFICATIONS',
|
||||
channelId: 'channel-id',
|
||||
projectId: 'project-id',
|
||||
organizationId: 'org-id',
|
||||
createdAt: new Date().toISOString(),
|
||||
targetId: 'target-id',
|
||||
},
|
||||
integrations: {
|
||||
slack: {
|
||||
token: null,
|
||||
},
|
||||
},
|
||||
event: {
|
||||
organization: {
|
||||
id: 'org-id',
|
||||
cleanId: 'org-clean-id',
|
||||
name: '',
|
||||
},
|
||||
project: {
|
||||
id: 'project-id',
|
||||
cleanId: 'project-clean-id',
|
||||
name: 'project-name',
|
||||
},
|
||||
target: {
|
||||
id: 'target-id',
|
||||
cleanId: 'target-clean-id',
|
||||
name: 'target-name',
|
||||
},
|
||||
|
||||
changes,
|
||||
messages,
|
||||
initial: false,
|
||||
errors: [],
|
||||
schema: {
|
||||
id: 'schema-id',
|
||||
commit: 'commit',
|
||||
valid: true,
|
||||
},
|
||||
},
|
||||
channel: {
|
||||
webhookEndpoint: webhookUrl,
|
||||
} as AlertChannel,
|
||||
} as SchemaChangeNotificationInput;
|
||||
|
||||
const adapter = new TeamsCommunicationAdapter(logger as any, appBaseUrl);
|
||||
const sendTeamsMessageSpy = vi.spyOn(adapter as any, 'sendTeamsMessage');
|
||||
|
||||
await adapter.sendSchemaChangeNotification(input);
|
||||
|
||||
expect(sendTeamsMessageSpy.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
[
|
||||
webhook-url,
|
||||
🐝 Hi, I found *4 changes* in project [project-name](app-base-url/org-clean-id/project-clean-id), target [target-name](app-base-url/org-clean-id/project-clean-id/target-clean-id) ([view details](app-base-url/org-clean-id/project-clean-id/target-clean-id/history/schema-id)):
|
||||
|
||||
### Breaking changes
|
||||
- Field \`addFoo\` was removed from object type \`Mutation\`
|
||||
- Field \`foo3\` was removed from object type \`Query\`
|
||||
### Safe changes
|
||||
- Field \`addFooT\` was added to object type \`Mutation\`
|
||||
- Field \`foo4\` was added to object type \`Query\`
|
||||
,
|
||||
[view full report](app-base-url/org-clean-id/project-clean-id/target-clean-id/history/schema-id),
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
// Add more test cases here if needed
|
||||
});
|
||||
});
|
||||
describe('sendChannelConfirmation', () => {
|
||||
it('should send channel confirmation', async () => {
|
||||
const appBaseUrl = 'app-base-url';
|
||||
const webhookUrl = 'webhook-url';
|
||||
const input = {
|
||||
event: {
|
||||
organization: {
|
||||
id: 'org-id',
|
||||
cleanId: 'org-clean-id',
|
||||
},
|
||||
project: {
|
||||
id: 'project-id',
|
||||
cleanId: 'project-clean-id',
|
||||
name: 'project-name',
|
||||
},
|
||||
kind: 'created',
|
||||
},
|
||||
channel: {
|
||||
webhookEndpoint: webhookUrl,
|
||||
},
|
||||
} as ChannelConfirmationInput;
|
||||
const adapter = new TeamsCommunicationAdapter(logger as any, appBaseUrl);
|
||||
const sendTeamsMessageSpy = vi.spyOn(adapter as any, 'sendTeamsMessage');
|
||||
await adapter.sendChannelConfirmation(input);
|
||||
expect(sendTeamsMessageSpy.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
[
|
||||
webhook-url,
|
||||
👋 Hi! I'm the notification 🐝.
|
||||
I will send here notifications about your [project-name](app-base-url/org-clean-id/project-clean-id) project.,
|
||||
]
|
||||
`);
|
||||
|
||||
input.event.kind = 'deleted';
|
||||
await adapter.sendChannelConfirmation(input);
|
||||
expect(sendTeamsMessageSpy.mock.calls[1]).toMatchInlineSnapshot(`
|
||||
[
|
||||
webhook-url,
|
||||
👋 Hi! I'm the notification 🐝.
|
||||
I will no longer send here notifications about your [project-name](app-base-url/org-clean-id/project-clean-id) project.,
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
describe('sendTeamsMessage', () => {
|
||||
const adapter = new TeamsCommunicationAdapter(logger as any, appBaseUrl);
|
||||
|
||||
beforeAll(() => {
|
||||
// @ts-expect-error mocking fetch
|
||||
global.fetch = vi.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
statusText: 'OK',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('sends a message under 27k characters', async () => {
|
||||
const message = 'Short message';
|
||||
await adapter.sendTeamsMessage('http://example.com/webhook', message);
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
body: expect.stringContaining(message),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('truncates and appends link for messages over 27k characters', async () => {
|
||||
const longMessage = 'a'.repeat(27001);
|
||||
const link = 'http://example.com/fullReport';
|
||||
await adapter.sendTeamsMessage('http://example.com/webhook', longMessage, link);
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
body: expect.stringContaining('... message truncated. ' + link),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('handles failed send operation', async () => {
|
||||
// @ts-expect-error types obviously don't account for the fact this is mocked
|
||||
fetch.mockImplementationOnce(() => Promise.resolve({ ok: false, statusText: 'Bad Request' }));
|
||||
|
||||
await expect(
|
||||
adapter.sendTeamsMessage('http://example.com/webhook', 'Test message'),
|
||||
).rejects.toThrow('Failed to send Microsoft Teams message: Bad Request');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
import { Inject, Injectable } from 'graphql-modules';
|
||||
import { CriticalityLevel } from '@graphql-inspector/core';
|
||||
import { SchemaChangeType } from '@hive/storage';
|
||||
import { Logger } from '../../../shared/providers/logger';
|
||||
import { WEB_APP_URL } from '../../../shared/providers/tokens';
|
||||
import {
|
||||
ChannelConfirmationInput,
|
||||
CommunicationAdapter,
|
||||
createMDLink,
|
||||
SchemaChangeNotificationInput,
|
||||
slackCoderize,
|
||||
} from './common';
|
||||
|
||||
@Injectable()
|
||||
export class TeamsCommunicationAdapter implements CommunicationAdapter {
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
logger: Logger,
|
||||
@Inject(WEB_APP_URL) private appBaseUrl: string,
|
||||
) {
|
||||
this.logger = logger.child({ service: 'TeamsCommunicationAdapter' });
|
||||
}
|
||||
|
||||
async sendSchemaChangeNotification(input: SchemaChangeNotificationInput) {
|
||||
this.logger.debug(
|
||||
`Sending Schema Change Notifications over Microsoft Teams (organization=%s, project=%s, target=%s)`,
|
||||
input.event.organization.id,
|
||||
input.event.project.id,
|
||||
input.event.target.id,
|
||||
);
|
||||
const webhookUrl = input.channel.webhookEndpoint;
|
||||
|
||||
if (!webhookUrl) {
|
||||
this.logger.debug(`Microsoft Teams Integration is not available`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const totalChanges = input.event.changes.length + input.event.messages.length;
|
||||
const projectLink = createMDLink({
|
||||
text: input.event.project.name,
|
||||
url: `${this.appBaseUrl}/${input.event.organization.cleanId}/${input.event.project.cleanId}`,
|
||||
});
|
||||
const targetLink = createMDLink({
|
||||
text: input.event.target.name,
|
||||
url: `${this.appBaseUrl}/${input.event.organization.cleanId}/${input.event.project.cleanId}/${input.event.target.cleanId}`,
|
||||
});
|
||||
const changeUrl = `${this.appBaseUrl}/${input.event.organization.cleanId}/${input.event.project.cleanId}/${input.event.target.cleanId}/history/${input.event.schema.id}`;
|
||||
const viewLink = createMDLink({
|
||||
text: 'view details',
|
||||
url: changeUrl,
|
||||
});
|
||||
|
||||
const message = input.event.initial
|
||||
? `🐝 Hi, I received your *first* schema in project ${projectLink}, target ${targetLink} (${viewLink}):`
|
||||
: `🐝 Hi, I found *${totalChanges} ${this.pluralize(
|
||||
'change',
|
||||
totalChanges,
|
||||
)}* in project ${projectLink}, target ${targetLink} (${viewLink}):`;
|
||||
|
||||
const attachmentsText = input.event.initial
|
||||
? ''
|
||||
: createAttachmentsText(input.event.changes, input.event.messages);
|
||||
|
||||
await this.sendTeamsMessage(
|
||||
webhookUrl,
|
||||
`${message}\n\n${attachmentsText}`,
|
||||
createMDLink({
|
||||
text: 'view full report',
|
||||
url: changeUrl,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to send Microsoft Teams notification`, error);
|
||||
}
|
||||
}
|
||||
|
||||
async sendChannelConfirmation(input: ChannelConfirmationInput) {
|
||||
this.logger.debug(
|
||||
`Sending Channel Confirmation over Microsoft Teams (organization=%s, project=%s, channel=%s)`,
|
||||
input.event.organization.id,
|
||||
input.event.project.id,
|
||||
);
|
||||
|
||||
const webhookUrl = input.channel.webhookEndpoint;
|
||||
|
||||
if (!webhookUrl) {
|
||||
this.logger.debug(`Microsoft Teams Integration is not available`);
|
||||
return;
|
||||
}
|
||||
|
||||
const actionMessage =
|
||||
input.event.kind === 'created'
|
||||
? `I will send here notifications`
|
||||
: `I will no longer send here notifications`;
|
||||
|
||||
try {
|
||||
const projectLink = createMDLink({
|
||||
text: input.event.project.name,
|
||||
url: `${this.appBaseUrl}/${input.event.organization.cleanId}/${input.event.project.cleanId}`,
|
||||
});
|
||||
|
||||
const message = [
|
||||
`👋 Hi! I'm the notification 🐝.`,
|
||||
`${actionMessage} about your ${projectLink} project.`,
|
||||
].join('\n');
|
||||
|
||||
await this.sendTeamsMessage(webhookUrl, message);
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to send Microsoft Teams notification`, error);
|
||||
}
|
||||
}
|
||||
|
||||
private pluralize(word: string, num: number): string {
|
||||
return word + (num > 1 ? 's' : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* message gets truncated to max 27k characters-max payload size for Microsoft Teams is 28 KB
|
||||
*/
|
||||
async sendTeamsMessage(webhookUrl: string, message: string, fullReportMdLink?: string) {
|
||||
if (message.length > 27000) {
|
||||
message = message.slice(0, 27000) + `\n\n... message truncated. ${fullReportMdLink ?? ''}`;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
'@type': 'MessageCard',
|
||||
'@context': 'http://schema.org/extensions',
|
||||
summary: 'Notification',
|
||||
themeColor: '0076D7',
|
||||
sections: [
|
||||
{
|
||||
activityTitle: 'Notification',
|
||||
text: message,
|
||||
markdown: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to send Microsoft Teams message: ${response.statusText}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createAttachmentsText(
|
||||
changes: readonly SchemaChangeType[],
|
||||
messages: readonly string[],
|
||||
): string {
|
||||
const breakingChanges = changes.filter(
|
||||
change => change.criticality === CriticalityLevel.Breaking,
|
||||
);
|
||||
const safeChanges = changes.filter(change => change.criticality !== CriticalityLevel.Breaking);
|
||||
|
||||
let text = '';
|
||||
|
||||
if (breakingChanges.length) {
|
||||
text += renderChangeList({
|
||||
color: '#E74C3B',
|
||||
title: 'Breaking changes',
|
||||
changes: breakingChanges,
|
||||
});
|
||||
}
|
||||
|
||||
if (safeChanges.length) {
|
||||
text += renderChangeList({
|
||||
color: '#23B99A',
|
||||
title: 'Safe changes',
|
||||
changes: safeChanges,
|
||||
});
|
||||
}
|
||||
|
||||
if (messages.length) {
|
||||
text += `### Other changes\n${messages.map(message => slackCoderize(message)).join('\n')}\n`;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
function renderChangeList({
|
||||
changes,
|
||||
title,
|
||||
}: {
|
||||
color: string;
|
||||
title: string;
|
||||
changes: readonly SchemaChangeType[];
|
||||
}): string {
|
||||
const text = changes
|
||||
.map(change => {
|
||||
let text = ` - ${change.message}`;
|
||||
if (change.isSafeBasedOnUsage) {
|
||||
text += ' (safe based on usage)';
|
||||
}
|
||||
|
||||
return slackCoderize(text);
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
return `### ${title}\n${text}\n`;
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import { WEB_APP_URL } from '../../../shared/providers/tokens';
|
|||
import {
|
||||
ChannelConfirmationInput,
|
||||
CommunicationAdapter,
|
||||
createMDLink,
|
||||
SchemaChangeNotificationInput,
|
||||
slackCoderize,
|
||||
} from './common';
|
||||
|
|
@ -43,15 +44,15 @@ export class SlackCommunicationAdapter implements CommunicationAdapter {
|
|||
const client = new WebClient(input.integrations.slack.token, {});
|
||||
|
||||
const totalChanges = input.event.changes.length + input.event.messages.length;
|
||||
const projectLink = this.createLink({
|
||||
const projectLink = createMDLink({
|
||||
text: input.event.project.name,
|
||||
url: `${this.appBaseUrl}/${input.event.organization.cleanId}/${input.event.project.cleanId}`,
|
||||
});
|
||||
const targetLink = this.createLink({
|
||||
const targetLink = createMDLink({
|
||||
text: input.event.target.name,
|
||||
url: `${this.appBaseUrl}/${input.event.organization.cleanId}/${input.event.project.cleanId}/${input.event.target.cleanId}`,
|
||||
});
|
||||
const viewLink = this.createLink({
|
||||
const viewLink = createMDLink({
|
||||
text: 'view details',
|
||||
url: `${this.appBaseUrl}/${input.event.organization.cleanId}/${input.event.project.cleanId}/${input.event.target.cleanId}/history/${input.event.schema.id}`,
|
||||
});
|
||||
|
|
@ -82,6 +83,9 @@ export class SlackCommunicationAdapter implements CommunicationAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* triggered when a channel is created or deleted
|
||||
*/
|
||||
async sendChannelConfirmation(input: ChannelConfirmationInput) {
|
||||
this.logger.debug(
|
||||
`Sending Channel Confirmation over Slack (organization=%s, project=%s, channel=%s)`,
|
||||
|
|
@ -90,7 +94,7 @@ export class SlackCommunicationAdapter implements CommunicationAdapter {
|
|||
input.channel.slackChannel,
|
||||
);
|
||||
|
||||
const token = input.integrations.slack.token;
|
||||
const token = input.integrations?.slack.token;
|
||||
|
||||
if (!token) {
|
||||
this.logger.debug(`Slack Integration is not available`);
|
||||
|
|
@ -103,7 +107,7 @@ export class SlackCommunicationAdapter implements CommunicationAdapter {
|
|||
: `I will no longer send here notifications`;
|
||||
|
||||
try {
|
||||
const projectLink = this.createLink({
|
||||
const projectLink = createMDLink({
|
||||
text: input.event.project.name,
|
||||
url: `${this.appBaseUrl}/${input.event.organization.cleanId}/${input.event.project.cleanId}`,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ import { ProjectManager } from '../../project/providers/project-manager';
|
|||
import { Logger } from '../../shared/providers/logger';
|
||||
import type { ProjectSelector } from '../../shared/providers/storage';
|
||||
import { Storage } from '../../shared/providers/storage';
|
||||
import { SchemaChangeNotificationInput } from './adapters/common';
|
||||
import { ChannelConfirmationInput, SchemaChangeNotificationInput } from './adapters/common';
|
||||
import { TeamsCommunicationAdapter } from './adapters/msteams';
|
||||
import { SlackCommunicationAdapter } from './adapters/slack';
|
||||
import { WebhookCommunicationAdapter } from './adapters/webhook';
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ export class AlertsManager {
|
|||
private slackIntegrationManager: SlackIntegrationManager,
|
||||
private slack: SlackCommunicationAdapter,
|
||||
private webhook: WebhookCommunicationAdapter,
|
||||
private teamsWebhook: TeamsCommunicationAdapter,
|
||||
private organizationManager: OrganizationManager,
|
||||
private projectManager: ProjectManager,
|
||||
private storage: Storage,
|
||||
|
|
@ -185,6 +187,7 @@ export class AlertsManager {
|
|||
channel: channels.find(channel => channel.id === alert.channelId)!,
|
||||
};
|
||||
});
|
||||
console.log('pairs:', pairs);
|
||||
|
||||
const slackToken = await this.slackIntegrationManager.getToken({
|
||||
organization: event.organization.id,
|
||||
|
|
@ -195,8 +198,9 @@ export class AlertsManager {
|
|||
|
||||
const integrations: SchemaChangeNotificationInput['integrations'] = {
|
||||
slack: {
|
||||
token: slackToken!,
|
||||
token: slackToken,
|
||||
},
|
||||
// ms Teams is integrated via webhook. Webhook contains the token in itself, so we don't have any other token for it
|
||||
};
|
||||
|
||||
// Let's not leak any data :)
|
||||
|
|
@ -237,6 +241,14 @@ export class AlertsManager {
|
|||
integrations,
|
||||
});
|
||||
}
|
||||
if (channel.type === 'MSTEAMS_WEBHOOK') {
|
||||
return this.teamsWebhook.sendSchemaChangeNotification({
|
||||
event: safeEvent,
|
||||
alert,
|
||||
channel,
|
||||
integrations,
|
||||
});
|
||||
}
|
||||
|
||||
return this.webhook.sendSchemaChangeNotification({
|
||||
event: safeEvent,
|
||||
|
|
@ -265,34 +277,42 @@ export class AlertsManager {
|
|||
}),
|
||||
]);
|
||||
|
||||
const channelConfirmationContext: ChannelConfirmationInput = {
|
||||
event: {
|
||||
kind: input.kind,
|
||||
organization: {
|
||||
id: organization.id,
|
||||
cleanId: organization.cleanId,
|
||||
name: organization.name,
|
||||
},
|
||||
project: {
|
||||
id: project.id,
|
||||
cleanId: project.cleanId,
|
||||
name: project.name,
|
||||
},
|
||||
},
|
||||
channel,
|
||||
integrations: {
|
||||
slack: {
|
||||
token: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (channel.type === 'SLACK') {
|
||||
const slackToken = await this.slackIntegrationManager.getToken({
|
||||
organization: organization.id,
|
||||
project: project.id,
|
||||
context: IntegrationsAccessContext.ChannelConfirmation,
|
||||
});
|
||||
if (!slackToken) {
|
||||
throw new Error(`Slack token was not found for channel "${channel.id}"`);
|
||||
}
|
||||
|
||||
await this.slack.sendChannelConfirmation({
|
||||
event: {
|
||||
kind: input.kind,
|
||||
organization: {
|
||||
id: organization.id,
|
||||
cleanId: organization.cleanId,
|
||||
name: organization.name,
|
||||
},
|
||||
project: {
|
||||
id: project.id,
|
||||
cleanId: project.cleanId,
|
||||
name: project.name,
|
||||
},
|
||||
},
|
||||
channel,
|
||||
integrations: {
|
||||
slack: {
|
||||
token: slackToken!,
|
||||
},
|
||||
},
|
||||
});
|
||||
channelConfirmationContext.integrations.slack.token = slackToken;
|
||||
await this.slack.sendChannelConfirmation(channelConfirmationContext);
|
||||
} else if (channel.type === 'MSTEAMS_WEBHOOK') {
|
||||
await this.teamsWebhook.sendChannelConfirmation(channelConfirmationContext);
|
||||
} else {
|
||||
await this.webhook.sendChannelConfirmation();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,4 +217,12 @@ export const resolvers: AlertsModule.Resolvers = {
|
|||
return channel.webhookEndpoint!;
|
||||
},
|
||||
},
|
||||
TeamsWebhookChannel: {
|
||||
__isTypeOf(channel) {
|
||||
return channel.type === 'MSTEAMS_WEBHOOK';
|
||||
},
|
||||
endpoint(channel) {
|
||||
return channel.webhookEndpoint!;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
export type alert_channel_type = 'SLACK' | 'WEBHOOK';
|
||||
export type alert_channel_type = 'MSTEAMS_WEBHOOK' | 'SLACK' | 'WEBHOOK';
|
||||
export type alert_type = 'SCHEMA_CHANGE_NOTIFICATIONS';
|
||||
export type schema_policy_resource = 'ORGANIZATION' | 'PROJECT';
|
||||
export type user_role = 'ADMIN' | 'MEMBER';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Checkbox, Table, Tag, TBody, Td, Tr } from '@/components/v2';
|
||||
import { FragmentType, graphql, useFragment } from '@/gql';
|
||||
import { AlertChannelType } from '@/gql/graphql';
|
||||
import { AlertChannelType, ChannelsTable_AlertChannelFragmentFragment } from '@/gql/graphql';
|
||||
|
||||
export const ChannelsTable_AlertChannelFragment = graphql(`
|
||||
fragment ChannelsTable_AlertChannelFragment on AlertChannel {
|
||||
|
|
@ -13,9 +13,18 @@ export const ChannelsTable_AlertChannelFragment = graphql(`
|
|||
... on AlertWebhookChannel {
|
||||
endpoint
|
||||
}
|
||||
... on TeamsWebhookChannel {
|
||||
endpoint
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const colorMap = {
|
||||
[AlertChannelType.Slack]: 'green' as const,
|
||||
[AlertChannelType.Webhook]: 'yellow' as const,
|
||||
[AlertChannelType.MsteamsWebhook]: 'orange' as const,
|
||||
};
|
||||
|
||||
export function ChannelsTable(props: {
|
||||
channels: FragmentType<typeof ChannelsTable_AlertChannelFragment>[];
|
||||
isChecked: (channelId: string) => boolean;
|
||||
|
|
@ -23,6 +32,20 @@ export function ChannelsTable(props: {
|
|||
}) {
|
||||
const channels = useFragment(ChannelsTable_AlertChannelFragment, props.channels);
|
||||
|
||||
const renderChannelEndpoint = (channel: ChannelsTable_AlertChannelFragmentFragment) => {
|
||||
if (channel.__typename === 'AlertSlackChannel') {
|
||||
return channel.channel;
|
||||
}
|
||||
if (
|
||||
channel.__typename === 'AlertWebhookChannel' ||
|
||||
channel.__typename === 'TeamsWebhookChannel'
|
||||
) {
|
||||
return channel.endpoint;
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<TBody>
|
||||
|
|
@ -36,18 +59,12 @@ export function ChannelsTable(props: {
|
|||
checked={props.isChecked(channel.id)}
|
||||
/>
|
||||
</Td>
|
||||
<Td>{channel.name}</Td>
|
||||
<Td className="truncate text-xs text-gray-400">
|
||||
{channel.__typename === 'AlertSlackChannel'
|
||||
? channel.channel
|
||||
: channel.__typename === 'AlertWebhookChannel'
|
||||
? channel.endpoint
|
||||
: ''}
|
||||
<Td className="text-ellipsis whitespace-nowrap">{channel.name}</Td>
|
||||
<Td className="max-w-xs truncate text-xs text-gray-400">
|
||||
{renderChannelEndpoint(channel)}
|
||||
</Td>
|
||||
<Td>
|
||||
<Tag color={channel.type === AlertChannelType.Webhook ? 'green' : 'yellow'}>
|
||||
{channel.type}
|
||||
</Tag>
|
||||
<Td className="flex max-w-24 content-end">
|
||||
<Tag color={colorMap[channel.type]}>{channel.type}</Tag>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ export const CreateChannelModal = ({
|
|||
),
|
||||
endpoint: Yup.string()
|
||||
.url()
|
||||
.when('type', ([type], schema) =>
|
||||
type === AlertChannelType.Webhook ? schema.required('Must enter endpoint') : schema,
|
||||
.when('type', ([_type], schema) =>
|
||||
isWebhookLike ? schema.required('Must enter endpoint') : schema,
|
||||
),
|
||||
}),
|
||||
async onSubmit(values) {
|
||||
|
|
@ -73,8 +73,7 @@ export const CreateChannelModal = ({
|
|||
name: values.name,
|
||||
type: values.type,
|
||||
slack: values.type === AlertChannelType.Slack ? { channel: values.slackChannel } : null,
|
||||
webhook:
|
||||
values.type === AlertChannelType.Webhook ? { endpoint: values.endpoint } : null,
|
||||
webhook: isWebhookLike ? { endpoint: values.endpoint } : null,
|
||||
},
|
||||
});
|
||||
if (error) {
|
||||
|
|
@ -88,6 +87,9 @@ export const CreateChannelModal = ({
|
|||
}
|
||||
},
|
||||
});
|
||||
const isWebhookLike = [AlertChannelType.Webhook, AlertChannelType.MsteamsWebhook].includes(
|
||||
values.type,
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal open={isOpen} onOpenChange={toggleModalOpen}>
|
||||
|
|
@ -132,12 +134,13 @@ export const CreateChannelModal = ({
|
|||
options={[
|
||||
{ value: AlertChannelType.Slack, name: 'Slack' },
|
||||
{ value: AlertChannelType.Webhook, name: 'Webhook' },
|
||||
{ value: AlertChannelType.MsteamsWebhook, name: 'MS Teams Webhook' },
|
||||
]}
|
||||
/>
|
||||
{touched.type && errors.type && <div className="text-sm text-red-500">{errors.type}</div>}
|
||||
</div>
|
||||
|
||||
{values.type === AlertChannelType.Webhook && (
|
||||
{isWebhookLike && (
|
||||
<div className="flex flex-col gap-4">
|
||||
<label className="text-sm font-semibold" htmlFor="endpoint">
|
||||
Endpoint
|
||||
|
|
@ -160,7 +163,13 @@ export const CreateChannelModal = ({
|
|||
{mutation.data.addAlertChannel.error.inputErrors.webhookEndpoint}
|
||||
</div>
|
||||
)}
|
||||
<p className="text-sm text-gray-500">Hive will send alerts to your endpoint.</p>
|
||||
{values.endpoint ? (
|
||||
<p className="text-sm text-gray-500">Hive will send alerts to your endpoint.</p>
|
||||
) : (
|
||||
<a href="https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=newteams%2Cdotnet">
|
||||
Follow this guide to set up an incoming webhook connector in MS Teams
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -205,7 +214,7 @@ export const CreateChannelModal = ({
|
|||
<Button
|
||||
type="submit"
|
||||
size="lg"
|
||||
className="w-full justify-center"
|
||||
className="w-full justify-center text-ellipsis whitespace-nowrap"
|
||||
variant="primary"
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ CardDescription.displayName = 'CardDescription';
|
|||
|
||||
const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
|
||||
<div ref={ref} className={cn('overflow-hidden p-6 pt-0', className)} {...props} />
|
||||
),
|
||||
);
|
||||
CardContent.displayName = 'CardContent';
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { cn } from '@/lib/utils';
|
|||
|
||||
function Table({ children, className, ...props }: ComponentProps<'table'>): ReactElement {
|
||||
return (
|
||||
<table className={cn('w-full', className)} {...props}>
|
||||
<table className={cn('w-full overflow-hidden', className)} {...props}>
|
||||
{children}
|
||||
</table>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const colors = {
|
|||
green: 'bg-green-500/10 text-green-500',
|
||||
yellow: 'bg-yellow-500/10 text-yellow-500',
|
||||
gray: 'bg-gray-500/10 text-gray-500',
|
||||
orange: 'bg-orange-500/10 text-orange-500',
|
||||
} as const;
|
||||
|
||||
export function Tag({
|
||||
|
|
@ -12,13 +13,17 @@ export function Tag({
|
|||
color = 'gray',
|
||||
className,
|
||||
}: {
|
||||
color?: 'green' | 'yellow' | 'gray';
|
||||
color?: keyof typeof colors;
|
||||
className?: string;
|
||||
children: ReactNode;
|
||||
}): ReactElement {
|
||||
return (
|
||||
<span
|
||||
className={cn('inline-flex items-center gap-x-1 rounded-sm p-2', colors[color], className)}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-x-1 whitespace-nowrap rounded-sm p-2',
|
||||
colors[color],
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 98 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
|
|
@ -21,4 +21,9 @@ export const authors: Record<string, Author> = {
|
|||
link: 'https://twitter.com/aleksandrasays',
|
||||
github: 'beerose',
|
||||
},
|
||||
jiri: {
|
||||
name: 'Jiri Spac',
|
||||
link: 'https://twitter.com/capajj',
|
||||
github: 'capaj',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import githubIntegrationImage from '../../../../public/docs/pages/management/org
|
|||
import slackIntegrationImage from '../../../../public/docs/pages/management/org-slack-integration.png'
|
||||
import projectGitLinkImage from '../../../../public/docs/pages/management/project-git-link.png'
|
||||
import projectHttpAlertImage from '../../../../public/docs/pages/management/project-http-alert.png'
|
||||
import msteamsFormImage from '../../../../public/docs/pages/management/project-msteams-alert.png'
|
||||
import slackAlertFormImage from '../../../../public/docs/pages/management/project-slack-alert.png'
|
||||
|
||||
# Project Management
|
||||
|
|
@ -140,6 +141,28 @@ Hive project:
|
|||
invitation, our Slack app will be unable to post messages to the channel.
|
||||
</Callout>
|
||||
|
||||
#### MS Teams Webhook
|
||||
|
||||
You set up Hive MS Teams webhook to receive alerts and notifications from Hive, when an alert or a
|
||||
notification is triggered. All you need to do is to provide a valid HTTP URL, and Hive will dispatch
|
||||
a `POST` request to that URL, with a JSON payload acceptable by MS Teams.
|
||||
[MS Teams Webhook JSON example](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using#example-of-connector-message)
|
||||
|
||||
Typically the webhook URL looks like:
|
||||
|
||||
```txt
|
||||
https://USERNAME.webhook.office.com/webhookb2/XXXXX/IncomingWebhook/YYYY/ZZZZZ
|
||||
```
|
||||
|
||||
You can find more information on how to set up a webhook in MS Teams in the
|
||||
[official documentation - Create Incoming Webhooks](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=newteams%2Cdotnet).
|
||||
|
||||
<NextImage
|
||||
alt="MS Teams Alert Configuration"
|
||||
src={msteamsFormImage}
|
||||
className="mt-6 max-w-sm rounded-lg drop-shadow-md"
|
||||
/>
|
||||
|
||||
#### HTTP Webhook
|
||||
|
||||
You can implement a custom HTTP webhook to receive alerts and notifications from Hive, when an alert
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
title: MS Teams Webhooks for Alerts in Hive
|
||||
description: MS Teams webhooks to receive alerts and notifications from Hive.
|
||||
date: 2024-06-14
|
||||
authors: [jiri]
|
||||
---
|
||||
|
||||
We’re excited to announce a new feature that lets you configure MS Teams webhooks to receive alerts
|
||||
and notifications from Hive. By connecting Hive with MS Teams, you can make your team always aware
|
||||
of critical changes and developments.
|
||||
|
||||

|
||||
|
||||
Here’s a simple guide to get you started:
|
||||
|
||||
1. **Go to Project:** Navigate to your project's page.
|
||||
1. **Access Alerts:** Click on the "Alerts" tab.
|
||||
1. **Add a Channel:** In the Channels section, click on the "Add channel" button.
|
||||
1. **Select type**: Choose "MS Teams Webhook" from the dropdown menu.
|
||||
1. **Enter Webhook URL:** Paste your webhook URL in the "Endpoint" field.
|
||||
1. **Save:** Click "Save" to confirm your settings.
|
||||
|
||||
Once set up, you can create an alert that triggers whenever a schema change is detected upon
|
||||
publishing. For more detailed instructions, check out our documentation
|
||||
[here](/docs/management/projects#ms-teams-webhook).
|
||||
|
||||
Setting it up ensures you stay updated, making your workflow smoother and more efficient, without
|
||||
stepping out of MS Teams application.
|
||||
409
pnpm-lock.yaml
409
pnpm-lock.yaml
|
|
@ -778,6 +778,9 @@ importers:
|
|||
tslib:
|
||||
specifier: 2.6.3
|
||||
version: 2.6.3
|
||||
vitest:
|
||||
specifier: 1.6.0
|
||||
version: 1.6.0(@types/node@20.14.10)(less@4.2.0)(terser@5.31.1)
|
||||
zod:
|
||||
specifier: 3.23.8
|
||||
version: 3.23.8
|
||||
|
|
@ -3628,12 +3631,6 @@ packages:
|
|||
resolution: {integrity: sha512-IPjmgSc4KpQRlO4qbEDnBEixvtb06WDmjKfi/7fkZaryh5HuOmTtixe1EupQI5XfXO8joc3d27uUZ0QdC++euA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@esbuild/aix-ppc64@0.19.11':
|
||||
resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/aix-ppc64@0.20.2':
|
||||
resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3652,12 +3649,6 @@ packages:
|
|||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm64@0.20.2':
|
||||
resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3676,12 +3667,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.19.11':
|
||||
resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.20.2':
|
||||
resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3700,12 +3685,6 @@ packages:
|
|||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.19.11':
|
||||
resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.20.2':
|
||||
resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3724,12 +3703,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-arm64@0.20.2':
|
||||
resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3748,12 +3721,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.19.11':
|
||||
resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.20.2':
|
||||
resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3772,12 +3739,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.20.2':
|
||||
resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3796,12 +3757,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.19.11':
|
||||
resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.20.2':
|
||||
resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3820,12 +3775,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm64@0.20.2':
|
||||
resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3844,12 +3793,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.19.11':
|
||||
resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.20.2':
|
||||
resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3868,12 +3811,6 @@ packages:
|
|||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.19.11':
|
||||
resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.20.2':
|
||||
resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3892,12 +3829,6 @@ packages:
|
|||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.19.11':
|
||||
resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.20.2':
|
||||
resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3916,12 +3847,6 @@ packages:
|
|||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.19.11':
|
||||
resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.20.2':
|
||||
resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3940,12 +3865,6 @@ packages:
|
|||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.19.11':
|
||||
resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.20.2':
|
||||
resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3964,12 +3883,6 @@ packages:
|
|||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.19.11':
|
||||
resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.20.2':
|
||||
resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -3988,12 +3901,6 @@ packages:
|
|||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.19.11':
|
||||
resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.20.2':
|
||||
resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -4012,12 +3919,6 @@ packages:
|
|||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.19.11':
|
||||
resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.20.2':
|
||||
resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -4036,12 +3937,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-x64@0.19.11':
|
||||
resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.20.2':
|
||||
resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -4066,12 +3961,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.19.11':
|
||||
resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.20.2':
|
||||
resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -4090,12 +3979,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/sunos-x64@0.19.11':
|
||||
resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/sunos-x64@0.20.2':
|
||||
resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -4114,12 +3997,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-arm64@0.20.2':
|
||||
resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -4138,12 +4015,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.19.11':
|
||||
resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.20.2':
|
||||
resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -4162,12 +4033,6 @@ packages:
|
|||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.19.11':
|
||||
resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.20.2':
|
||||
resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -4994,7 +4859,6 @@ packages:
|
|||
'@humanwhocodes/config-array@0.11.14':
|
||||
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
|
||||
engines: {node: '>=10.10.0'}
|
||||
deprecated: Use @eslint/config-array instead
|
||||
|
||||
'@humanwhocodes/module-importer@1.0.1':
|
||||
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
|
||||
|
|
@ -5002,7 +4866,6 @@ packages:
|
|||
|
||||
'@humanwhocodes/object-schema@2.0.2':
|
||||
resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
|
||||
deprecated: Use @eslint/object-schema instead
|
||||
|
||||
'@ianvs/prettier-plugin-sort-imports@4.2.1':
|
||||
resolution: {integrity: sha512-NKN1LVFWUDGDGr3vt+6Ey3qPeN/163uR1pOPAlkWpgvAqgxQ6kSdUf1F0it8aHUtKRUzEGcK38Wxd07O61d7+Q==}
|
||||
|
|
@ -6900,11 +6763,6 @@ packages:
|
|||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.6.1':
|
||||
resolution: {integrity: sha512-0WQ0ouLejaUCRsL93GD4uft3rOmB8qoQMU05Kb8CmMtMBe7XUDLAltxVZI1q6byNqEtU7N1ZX1Vw5lIpgulLQA==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.17.2':
|
||||
resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==}
|
||||
cpu: [arm64]
|
||||
|
|
@ -6915,11 +6773,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.6.1':
|
||||
resolution: {integrity: sha512-1TKm25Rn20vr5aTGGZqo6E4mzPicCUD79k17EgTLAsXc1zysyi4xXKACfUbwyANEPAEIxkzwue6JZ+stYzWUTA==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.17.2':
|
||||
resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==}
|
||||
cpu: [arm64]
|
||||
|
|
@ -6930,11 +6783,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.6.1':
|
||||
resolution: {integrity: sha512-cEXJQY/ZqMACb+nxzDeX9IPLAg7S94xouJJCNVE5BJM8JUEP4HeTF+ti3cmxWeSJo+5D+o8Tc0UAWUkfENdeyw==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.17.2':
|
||||
resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==}
|
||||
cpu: [x64]
|
||||
|
|
@ -6945,11 +6793,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.6.1':
|
||||
resolution: {integrity: sha512-LoSU9Xu56isrkV2jLldcKspJ7sSXmZWkAxg7sW/RfF7GS4F5/v4EiqKSMCFbZtDu2Nc1gxxFdQdKwkKS4rwxNg==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.17.2':
|
||||
resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==}
|
||||
cpu: [arm]
|
||||
|
|
@ -6960,11 +6803,6 @@ packages:
|
|||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.6.1':
|
||||
resolution: {integrity: sha512-EfI3hzYAy5vFNDqpXsNxXcgRDcFHUWSx5nnRSCKwXuQlI5J9dD84g2Usw81n3FLBNsGCegKGwwTVsSKK9cooSQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.17.2':
|
||||
resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==}
|
||||
cpu: [arm]
|
||||
|
|
@ -6985,11 +6823,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.6.1':
|
||||
resolution: {integrity: sha512-9lhc4UZstsegbNLhH0Zu6TqvDfmhGzuCWtcTFXY10VjLLUe4Mr0Ye2L3rrtHaDd/J5+tFMEuo5LTCSCMXWfUKw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.17.2':
|
||||
resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==}
|
||||
cpu: [arm64]
|
||||
|
|
@ -7000,11 +6833,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.6.1':
|
||||
resolution: {integrity: sha512-FfoOK1yP5ksX3wwZ4Zk1NgyGHZyuRhf99j64I5oEmirV8EFT7+OhUZEnP+x17lcP/QHJNWGsoJwrz4PJ9fBEXw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.17.2':
|
||||
resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==}
|
||||
cpu: [ppc64]
|
||||
|
|
@ -7045,11 +6873,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.6.1':
|
||||
resolution: {integrity: sha512-DNGZvZDO5YF7jN5fX8ZqmGLjZEXIJRdJEdTFMhiyXqyXubBa0WVLDWSNlQ5JR2PNgDbEV1VQowhVRUh+74D+RA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.17.2':
|
||||
resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==}
|
||||
cpu: [x64]
|
||||
|
|
@ -7060,11 +6883,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.6.1':
|
||||
resolution: {integrity: sha512-RkJVNVRM+piYy87HrKmhbexCHg3A6Z6MU0W9GHnJwBQNBeyhCJG9KDce4SAMdicQnpURggSvtbGo9xAWOfSvIQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.17.2':
|
||||
resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==}
|
||||
cpu: [arm64]
|
||||
|
|
@ -7075,11 +6893,6 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.6.1':
|
||||
resolution: {integrity: sha512-v2FVT6xfnnmTe3W9bJXl6r5KwJglMK/iRlkKiIFfO6ysKs0rDgz7Cwwf3tjldxQUrHL9INT/1r4VA0n9L/F1vQ==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.17.2':
|
||||
resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==}
|
||||
cpu: [ia32]
|
||||
|
|
@ -7090,11 +6903,6 @@ packages:
|
|||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.6.1':
|
||||
resolution: {integrity: sha512-YEeOjxRyEjqcWphH9dyLbzgkF8wZSKAKUkldRY6dgNR5oKs2LZazqGB41cWJ4Iqqcy9/zqYgmzBkRoVz3Q9MLw==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.17.2':
|
||||
resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==}
|
||||
cpu: [x64]
|
||||
|
|
@ -7105,11 +6913,6 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.6.1':
|
||||
resolution: {integrity: sha512-0zfTlFAIhgz8V2G8STq8toAjsYYA6eci1hnXuyOTUFnymrtJwnS6uGKiv3v5UrPZkBlamLvrLV2iiaeqCKzb0A==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rushstack/eslint-patch@1.6.1':
|
||||
resolution: {integrity: sha512-UY+FGM/2jjMkzQLn8pxcHGMaVLh9aEitG3zY2CiY7XHdLiz3bZOwa6oDxNqEMv7zZkV+cj5DOdz0cQ1BP5Hjgw==}
|
||||
|
||||
|
|
@ -10491,11 +10294,6 @@ packages:
|
|||
peerDependencies:
|
||||
esbuild: '>=0.12 <1'
|
||||
|
||||
esbuild@0.19.11:
|
||||
resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
|
||||
esbuild@0.20.2:
|
||||
resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -15360,11 +15158,6 @@ packages:
|
|||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
rollup@4.6.1:
|
||||
resolution: {integrity: sha512-jZHaZotEHQaHLgKr8JnQiDT1rmatjgKlMekyksz+yk9jt/8z9quNjnKNRoaM0wd9DC2QKXjmWWuDYtM3jfF8pQ==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
rss@1.2.2:
|
||||
resolution: {integrity: sha512-xUhRTgslHeCBeHAqaWSbOYTydN2f0tAzNXvzh3stjz7QDhQMzdgHf3pfgNIngeytQflrFPfy6axHilTETr6gDg==}
|
||||
|
||||
|
|
@ -16796,34 +16589,6 @@ packages:
|
|||
vite:
|
||||
optional: true
|
||||
|
||||
vite@5.0.5:
|
||||
resolution: {integrity: sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': ^18.0.0 || >=20.0.0
|
||||
less: '*'
|
||||
lightningcss: ^1.21.0
|
||||
sass: '*'
|
||||
stylus: '*'
|
||||
sugarss: '*'
|
||||
terser: ^5.4.0
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
less:
|
||||
optional: true
|
||||
lightningcss:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
stylus:
|
||||
optional: true
|
||||
sugarss:
|
||||
optional: true
|
||||
terser:
|
||||
optional: true
|
||||
|
||||
vite@5.3.3:
|
||||
resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
|
|
@ -19935,9 +19700,6 @@ snapshots:
|
|||
dependencies:
|
||||
tslib: 2.6.3
|
||||
|
||||
'@esbuild/aix-ppc64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -19947,9 +19709,6 @@ snapshots:
|
|||
'@esbuild/aix-ppc64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -19959,9 +19718,6 @@ snapshots:
|
|||
'@esbuild/android-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -19971,9 +19727,6 @@ snapshots:
|
|||
'@esbuild/android-arm@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -19983,9 +19736,6 @@ snapshots:
|
|||
'@esbuild/android-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -19995,9 +19745,6 @@ snapshots:
|
|||
'@esbuild/darwin-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20007,9 +19754,6 @@ snapshots:
|
|||
'@esbuild/darwin-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20019,9 +19763,6 @@ snapshots:
|
|||
'@esbuild/freebsd-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20031,9 +19772,6 @@ snapshots:
|
|||
'@esbuild/freebsd-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20043,9 +19781,6 @@ snapshots:
|
|||
'@esbuild/linux-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20055,9 +19790,6 @@ snapshots:
|
|||
'@esbuild/linux-arm@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20067,9 +19799,6 @@ snapshots:
|
|||
'@esbuild/linux-ia32@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20079,9 +19808,6 @@ snapshots:
|
|||
'@esbuild/linux-loong64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20091,9 +19817,6 @@ snapshots:
|
|||
'@esbuild/linux-mips64el@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20103,9 +19826,6 @@ snapshots:
|
|||
'@esbuild/linux-ppc64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20115,9 +19835,6 @@ snapshots:
|
|||
'@esbuild/linux-riscv64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20127,9 +19844,6 @@ snapshots:
|
|||
'@esbuild/linux-s390x@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20139,9 +19853,6 @@ snapshots:
|
|||
'@esbuild/linux-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20154,9 +19865,6 @@ snapshots:
|
|||
'@esbuild/openbsd-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20166,9 +19874,6 @@ snapshots:
|
|||
'@esbuild/openbsd-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20178,9 +19883,6 @@ snapshots:
|
|||
'@esbuild/sunos-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20190,9 +19892,6 @@ snapshots:
|
|||
'@esbuild/win32-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -20202,9 +19901,6 @@ snapshots:
|
|||
'@esbuild/win32-ia32@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.20.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -24110,45 +23806,30 @@ snapshots:
|
|||
'@rollup/rollup-android-arm-eabi@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.17.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -24161,18 +23842,12 @@ snapshots:
|
|||
'@rollup/rollup-linux-arm64-gnu@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.17.2':
|
||||
optional: true
|
||||
|
||||
|
|
@ -24197,45 +23872,30 @@ snapshots:
|
|||
'@rollup/rollup-linux-x64-gnu@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.6.1':
|
||||
optional: true
|
||||
|
||||
'@rushstack/eslint-patch@1.6.1': {}
|
||||
|
||||
'@sec-ant/readable-stream@0.4.1': {}
|
||||
|
|
@ -28745,32 +28405,6 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
esbuild@0.19.11:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.19.11
|
||||
'@esbuild/android-arm': 0.19.11
|
||||
'@esbuild/android-arm64': 0.19.11
|
||||
'@esbuild/android-x64': 0.19.11
|
||||
'@esbuild/darwin-arm64': 0.19.11
|
||||
'@esbuild/darwin-x64': 0.19.11
|
||||
'@esbuild/freebsd-arm64': 0.19.11
|
||||
'@esbuild/freebsd-x64': 0.19.11
|
||||
'@esbuild/linux-arm': 0.19.11
|
||||
'@esbuild/linux-arm64': 0.19.11
|
||||
'@esbuild/linux-ia32': 0.19.11
|
||||
'@esbuild/linux-loong64': 0.19.11
|
||||
'@esbuild/linux-mips64el': 0.19.11
|
||||
'@esbuild/linux-ppc64': 0.19.11
|
||||
'@esbuild/linux-riscv64': 0.19.11
|
||||
'@esbuild/linux-s390x': 0.19.11
|
||||
'@esbuild/linux-x64': 0.19.11
|
||||
'@esbuild/netbsd-x64': 0.19.11
|
||||
'@esbuild/openbsd-x64': 0.19.11
|
||||
'@esbuild/sunos-x64': 0.19.11
|
||||
'@esbuild/win32-arm64': 0.19.11
|
||||
'@esbuild/win32-ia32': 0.19.11
|
||||
'@esbuild/win32-x64': 0.19.11
|
||||
|
||||
esbuild@0.20.2:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.20.2
|
||||
|
|
@ -35021,22 +34655,6 @@ snapshots:
|
|||
'@rollup/rollup-win32-x64-msvc': 4.18.0
|
||||
fsevents: 2.3.3
|
||||
|
||||
rollup@4.6.1:
|
||||
optionalDependencies:
|
||||
'@rollup/rollup-android-arm-eabi': 4.6.1
|
||||
'@rollup/rollup-android-arm64': 4.6.1
|
||||
'@rollup/rollup-darwin-arm64': 4.6.1
|
||||
'@rollup/rollup-darwin-x64': 4.6.1
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.6.1
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.6.1
|
||||
'@rollup/rollup-linux-arm64-musl': 4.6.1
|
||||
'@rollup/rollup-linux-x64-gnu': 4.6.1
|
||||
'@rollup/rollup-linux-x64-musl': 4.6.1
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.6.1
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.6.1
|
||||
'@rollup/rollup-win32-x64-msvc': 4.6.1
|
||||
fsevents: 2.3.3
|
||||
|
||||
rss@1.2.2:
|
||||
dependencies:
|
||||
mime-types: 2.1.13
|
||||
|
|
@ -36632,9 +36250,9 @@ snapshots:
|
|||
vite-node@1.6.0(@types/node@20.14.10)(less@4.2.0)(terser@5.31.1):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
pathe: 1.1.1
|
||||
picocolors: 1.0.0
|
||||
picocolors: 1.0.1
|
||||
vite: 5.3.3(@types/node@20.14.10)(less@4.2.0)(terser@5.31.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
|
|
@ -36657,17 +36275,6 @@ snapshots:
|
|||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@5.0.5(@types/node@20.14.10)(less@4.2.0)(terser@5.31.1):
|
||||
dependencies:
|
||||
esbuild: 0.19.11
|
||||
postcss: 8.4.39
|
||||
rollup: 4.6.1
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.10
|
||||
fsevents: 2.3.3
|
||||
less: 4.2.0
|
||||
terser: 5.31.1
|
||||
|
||||
vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(terser@5.31.1):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
|
|
@ -36688,17 +36295,17 @@ snapshots:
|
|||
'@vitest/utils': 1.6.0
|
||||
acorn-walk: 8.3.2
|
||||
chai: 4.4.1
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
execa: 8.0.1
|
||||
local-pkg: 0.5.0
|
||||
magic-string: 0.30.5
|
||||
pathe: 1.1.1
|
||||
picocolors: 1.0.0
|
||||
picocolors: 1.0.1
|
||||
std-env: 3.6.0
|
||||
strip-literal: 2.0.0
|
||||
tinybench: 2.5.1
|
||||
tinypool: 0.8.3
|
||||
vite: 5.0.5(@types/node@20.14.10)(less@4.2.0)(terser@5.31.1)
|
||||
vite: 5.3.3(@types/node@20.14.10)(less@4.2.0)(terser@5.31.1)
|
||||
vite-node: 1.6.0(@types/node@20.14.10)(less@4.2.0)(terser@5.31.1)
|
||||
why-is-node-running: 2.2.2
|
||||
optionalDependencies:
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'reflect-metadata';
|
||||
import rawSnapshotSerializer from 'jest-snapshot-serializer-raw/always';
|
||||
import { expect } from 'vitest';
|
||||
import { normalizeCliOutput } from './serializers/cli-output';
|
||||
|
|
|
|||
|
|
@ -9,7 +9,12 @@ export default defineConfig({
|
|||
.pathname,
|
||||
},
|
||||
globals: true,
|
||||
exclude: [...defaultExclude, 'integration-tests', 'packages/migrations/test'],
|
||||
exclude: [
|
||||
...defaultExclude,
|
||||
'integration-tests',
|
||||
'packages/migrations/test',
|
||||
'docker/.hive-dev',
|
||||
],
|
||||
setupFiles: ['./scripts/serializer.ts'],
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue