From 6148bbbd622a5467b9917be012ad808241bb1a6d Mon Sep 17 00:00:00 2001 From: Michael Derynck Date: Tue, 27 Feb 2024 17:41:14 -0700 Subject: [PATCH 1/6] Fix path for plugin release publish (#3967) # What this PR does Fixes the path of the plugin file to public. Leftover from last round of build changes ## Which issue(s) this PR fixes ## Checklist - [ ] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) --- .drone.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 55e0ca47..44339910 100644 --- a/.drone.yml +++ b/.drone.yml @@ -40,7 +40,7 @@ steps: image: plugins/gcs settings: acl: allUsers:READER - source: grafana-plugin/ci/dist/grafana-oncall-app-${DRONE_TAG}.zip + source: grafana-plugin/grafana-oncall-app-${DRONE_TAG}.zip target: grafana-oncall-app/releases/grafana-oncall-app-${DRONE_TAG}.zip token: from_secret: gcs_oncall_publisher_key @@ -385,4 +385,6 @@ name: cloud_access_policy_token --- kind: signature -hmac: 198b7c7d2c94fc5698b22a722e7748181990207755cf1778b2290137e262518c +hmac: d541ed21fc2472272c6772e246aaf1a2606db112b4e72a44bc4530831e9ca4d3 + +... From bec2589b43f8b150317898bf1e1b97a5272c7442 Mon Sep 17 00:00:00 2001 From: Dominik Broj Date: Wed, 28 Feb 2024 07:13:26 +0100 Subject: [PATCH 2/6] Deploy PR e2e test report to GH Pages (#3952) # What this PR does - publish Playwright HTML report to GH Pages - turn off video recordings ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) --- .github/workflows/e2e-tests.yml | 27 +++++++++++++++-- grafana-plugin/e2e-tests/fixtures.ts | 45 +++++----------------------- grafana-plugin/playwright.config.ts | 2 +- 3 files changed, 33 insertions(+), 41 deletions(-) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index cf38e2d5..ecfc47c2 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -33,6 +33,11 @@ jobs: # this will allow us to run more backend containers and parralelize the tests) runs-on: ubuntu-latest-8-cores name: "Grafana: ${{ inputs.grafana-image-tag }}" + environment: + name: github-pages + permissions: + id-token: write + pages: "write" steps: - name: Checkout uses: actions/checkout@v3 @@ -222,9 +227,25 @@ jobs: with: important-workloads: deploy/oncall-ci-grafana - - uses: actions/upload-artifact@v3 + - name: Setup Pages if: failure() + uses: actions/configure-pages@v2 + + - name: Upload artifact + if: failure() + uses: actions/upload-pages-artifact@v1 with: - name: playwright-report-${{ inputs.grafana-image-tag }} path: ./grafana-plugin/playwright-report/ - retention-days: 30 + + - name: Deploy to GitHub Pages + if: failure() + id: deployment + uses: actions/deploy-pages@v3 + with: + preview: true + + - name: Linked Github Page + if: failure() + run: | + echo "Test report has been deployed to [GitHub Pages](https://grafana.github.io/oncall/) :rocket:" \ + >> $GITHUB_STEP_SUMMARY diff --git a/grafana-plugin/e2e-tests/fixtures.ts b/grafana-plugin/e2e-tests/fixtures.ts index fde536a9..e2f38f4a 100644 --- a/grafana-plugin/e2e-tests/fixtures.ts +++ b/grafana-plugin/e2e-tests/fixtures.ts @@ -1,12 +1,9 @@ -import { test as base, Browser, Fixtures, Page, TestInfo } from '@playwright/test'; +import { test as base, Browser, Fixtures, Page } from '@playwright/test'; import { VIEWER_USER_STORAGE_STATE, EDITOR_USER_STORAGE_STATE, ADMIN_USER_STORAGE_STATE } from '../playwright.config'; import { GRAFANA_ADMIN_USERNAME, GRAFANA_EDITOR_USERNAME, GRAFANA_VIEWER_USERNAME } from './utils/constants'; -import * as fs from 'fs'; -import * as path from 'path'; - export class BaseRolePage { page: Page; userName: string; @@ -39,55 +36,29 @@ interface TestFixtures extends Fixtures { interface WorkerFixtures extends Fixtures {} -/** - * NOTE: currently videos are not generated automatically because of how we generate a browserContext within our - * auth fixtures (which is how Playwright suggested setting up multi-role authnz tests..). There's a GitHub - * Issue here that tracks this issue https://github.com/microsoft/playwright/issues/14813 - * - * Here's a temporary workaround on this, which is what this function does - * https://github.com/microsoft/playwright/issues/14813#issuecomment-1582499142 - */ -const _recordTestVideo = async ( +const setContextForPage = async ( browser: Browser, use: (r: BaseRolePage) => Promise, - testInfo: TestInfo, storageStateLocation: string, RolePage: BaseRolePageType ) => { - const videoDir = path.join(testInfo.outputPath(), 'videos'); - const context = await browser.newContext({ storageState: storageStateLocation, - recordVideo: { dir: videoDir }, }); const page = new RolePage(await context.newPage()); - - try { - await use(page); - } finally { - await context.close(); - const videoFiles = fs.readdirSync(videoDir); - - if (videoFiles.length > 0) { - for (let i = videoFiles.length; i > 0; i--) { - let videoFile = path.join(videoDir, videoFiles[i - 1]); - await testInfo.attach('video', { path: videoFile }); - } - } - } + await use(page); }; export * from '@playwright/test'; export const test = base.extend({ - viewerRolePage: ({ browser }, use, testInfo) => - _recordTestVideo(browser, use, testInfo, VIEWER_USER_STORAGE_STATE, ViewerRolePage), - editorRolePage: async ({ browser }, use, testInfo) => - _recordTestVideo(browser, use, testInfo, EDITOR_USER_STORAGE_STATE, EditorRolePage), - adminRolePage: async ({ browser }, use, testInfo) => - _recordTestVideo(browser, use, testInfo, ADMIN_USER_STORAGE_STATE, AdminRolePage), /** * add back this fixture once this bug is fixed * https://github.com/microsoft/playwright/issues/29608 */ // currentGrafanaVersion: ({}, use) => use('9.0.0'), + viewerRolePage: async ({ browser }, use) => + setContextForPage(browser, use, VIEWER_USER_STORAGE_STATE, ViewerRolePage), + editorRolePage: async ({ browser }, use) => + setContextForPage(browser, use, EDITOR_USER_STORAGE_STATE, EditorRolePage), + adminRolePage: async ({ browser }, use) => setContextForPage(browser, use, ADMIN_USER_STORAGE_STATE, AdminRolePage), }); diff --git a/grafana-plugin/playwright.config.ts b/grafana-plugin/playwright.config.ts index c6721cf8..3d3dff3e 100644 --- a/grafana-plugin/playwright.config.ts +++ b/grafana-plugin/playwright.config.ts @@ -64,7 +64,7 @@ export default defineConfig({ // baseURL: 'http://localhost:3000', trace: 'on', - video: 'on', + video: 'off', headless: true, }, From f886fee93c203e7b980c4691e0655e64ac3bdc97 Mon Sep 17 00:00:00 2001 From: Dominik Broj Date: Wed, 28 Feb 2024 12:27:57 +0100 Subject: [PATCH 3/6] Fetch selected value of notify schedule in escalation policy (#3969) # What this PR does - Fetch selected schedule on mount which is not done as soon as schedule is not on the first page - Add missing observer decorator - Fix incorrect HTTP calls when creating integrations https://raintank-corp.slack.com/archives/C04JCU51NF8/p1708703429829919 ## Which issue(s) this PR fixes https://github.com/grafana/oncall/issues/3966 ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) --- grafana-plugin/src/components/Policy/EscalationPolicy.tsx | 8 ++++++++ .../src/containers/IntegrationForm/IntegrationForm.tsx | 1 + .../src/pages/integration/Integration.helper.ts | 4 ---- grafana-plugin/src/pages/integration/Integration.tsx | 7 ++++--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/grafana-plugin/src/components/Policy/EscalationPolicy.tsx b/grafana-plugin/src/components/Policy/EscalationPolicy.tsx index 5f743d60..6a0fe54e 100644 --- a/grafana-plugin/src/components/Policy/EscalationPolicy.tsx +++ b/grafana-plugin/src/components/Policy/EscalationPolicy.tsx @@ -3,6 +3,7 @@ import React, { ChangeEvent } from 'react'; import { SelectableValue } from '@grafana/data'; import { Button, Input, Select, IconButton } from '@grafana/ui'; import cn from 'classnames/bind'; +import { observer } from 'mobx-react'; import moment from 'moment-timezone'; import { SortableElement } from 'react-sortable-hoc'; import reactStringReplace from 'react-string-replace'; @@ -56,7 +57,14 @@ export interface EscalationPolicyProps extends ElementSortableProps { isSlackInstalled: boolean; } +@observer class _EscalationPolicy extends React.Component { + componentDidMount() { + if (this.props.data.notify_schedule) { + this.props.store.scheduleStore.loadItem(this.props.data.notify_schedule); + } + } + render() { const { data, escalationChoices, number, isDisabled, backgroundClassName, backgroundHexNumber } = this.props; const { id, step, is_final } = data; diff --git a/grafana-plugin/src/containers/IntegrationForm/IntegrationForm.tsx b/grafana-plugin/src/containers/IntegrationForm/IntegrationForm.tsx index 252263fe..a67b73d2 100644 --- a/grafana-plugin/src/containers/IntegrationForm/IntegrationForm.tsx +++ b/grafana-plugin/src/containers/IntegrationForm/IntegrationForm.tsx @@ -239,6 +239,7 @@ export const IntegrationForm = observer((props: IntegrationFormProps) => { if (!IntegrationHelper.isSpecificIntegration(selectedOption.value, 'grafana_alerting')) { pushHistory(response.id); + return; } await (data.is_existing diff --git a/grafana-plugin/src/pages/integration/Integration.helper.ts b/grafana-plugin/src/pages/integration/Integration.helper.ts index 9fd67dec..c54cc247 100644 --- a/grafana-plugin/src/pages/integration/Integration.helper.ts +++ b/grafana-plugin/src/pages/integration/Integration.helper.ts @@ -71,10 +71,6 @@ export const IntegrationHelper = { return hasSlack || hasTelegram || isMSTeamsInstalled; }, - fetchChatOps(store: RootStore): Promise { - return store.msteamsChannelStore.updateMSTeamsChannels(); - }, - getChatOpsChannels(channelFilter: ChannelFilter, store: RootStore): Array<{ name: string; icon: IconName }> { const channels: Array<{ name: string; icon: IconName }> = []; const telegram = Object.keys(store.telegramChannelStore.items).map((k) => store.telegramChannelStore.items[k]); diff --git a/grafana-plugin/src/pages/integration/Integration.tsx b/grafana-plugin/src/pages/integration/Integration.tsx index 1aa3010e..e875f8e9 100644 --- a/grafana-plugin/src/pages/integration/Integration.tsx +++ b/grafana-plugin/src/pages/integration/Integration.tsx @@ -750,8 +750,7 @@ class _IntegrationPage extends React.Component Date: Wed, 28 Feb 2024 13:19:18 +0100 Subject: [PATCH 4/6] Brojd/connect integration to snow (#3968) # What this PR does https://github.com/grafana/oncall/assets/12073649/0dad62c2-d722-4f5b-aee6-549dc97902cd ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) --- .../e2e-tests/insights/insights.test.ts | 1 + .../integrations/maintenanceMode.test.ts | 2 +- .../src/components/GTable/GTable.tsx | 4 +- .../src/components/Webhooks/WebhookName.tsx | 1 + .../AlertReceiveChannelCard.tsx | 5 +- .../alert_receive_channel.helpers.ts | 2 +- .../alert_receive_channel.ts | 18 +++- .../src/models/loader/action-keys.ts | 1 + .../src/pages/incident/Incident.tsx | 2 +- .../src/pages/incidents/Incidents.tsx | 2 +- .../src/pages/integration/Integration.tsx | 5 +- .../OutgoingTab/ConnectIntegrationModal.tsx | 84 ++++++++++++++- .../ConnectedIntegrationsTable.tsx | 101 +++++++++++------- .../OutgoingTab/OtherIntegrations.tsx | 2 +- .../OutgoingTab/OutgoingTab.styles.ts | 9 ++ .../src/pages/integrations/Integrations.tsx | 9 +- 16 files changed, 188 insertions(+), 60 deletions(-) diff --git a/grafana-plugin/e2e-tests/insights/insights.test.ts b/grafana-plugin/e2e-tests/insights/insights.test.ts index e9655de4..db2d9dd8 100644 --- a/grafana-plugin/e2e-tests/insights/insights.test.ts +++ b/grafana-plugin/e2e-tests/insights/insights.test.ts @@ -1,4 +1,5 @@ import semver from 'semver'; + import { test, expect } from '../fixtures'; import { resolveFiringAlert } from '../utils/alertGroup'; import { createEscalationChain, EscalationStep } from '../utils/escalationChain'; diff --git a/grafana-plugin/e2e-tests/integrations/maintenanceMode.test.ts b/grafana-plugin/e2e-tests/integrations/maintenanceMode.test.ts index b78e3d22..306fa4d9 100644 --- a/grafana-plugin/e2e-tests/integrations/maintenanceMode.test.ts +++ b/grafana-plugin/e2e-tests/integrations/maintenanceMode.test.ts @@ -1,7 +1,7 @@ import { test, expect, Page, Locator } from '../fixtures'; import { verifyThatAlertGroupIsRoutedCorrectlyButNotEscalated } from '../utils/alertGroup'; import { EscalationStep, createEscalationChain } from '../utils/escalationChain'; -import { clickButton, generateRandomValue, selectDropdownValue } from '../utils/forms'; +import { generateRandomValue, selectDropdownValue } from '../utils/forms'; import { assignEscalationChainToIntegration, createIntegration, diff --git a/grafana-plugin/src/components/GTable/GTable.tsx b/grafana-plugin/src/components/GTable/GTable.tsx index 212b26e8..02240fc3 100644 --- a/grafana-plugin/src/components/GTable/GTable.tsx +++ b/grafana-plugin/src/components/GTable/GTable.tsx @@ -10,7 +10,7 @@ import styles from './GTable.module.css'; const cx = cn.bind(styles); -export interface Props extends TableProps { +export interface GTableProps extends TableProps { pagination?: { page: number; total: number; @@ -31,7 +31,7 @@ export interface Props extends TableProps { showHeader?: boolean; } -export const GTable = (props: Props): ReactElement => { +export const GTable = (props: GTableProps): ReactElement => { const { columns: columnsProp, data, diff --git a/grafana-plugin/src/components/Webhooks/WebhookName.tsx b/grafana-plugin/src/components/Webhooks/WebhookName.tsx index 494e6a24..b503ee14 100644 --- a/grafana-plugin/src/components/Webhooks/WebhookName.tsx +++ b/grafana-plugin/src/components/Webhooks/WebhookName.tsx @@ -39,5 +39,6 @@ export const getStyles = () => ({ }), disabledBadge: css({ wordBreak: 'keep-all', + marginLeft: '8px', }), }); diff --git a/grafana-plugin/src/containers/AlertReceiveChannelCard/AlertReceiveChannelCard.tsx b/grafana-plugin/src/containers/AlertReceiveChannelCard/AlertReceiveChannelCard.tsx index 23f27641..e91b5ebb 100644 --- a/grafana-plugin/src/containers/AlertReceiveChannelCard/AlertReceiveChannelCard.tsx +++ b/grafana-plugin/src/containers/AlertReceiveChannelCard/AlertReceiveChannelCard.tsx @@ -39,7 +39,10 @@ export const AlertReceiveChannelCard = observer((props: AlertReceiveChannelCardP const heartbeatStatus = Boolean(heartbeat?.status); - const integration = AlertReceiveChannelHelper.getIntegration(alertReceiveChannelStore, alertReceiveChannel); + const integration = AlertReceiveChannelHelper.getIntegrationSelectOption( + alertReceiveChannelStore, + alertReceiveChannel + ); return (
diff --git a/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.helpers.ts b/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.helpers.ts index 932e21ad..99b9dac0 100644 --- a/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.helpers.ts +++ b/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.helpers.ts @@ -43,7 +43,7 @@ export class AlertReceiveChannelHelper { : undefined; } - static getIntegration( + static getIntegrationSelectOption( store: AlertReceiveChannelStore, alertReceiveChannel: Partial ): SelectOption { diff --git a/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.ts b/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.ts index 999ba481..9b75571c 100644 --- a/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.ts +++ b/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.ts @@ -5,6 +5,7 @@ import { AlertTemplatesDTO } from 'models/alert_templates/alert_templates'; import { Alert } from 'models/alertgroup/alertgroup.types'; import { ChannelFilter } from 'models/channel_filter/channel_filter.types'; import { Heartbeat } from 'models/heartbeat/heartbeat.types'; +import { ActionKey } from 'models/loader/action-keys'; import { OutgoingWebhook } from 'models/outgoing_webhook/outgoing_webhook.types'; import { makeRequest } from 'network/network'; import { ApiSchemas } from 'network/oncall-api/api.types'; @@ -12,7 +13,7 @@ import { operations } from 'network/oncall-api/autogenerated-api.types'; import { onCallApi } from 'network/oncall-api/http-client'; import { move } from 'state/helpers'; import { RootBaseStore } from 'state/rootBaseStore/RootBaseStore'; -import { WithGlobalNotification } from 'utils/decorators'; +import { AutoLoadingState, WithGlobalNotification } from 'utils/decorators'; import { OmitReadonlyMembers } from 'utils/types'; import { AlertReceiveChannelCounters, ContactPoint } from './alert_receive_channel.types'; @@ -124,20 +125,23 @@ export class AlertReceiveChannelStore { return results; } + @AutoLoadingState(ActionKey.FETCH_INTEGRATIONS) async fetchPaginatedItems({ filters, page = 1, shouldFetchCounters = false, invalidateFn = undefined, + perpage, }: { filters: operations['alert_receive_channels_list']['parameters']['query']; - page: number; - shouldFetchCounters: boolean; - invalidateFn: () => boolean; + page?: number; + shouldFetchCounters?: boolean; + invalidateFn?: () => boolean; + perpage?: number; }) { const { data: { count, results, page_size }, - } = await onCallApi().GET('/alert_receive_channels/', { params: { query: { ...filters, page } } }); + } = await onCallApi().GET('/alert_receive_channels/', { params: { query: { ...filters, page, perpage } } }); if (invalidateFn?.()) { return undefined; @@ -173,6 +177,10 @@ export class AlertReceiveChannelStore { return results; } + resetPaginatedResults() { + this.paginatedSearchResult = {}; + } + populateHearbeats(alertReceiveChannels: Array) { const heartbeats = alertReceiveChannels.reduce( (acc: any, alertReceiveChannel: ApiSchemas['AlertReceiveChannel']) => { diff --git a/grafana-plugin/src/models/loader/action-keys.ts b/grafana-plugin/src/models/loader/action-keys.ts index 10505e2a..9699dee8 100644 --- a/grafana-plugin/src/models/loader/action-keys.ts +++ b/grafana-plugin/src/models/loader/action-keys.ts @@ -8,4 +8,5 @@ export enum ActionKey { FETCH_INCIDENTS_POLLING = 'FETCH_INCIDENTS_POLLING', FETCH_INCIDENTS_AND_STATS = 'FETCH_INCIDENTS_AND_STATS', UPDATE_FILTERS_AND_FETCH_INCIDENTS = 'UPDATE_FILTERS_AND_FETCH_INCIDENTS', + FETCH_INTEGRATIONS = 'FETCH_INTEGRATIONS', } diff --git a/grafana-plugin/src/pages/incident/Incident.tsx b/grafana-plugin/src/pages/incident/Incident.tsx index e37c4937..ad97c8b4 100644 --- a/grafana-plugin/src/pages/incident/Incident.tsx +++ b/grafana-plugin/src/pages/incident/Incident.tsx @@ -273,7 +273,7 @@ class _IncidentPage extends React.Component void }) => { +const DEBOUNCE_MS = 500; + +export const ConnectIntegrationModal = observer(({ onDismiss }: { onDismiss: () => void }) => { + const { alertReceiveChannelStore } = useStore(); + const isLoading = useIsLoading(ActionKey.FETCH_INTEGRATIONS); + const commonStyles = useCommonStyles(); + const [selectedIntegrations, setSelectedIntegrations] = useState>([]); + const [page, setPage] = useState(1); const styles = useStyles2(getStyles); + const { count, results, page_size } = AlertReceiveChannelHelper.getPaginatedSearchResult(alertReceiveChannelStore); + + useEffect(() => { + fetchItems(); + return alertReceiveChannelStore.resetPaginatedResults; + }, [page]); + + const fetchItems = async (search?: string) => { + await alertReceiveChannelStore.fetchPaginatedItems({ + filters: { search }, + perpage: 10, + page, + }); + }; + + const onChange = (integration: ApiSchemas['AlertReceiveChannel'], checked) => { + if (checked) { + setSelectedIntegrations((integrations) => [...integrations, integration]); + } else { + setSelectedIntegrations((integrations) => integrations.filter(({ id }) => id !== integration.id)); + } + }; + + const onConnect = () => {}; + + const debouncedSearch = debounce(fetchItems, DEBOUNCE_MS); + + const onSearchInputChange = (searchTerm: string) => { + debouncedSearch(searchTerm); + }; + + const onChangePage = (page: number) => { + setPage(page); + }; + return ( void } closeOnBackdropClick={false} closeOnEscape onDismiss={onDismiss} + contentClassName={styles.connectIntegrationModalContent} > } placeholder="Search integrations..." + onChange={(e) => onSearchInputChange(e.currentTarget.value)} /> - + +
+ + + + +
); -}; +}); diff --git a/grafana-plugin/src/pages/integration/OutgoingTab/ConnectedIntegrationsTable.tsx b/grafana-plugin/src/pages/integration/OutgoingTab/ConnectedIntegrationsTable.tsx index 63efa48c..675e6170 100644 --- a/grafana-plugin/src/pages/integration/OutgoingTab/ConnectedIntegrationsTable.tsx +++ b/grafana-plugin/src/pages/integration/OutgoingTab/ConnectedIntegrationsTable.tsx @@ -1,57 +1,78 @@ import React, { FC } from 'react'; -import { HorizontalGroup, Tooltip, Icon, useStyles2, IconButton, Switch } from '@grafana/ui'; +import { HorizontalGroup, Tooltip, Icon, useStyles2, IconButton, Switch, Checkbox } from '@grafana/ui'; +import { observer } from 'mobx-react'; -import { GTable } from 'components/GTable/GTable'; +import { GTable, GTableProps } from 'components/GTable/GTable'; import { IntegrationLogoWithTitle } from 'components/IntegrationLogo/IntegrationLogoWithTitle'; import { Text } from 'components/Text/Text'; +import { AlertReceiveChannelHelper } from 'models/alert_receive_channel/alert_receive_channel.helpers'; +import { ApiSchemas } from 'network/oncall-api/api.types'; +import { useStore } from 'state/useStore'; import { getStyles } from './OutgoingTab.styles'; interface ConnectedIntegrationsTableProps { allowDelete?: boolean; + allowBacksync?: boolean; + selectable?: boolean; + onChange?: (integration: ApiSchemas['AlertReceiveChannel'], checked: boolean) => void; + tableProps: GTableProps; } -const ConnectedIntegrationsTable: FC = (props) => { - const FAKE_INTEGRATIONS = [{ a: 'a' }]; +const ConnectedIntegrationsTable: FC = observer( + ({ selectable, allowDelete, onChange, tableProps, allowBacksync }) => { + const { alertReceiveChannelStore } = useStore(); - return ( - - ); -}; + const columns = [ + ...(selectable + ? [ + { + width: '5%', + render: (integration: ApiSchemas['AlertReceiveChannel']) => ( + onChange(integration, event.currentTarget.checked)} /> + ), + }, + ] + : []), + { + width: '45%', + title: Integration name, + dataIndex: 'verbal_name', + render: (name: string) => name, + }, + { + width: '55%', + title: Type, + render: (integration: ApiSchemas['AlertReceiveChannel']) => ( + + ), + }, + ...(allowBacksync + ? [ + { + title: ( + + Backsync + Switch on to start sending data from other integrations}> + + + + ), + render: BacksyncSwitcher, + }, + ] + : []), + { + render: () => , + }, + ]; -const getColumns = ({ allowDelete }: ConnectedIntegrationsTableProps) => [ - { - width: '45%', - title: Integration name, - dataIndex: 'trigger_type_name', - render: () => <>Some integration name, - }, - { - width: '55%', - title: Type, - render: () => , - }, - { - title: ( - - Backsync - Switch on to start sending data from other integrations}> - - - - ), - render: BacksyncSwitcher, - }, - { - render: () => , - }, -]; + return ; + } +); const BacksyncSwitcher = () => { const styles = useStyles2(getStyles); diff --git a/grafana-plugin/src/pages/integration/OutgoingTab/OtherIntegrations.tsx b/grafana-plugin/src/pages/integration/OutgoingTab/OtherIntegrations.tsx index 6fcf1c87..02cef51e 100644 --- a/grafana-plugin/src/pages/integration/OutgoingTab/OtherIntegrations.tsx +++ b/grafana-plugin/src/pages/integration/OutgoingTab/OtherIntegrations.tsx @@ -24,7 +24,7 @@ export const OtherIntegrations = observer(() => { } - content={} + content={} /> ); diff --git a/grafana-plugin/src/pages/integration/OutgoingTab/OutgoingTab.styles.ts b/grafana-plugin/src/pages/integration/OutgoingTab/OutgoingTab.styles.ts index d4739707..7d6d30e0 100644 --- a/grafana-plugin/src/pages/integration/OutgoingTab/OutgoingTab.styles.ts +++ b/grafana-plugin/src/pages/integration/OutgoingTab/OutgoingTab.styles.ts @@ -58,6 +58,9 @@ export const getStyles = (theme: GrafanaTheme2) => ({ backsyncColumn: css({ display: 'flex', justifyContent: 'flex-end', + '& label': { + position: 'relative', + }, }), triggerTemplateWrapper: css({ position: 'relative', @@ -77,4 +80,10 @@ export const getStyles = (theme: GrafanaTheme2) => ({ tabsWrapper: css({ padding: '16px 16px 0 8px', }), + connectIntegrationModalContent: css({ + paddingBottom: 0, + }), + connectIntegrationModalButtons: css({ + marginTop: '50px', + }), }); diff --git a/grafana-plugin/src/pages/integrations/Integrations.tsx b/grafana-plugin/src/pages/integrations/Integrations.tsx index 2e09ed0c..a26720b1 100644 --- a/grafana-plugin/src/pages/integrations/Integrations.tsx +++ b/grafana-plugin/src/pages/integrations/Integrations.tsx @@ -122,6 +122,10 @@ class _IntegrationsPage extends React.Component { const { store, @@ -353,7 +357,10 @@ class _IntegrationsPage extends React.Component Date: Wed, 28 Feb 2024 10:38:11 -0700 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff7c7ee9..2333bb93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## v1.3.108 (2024-02-28) + +### Fixed + +- Fetch selected value of notify schedule in escalation policy, fixes ([#3966](https://github.com/grafana/oncall/issues/3966)) ([#3969](https://github.com/grafana/oncall/pull/3969)) ## v1.3.107 (2024-02-27) From cd55301a7644cdbe99fae04bd6dde11c11e52bfe Mon Sep 17 00:00:00 2001 From: Michael Derynck Date: Wed, 28 Feb 2024 10:53:20 -0700 Subject: [PATCH 6/6] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2333bb93..a3db06ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Fetch selected value of notify schedule in escalation policy, fixes ([#3966](https://github.com/grafana/oncall/issues/3966)) ([#3969](https://github.com/grafana/oncall/pull/3969)) +- Fetch selected value of notify schedule in escalation policy, fixes ([#3966](https://github.com/grafana/oncall/issues/3966)) + ([#3969](https://github.com/grafana/oncall/pull/3969)) ## v1.3.107 (2024-02-27)