diff --git a/packages/api-v4/src/delivery/types.ts b/packages/api-v4/src/delivery/types.ts
index 384cf4a7b26..97f2202f0b9 100644
--- a/packages/api-v4/src/delivery/types.ts
+++ b/packages/api-v4/src/delivery/types.ts
@@ -1,5 +1,7 @@
export const streamStatus = {
Active: 'active',
+ Deactivating: 'deactivating',
+ Failed: 'failed',
Inactive: 'inactive',
Provisioning: 'provisioning',
} as const;
diff --git a/packages/manager/.changeset/pr-13551-added-1774974854479.md b/packages/manager/.changeset/pr-13551-added-1774974854479.md
new file mode 100644
index 00000000000..882d080c970
--- /dev/null
+++ b/packages/manager/.changeset/pr-13551-added-1774974854479.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Added
+---
+
+New stream statuses - deactivating, failed ([#13551](https://github.com/linode/manager/pull/13551))
diff --git a/packages/manager/src/features/Delivery/Shared/types.ts b/packages/manager/src/features/Delivery/Shared/types.ts
index 9373632cf7c..bddacb55f08 100644
--- a/packages/manager/src/features/Delivery/Shared/types.ts
+++ b/packages/manager/src/features/Delivery/Shared/types.ts
@@ -49,6 +49,16 @@ export const streamStatusOptions: AutocompleteOption[] = [
label: 'Active',
pendoId: 'Logs Delivery Streams-Status Active',
},
+ {
+ value: streamStatus.Deactivating,
+ label: 'Deactivating',
+ pendoId: 'Logs Delivery Streams-Status Deactivating',
+ },
+ {
+ value: streamStatus.Failed,
+ label: 'Failed',
+ pendoId: 'Logs Delivery Streams-Status Failed',
+ },
{
value: streamStatus.Inactive,
label: 'Inactive',
diff --git a/packages/manager/src/features/Delivery/Streams/StreamActionMenu.tsx b/packages/manager/src/features/Delivery/Streams/StreamActionMenu.tsx
index 97078a82672..8b4c20396ff 100644
--- a/packages/manager/src/features/Delivery/Streams/StreamActionMenu.tsx
+++ b/packages/manager/src/features/Delivery/Streams/StreamActionMenu.tsx
@@ -17,6 +17,7 @@ interface StreamActionMenuProps extends StreamHandlers {
export const StreamActionMenu = (props: StreamActionMenuProps) => {
const { stream, onDelete, onDisableOrEnable, onEdit } = props;
+ const { status, label } = stream;
const menuActions: Action[] = [
{
@@ -30,9 +31,12 @@ export const StreamActionMenu = (props: StreamActionMenuProps) => {
onClick: () => {
onDisableOrEnable(stream);
},
- title: stream.status === streamStatus.Active ? 'Deactivate' : 'Activate',
- pendoId: `Logs Delivery Streams-${stream.status === streamStatus.Active ? 'Deactivate' : 'Activate'}`,
- disabled: stream.status === streamStatus.Provisioning,
+ title: status === streamStatus.Active ? 'Deactivate' : 'Activate',
+ pendoId: `Logs Delivery Streams-${status === streamStatus.Active ? 'Deactivate' : 'Activate'}`,
+ disabled:
+ status === streamStatus.Deactivating ||
+ status === streamStatus.Failed ||
+ status === streamStatus.Provisioning,
},
{
onClick: () => {
@@ -46,7 +50,7 @@ export const StreamActionMenu = (props: StreamActionMenuProps) => {
return (
);
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 4f2850ff542..be8fb54644f 100644
--- a/packages/manager/src/features/Delivery/Streams/StreamForm/StreamEdit.test.tsx
+++ b/packages/manager/src/features/Delivery/Streams/StreamForm/StreamEdit.test.tsx
@@ -1,3 +1,4 @@
+import { streamStatus } from '@linode/api-v4';
import {
screen,
waitFor,
@@ -241,47 +242,63 @@ describe('StreamEdit', () => {
});
});
- 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 blockingStatuses = [
+ streamStatus.Deactivating,
+ streamStatus.Failed,
+ streamStatus.Provisioning,
+ ];
+
+ describe.each(blockingStatuses)(
+ 'and stream has status: %status',
+ (status) => {
+ 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,
+ });
+ })
+ );
+
+ 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 screen.findByRole('tooltip');
+
+ screen.getByText((content) =>
+ content.includes(
+ `You cannot save changes while the stream status is ${status}`
+ )
+ );
+
+ const disabledButtonTooltip = screen.getByText((content) =>
+ content.includes(
+ `You cannot save changes while the stream status is ${status}`
+ )
+ );
+
+ expect(disabledButtonTooltip).toBeInTheDocument();
});
- 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 8ede47204b6..c046a35c226 100644
--- a/packages/manager/src/features/Delivery/Streams/StreamForm/StreamForm.tsx
+++ b/packages/manager/src/features/Delivery/Streams/StreamForm/StreamForm.tsx
@@ -77,12 +77,23 @@ export const StreamForm = (props: StreamFormProps) => {
control,
name: 'stream.status',
});
+
+ const isStreamStatusBlocking =
+ !!selectedStreamStatus &&
+ (
+ [
+ streamStatus.Provisioning,
+ streamStatus.Deactivating,
+ streamStatus.Failed,
+ ] as StreamStatus[]
+ ).includes(selectedStreamStatus);
+
const submitButtonTooltip = useMemo(
() =>
- selectedStreamStatus === streamStatus.Provisioning
- ? 'You cannot save changes while the stream is provisioning.'
+ isStreamStatusBlocking
+ ? `You cannot save changes while the stream status is ${selectedStreamStatus}`
: undefined,
- [selectedStreamStatus]
+ [isStreamStatusBlocking, selectedStreamStatus]
);
useEffect(() => {
@@ -212,8 +223,7 @@ export const StreamForm = (props: StreamFormProps) => {
{
const { stream, onDelete, onDisableOrEnable, onEdit } = props;
const { id, status } = stream;
- const iconStatus = (
- ['active', 'error', 'inactive'].includes(status) ? status : 'other'
- ) as Status;
+ const iconStatus = ((): Status => {
+ if (status === 'failed') return 'error';
+ if (['active', 'error', 'inactive'].includes(status)) {
+ return status as Status;
+ }
+ return 'other';
+ })();
return (
@@ -72,6 +76,10 @@ const humanizeStreamStatus = (status: StreamStatus) => {
switch (status) {
case 'active':
return 'Active';
+ case 'deactivating':
+ return 'Deactivating';
+ case 'failed':
+ return 'Failed';
case 'inactive':
return 'Inactive';
case 'provisioning':
diff --git a/packages/validation/src/delivery.schema.ts b/packages/validation/src/delivery.schema.ts
index 530cdfafa85..06b36f37420 100644
--- a/packages/validation/src/delivery.schema.ts
+++ b/packages/validation/src/delivery.schema.ts
@@ -351,11 +351,9 @@ 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' | 'provisioning'>().oneOf([
- 'active',
- 'inactive',
- 'provisioning',
- ]),
+ status: mixed<
+ 'active' | 'deactivating' | 'failed' | 'inactive' | 'provisioning'
+ >().oneOf(['active', 'deactivating', 'failed', 'inactive', 'provisioning']),
type: string()
.oneOf(['audit_logs', 'lke_audit_logs'])
.required('Stream type is required.'),
@@ -372,8 +370,10 @@ export const createStreamSchema = streamSchemaBase;
export const updateStreamSchema = streamSchemaBase
.omit(['type'])
.shape({
- status: mixed<'active' | 'inactive' | 'provisioning'>()
- .oneOf(['active', 'inactive', 'provisioning'])
+ status: mixed<
+ 'active' | 'deactivating' | 'failed' | 'inactive' | 'provisioning'
+ >()
+ .oneOf(['active', 'deactivating', 'failed', 'inactive', 'provisioning'])
.required(),
details: lazy((value) => {
if (