From 3f03450a3b724753846cb4b93d9d1faeb95684e4 Mon Sep 17 00:00:00 2001 From: kagora Date: Thu, 15 Jan 2026 16:44:51 +0100 Subject: [PATCH 1/2] change: [DPS-35018] - Logs: Add new status - Provisioning --- packages/api-v4/src/delivery/types.ts | 1 + .../Shared/FormSubmitBar/FormSubmitBar.tsx | 3 ++ .../src/features/Delivery/Shared/types.ts | 5 +++ .../Delivery/Streams/StreamActionMenu.tsx | 1 + .../Streams/StreamForm/StreamEdit.test.tsx | 42 +++++++++++++++++++ .../Streams/StreamForm/StreamForm.tsx | 21 +++++++++- .../Delivery/Streams/StreamTableRow.tsx | 8 +++- packages/validation/src/delivery.schema.ts | 10 +++-- 8 files changed, 85 insertions(+), 6 deletions(-) diff --git a/packages/api-v4/src/delivery/types.ts b/packages/api-v4/src/delivery/types.ts index cb8691f8211..84f2d82460a 100644 --- a/packages/api-v4/src/delivery/types.ts +++ b/packages/api-v4/src/delivery/types.ts @@ -1,6 +1,7 @@ export const streamStatus = { Active: 'active', Inactive: 'inactive', + Provisioning: 'provisioning', } as const; export type StreamStatus = (typeof streamStatus)[keyof typeof streamStatus]; diff --git a/packages/manager/src/features/Delivery/Shared/FormSubmitBar/FormSubmitBar.tsx b/packages/manager/src/features/Delivery/Shared/FormSubmitBar/FormSubmitBar.tsx index 640d6093ce5..80e8ecfcad4 100644 --- a/packages/manager/src/features/Delivery/Shared/FormSubmitBar/FormSubmitBar.tsx +++ b/packages/manager/src/features/Delivery/Shared/FormSubmitBar/FormSubmitBar.tsx @@ -21,6 +21,7 @@ interface StreamFormSubmitBarProps { mode: FormMode; onSubmit: () => void; onTestConnection: () => void; + submitButtonTooltip?: string; } export const FormSubmitBar = (props: StreamFormSubmitBarProps) => { @@ -35,6 +36,7 @@ export const FormSubmitBar = (props: StreamFormSubmitBarProps) => { isSubmitting, isTesting, disableTestConnection = false, + submitButtonTooltip, } = props; const capitalizedFormType = capitalize(formType); @@ -108,6 +110,7 @@ export const FormSubmitBar = (props: StreamFormSubmitBarProps) => { alignSelf: 'flex-end', }, })} + tooltipText={submitButtonTooltip} > {buttonLabel} diff --git a/packages/manager/src/features/Delivery/Shared/types.ts b/packages/manager/src/features/Delivery/Shared/types.ts index 205e44573bd..ee312d80896 100644 --- a/packages/manager/src/features/Delivery/Shared/types.ts +++ b/packages/manager/src/features/Delivery/Shared/types.ts @@ -48,6 +48,11 @@ export const streamStatusOptions: AutocompleteOption[] = [ label: 'Inactive', pendoId: 'Logs Delivery Streams-Status Inactive', }, + { + value: streamStatus.Provisioning, + label: 'Provisioning', + pendoId: 'Logs Delivery Streams-Status Provisioning', + }, ]; export type DestinationDetailsForm = diff --git a/packages/manager/src/features/Delivery/Streams/StreamActionMenu.tsx b/packages/manager/src/features/Delivery/Streams/StreamActionMenu.tsx index f976acd4096..97078a82672 100644 --- a/packages/manager/src/features/Delivery/Streams/StreamActionMenu.tsx +++ b/packages/manager/src/features/Delivery/Streams/StreamActionMenu.tsx @@ -32,6 +32,7 @@ export const StreamActionMenu = (props: StreamActionMenuProps) => { }, title: stream.status === streamStatus.Active ? 'Deactivate' : 'Activate', pendoId: `Logs Delivery Streams-${stream.status === streamStatus.Active ? 'Deactivate' : 'Activate'}`, + disabled: stream.status === streamStatus.Provisioning, }, { onClick: () => { diff --git a/packages/manager/src/features/Delivery/Streams/StreamForm/StreamEdit.test.tsx b/packages/manager/src/features/Delivery/Streams/StreamForm/StreamEdit.test.tsx index 2d1eaacd74b..7b0d5f6c18f 100644 --- a/packages/manager/src/features/Delivery/Streams/StreamForm/StreamEdit.test.tsx +++ b/packages/manager/src/features/Delivery/Streams/StreamForm/StreamEdit.test.tsx @@ -224,6 +224,48 @@ describe('StreamEdit', () => { expect(editStreamSpy).toHaveBeenCalled(); }); }); + + describe('and stream has status: provisioning', () => { + it('should have disabled Edit Stream button and show info tooltip', async () => { + server.use( + http.get('*/monitor/streams/destinations', () => { + return HttpResponse.json(makeResourcePage(mockDestinations)); + }), + http.get(`*/monitor/streams/${streamId}`, () => { + return HttpResponse.json({ + ...mockStream, + status: 'provisioning', + }); + }) + ); + + renderWithThemeAndHookFormContext({ + component: , + }); + const loadingElement = screen.queryByTestId(loadingTestId); + await waitForElementToBeRemoved(loadingElement); + + const editStreamButton = screen.getByRole('button', { + name: saveStreamButtonText, + }); + + // Edit stream button should be disabled + expect(editStreamButton).toBeDisabled(); + + // Edit stream + await userEvent.hover(editStreamButton); + + await waitFor(() => { + expect(screen.getByRole('tooltip')).toBeInTheDocument(); + }); + + const disabledButtonTooltip = screen.getByText( + 'You cannot save changes while the stream is provisioning.' + ); + + expect(disabledButtonTooltip).toBeInTheDocument(); + }); + }); }); }); diff --git a/packages/manager/src/features/Delivery/Streams/StreamForm/StreamForm.tsx b/packages/manager/src/features/Delivery/Streams/StreamForm/StreamForm.tsx index 6ac55bb6ff8..19b01c72a73 100644 --- a/packages/manager/src/features/Delivery/Streams/StreamForm/StreamForm.tsx +++ b/packages/manager/src/features/Delivery/Streams/StreamForm/StreamForm.tsx @@ -1,5 +1,6 @@ import { type CreateDestinationPayload, + streamStatus, type StreamStatus, streamType, } from '@linode/api-v4'; @@ -14,7 +15,7 @@ import Grid from '@mui/material/Grid'; import { useNavigate } from '@tanstack/react-router'; import { enqueueSnackbar } from 'notistack'; import * as React from 'react'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { type SubmitHandler, useFormContext, useWatch } from 'react-hook-form'; import { @@ -72,6 +73,18 @@ export const StreamForm = (props: StreamFormProps) => { name: 'destination', }); + const selectedStreamStatus = useWatch({ + control, + name: 'stream.status', + }); + const submitButtonTooltip = useMemo( + () => + selectedStreamStatus === streamStatus.Provisioning + ? 'You cannot save changes while the stream is provisioning.' + : undefined, + [selectedStreamStatus] + ); + useEffect(() => { setDestinationVerified(false); }, [destination, setDestinationVerified]); @@ -194,7 +207,10 @@ export const StreamForm = (props: StreamFormProps) => { { scrollErrorIntoViewV2(formRef) )} onTestConnection={handleTestConnection} + submitButtonTooltip={submitButtonTooltip} /> diff --git a/packages/manager/src/features/Delivery/Streams/StreamTableRow.tsx b/packages/manager/src/features/Delivery/Streams/StreamTableRow.tsx index 8184c7f33f9..44b92c1fddc 100644 --- a/packages/manager/src/features/Delivery/Streams/StreamTableRow.tsx +++ b/packages/manager/src/features/Delivery/Streams/StreamTableRow.tsx @@ -13,6 +13,7 @@ import { LinkWithTooltipAndEllipsis } from 'src/features/Delivery/Shared/LinkWit import { StreamActionMenu } from 'src/features/Delivery/Streams/StreamActionMenu'; import type { Stream, StreamStatus } from '@linode/api-v4'; +import type { Status } from 'src/components/StatusIcon/StatusIcon'; import type { StreamHandlers } from 'src/features/Delivery/Streams/StreamActionMenu'; interface StreamTableRowProps extends StreamHandlers { @@ -22,6 +23,9 @@ interface StreamTableRowProps extends StreamHandlers { export const StreamTableRow = React.memo((props: StreamTableRowProps) => { const { stream, onDelete, onDisableOrEnable, onEdit } = props; const { id, status } = stream; + const iconStatus = ( + ['active', 'error', 'inactive'].includes(status) ? status : 'other' + ) as Status; return ( @@ -35,7 +39,7 @@ export const StreamTableRow = React.memo((props: StreamTableRowProps) => { {getStreamTypeOption(stream.type)?.label} - + {humanizeStreamStatus(status)} {id} @@ -70,6 +74,8 @@ const humanizeStreamStatus = (status: StreamStatus) => { return 'Active'; case 'inactive': return 'Inactive'; + case 'provisioning': + return 'Provisioning'; default: return 'Unknown'; } diff --git a/packages/validation/src/delivery.schema.ts b/packages/validation/src/delivery.schema.ts index 28a183b16f5..465748b70e6 100644 --- a/packages/validation/src/delivery.schema.ts +++ b/packages/validation/src/delivery.schema.ts @@ -212,7 +212,11 @@ const streamSchemaBase = object({ .min(3, 'Stream name must have at least 3 characters') .max(maxLength, maxLengthMessage) .required('Stream name is required.'), - status: mixed<'active' | 'inactive'>().oneOf(['active', 'inactive']), + status: mixed<'active' | 'inactive' | 'provisioning'>().oneOf([ + 'active', + 'inactive', + 'provisioning', + ]), type: string() .oneOf(['audit_logs', 'lke_audit_logs']) .required('Stream type is required.'), @@ -229,8 +233,8 @@ export const createStreamSchema = streamSchemaBase; export const updateStreamSchema = streamSchemaBase .omit(['type']) .shape({ - status: mixed<'active' | 'inactive'>() - .oneOf(['active', 'inactive']) + status: mixed<'active' | 'inactive' | 'provisioning'>() + .oneOf(['active', 'inactive', 'provisioning']) .required(), details: lazy((value) => { if ( From 8ad2a5fd0a701abdf9365fa734f7ad3f68922bd3 Mon Sep 17 00:00:00 2001 From: kagora Date: Fri, 16 Jan 2026 08:57:31 +0100 Subject: [PATCH 2/2] Added changeset: Logs Stream - Provisioning status --- packages/manager/.changeset/pr-13284-added-1768550251063.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-13284-added-1768550251063.md diff --git a/packages/manager/.changeset/pr-13284-added-1768550251063.md b/packages/manager/.changeset/pr-13284-added-1768550251063.md new file mode 100644 index 00000000000..221c78b9716 --- /dev/null +++ b/packages/manager/.changeset/pr-13284-added-1768550251063.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Added +--- + +Logs Stream - Provisioning status ([#13284](https://github.com/linode/manager/pull/13284))