From 16b3d79563b0ca8b5db4bcd3968ec77abba2277b Mon Sep 17 00:00:00 2001
From: Hussain Khalil <122488130+hkhalil-akamai@users.noreply.github.com>
Date: Wed, 28 Jun 2023 08:15:25 -0400
Subject: [PATCH 01/12] hotfix: Notification Menu crash due to null value
(#9331)
---
packages/api-v4/CHANGELOG.md | 7 +++++++
packages/api-v4/package.json | 2 +-
packages/api-v4/src/account/types.ts | 2 +-
packages/manager/CHANGELOG.md | 7 +++++++
packages/manager/package.json | 2 +-
packages/manager/src/eventMessageGenerator.test.ts | 13 +++++++++++++
packages/manager/src/eventMessageGenerator.ts | 12 ++++++------
7 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/packages/api-v4/CHANGELOG.md b/packages/api-v4/CHANGELOG.md
index 4722e941992..17811bae3c5 100644
--- a/packages/api-v4/CHANGELOG.md
+++ b/packages/api-v4/CHANGELOG.md
@@ -1,3 +1,10 @@
+## [2023-06-27] - v0.95.1
+
+
+### Fixed:
+
+- Updated Entity interface to reflect the possibility of a null label ([#9331](https://github.com/linode/manager/pull/9331))
+
## [2023-06-26] - v0.95.0
### Added:
diff --git a/packages/api-v4/package.json b/packages/api-v4/package.json
index 4fdc0fff985..4920f6ba031 100644
--- a/packages/api-v4/package.json
+++ b/packages/api-v4/package.json
@@ -1,6 +1,6 @@
{
"name": "@linode/api-v4",
- "version": "0.95.0",
+ "version": "0.95.1",
"homepage": "https://github.com/linode/manager/tree/develop/packages/api-v4",
"bugs": {
"url": "https://github.com/linode/manager/issues"
diff --git a/packages/api-v4/src/account/types.ts b/packages/api-v4/src/account/types.ts
index 2b71fb9a8e1..c0e7d854f2b 100644
--- a/packages/api-v4/src/account/types.ts
+++ b/packages/api-v4/src/account/types.ts
@@ -223,7 +223,7 @@ export interface Notification {
export interface Entity {
id: number;
- label: string;
+ label: string | null;
type: string;
url: string;
}
diff --git a/packages/manager/CHANGELOG.md b/packages/manager/CHANGELOG.md
index 7d2356fdceb..28a1647bd1b 100644
--- a/packages/manager/CHANGELOG.md
+++ b/packages/manager/CHANGELOG.md
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
+## [2023-06-27] - v1.96.1
+
+
+### Fixed:
+
+- Crash when viewing notifications due to `null` label in event entity ([#9331](https://github.com/linode/manager/pull/9331))
+
## [2023-06-26] - v1.96.0
### Added:
diff --git a/packages/manager/package.json b/packages/manager/package.json
index 3544425f279..81fd42b037a 100644
--- a/packages/manager/package.json
+++ b/packages/manager/package.json
@@ -2,7 +2,7 @@
"name": "linode-manager",
"author": "Linode",
"description": "The Linode Manager website",
- "version": "1.96.0",
+ "version": "1.96.1",
"private": true,
"bugs": {
"url": "https://github.com/Linode/manager/issues"
diff --git a/packages/manager/src/eventMessageGenerator.test.ts b/packages/manager/src/eventMessageGenerator.test.ts
index 015ed63eb6f..7dd2873096c 100644
--- a/packages/manager/src/eventMessageGenerator.test.ts
+++ b/packages/manager/src/eventMessageGenerator.test.ts
@@ -141,5 +141,18 @@ describe('Event message generation', () => {
'created entity Weird label with special characters.(?) '
);
});
+
+ it('should work when label is null', () => {
+ const mockEvent = eventFactory.build({
+ entity: entityFactory.build({
+ id: 10,
+ label: null,
+ }),
+ });
+ const message = 'created entity Null label';
+ const result = applyLinking(mockEvent, message);
+
+ expect(result).toEqual('created entity Null label');
+ });
});
});
diff --git a/packages/manager/src/eventMessageGenerator.ts b/packages/manager/src/eventMessageGenerator.ts
index f5055b167ec..718144a6b87 100644
--- a/packages/manager/src/eventMessageGenerator.ts
+++ b/packages/manager/src/eventMessageGenerator.ts
@@ -54,19 +54,19 @@ export const eventMessageCreators: { [index: string]: CreatorsForStatus } = {
},
community_question_reply: {
notification: (e) =>
- e.entity
+ e.entity?.label
? `There has been a reply to your thread "${e.entity.label}".`
: `There has been a reply to your thread.`,
},
community_like: {
notification: (e) =>
- e.entity
+ e.entity?.label
? `A post on "${e.entity.label}" has been liked.`
: `There has been a like on your community post.`,
},
community_mention: {
notification: (e) =>
- e.entity
+ e.entity?.label
? `You have been mentioned in a Community post: ${e.entity.label}.`
: `You have been mentioned in a Community post.`,
},
@@ -790,7 +790,7 @@ export default (e: Event): string => {
/** finally return some default fallback text */
return e.message
? formatEventWithAPIMessage(e)
- : `${e.action}${e.entity ? ` on ${e.entity.label}` : ''}`;
+ : `${e.action}${e.entity?.label ? ` on ${e.entity.label}` : ''}`;
}
let message = '';
@@ -872,7 +872,7 @@ export function applyLinking(event: Event, message: string) {
let newMessage = message;
- if (event.entity && entityLinkTarget) {
+ if (event.entity?.label && entityLinkTarget) {
const label = event.entity.label;
const nonTickedLabels = new RegExp(`(?${event.secondary_entity.label}`
From c335cb183948ab67cf6d1b2eb0fa1fd4de3ced20 Mon Sep 17 00:00:00 2001
From: Alban Bailly
Date: Wed, 28 Jun 2023 15:54:35 -0400
Subject: [PATCH 02/12] Fix: [M3-6800] improve FW custom ports validation
---
.../Rules/FirewallRuleDrawer.utils.ts | 4 +-
packages/validation/src/firewalls.schema.ts | 90 +++++++++++++++++--
2 files changed, 86 insertions(+), 8 deletions(-)
diff --git a/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.utils.ts b/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.utils.ts
index fad2eb3658b..5351b3fe68b 100644
--- a/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.utils.ts
+++ b/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.utils.ts
@@ -12,8 +12,8 @@ import {
predefinedFirewallFromRule,
} from 'src/features/Firewalls/shared';
import {
- CUSTOM_PORTS_VALIDATION_REGEX,
CUSTOM_PORTS_ERROR_MESSAGE,
+ runCustomPortsValidation,
} from '@linode/validation';
import type {
FirewallRuleProtocol,
@@ -332,7 +332,7 @@ export const validateForm = ({
if ((protocol === 'ICMP' || protocol === 'IPENCAP') && ports) {
errors.ports = `Ports are not allowed for ${protocol} protocols.`;
- } else if (ports && !ports.match(CUSTOM_PORTS_VALIDATION_REGEX)) {
+ } else if (ports && !runCustomPortsValidation(ports)) {
errors.ports = CUSTOM_PORTS_ERROR_MESSAGE;
}
diff --git a/packages/validation/src/firewalls.schema.ts b/packages/validation/src/firewalls.schema.ts
index b9aa0d36946..38754ca85e1 100644
--- a/packages/validation/src/firewalls.schema.ts
+++ b/packages/validation/src/firewalls.schema.ts
@@ -5,8 +5,8 @@ import { array, mixed, number, object, string } from 'yup';
export const IP_ERROR_MESSAGE =
'Must be a valid IPv4 or IPv6 address or range.';
-export const CUSTOM_PORTS_ERROR_MESSAGE =
- 'Ports must be an integer, range of integers, or a comma-separated list of integers.';
+// export const CUSTOM_PORTS_ERROR_MESSAGE =
+// 'Ports must be an integer, range of integers, or a comma-separated list of integers.';
export const CUSTOM_PORTS_VALIDATION_REGEX = /^(?:\d+|\d+-\d+|(?:\d+,\s*)*\d+)$/;
export const validateIP = (ipAddress?: string | null): boolean => {
@@ -42,10 +42,88 @@ export const ipAddress = string().test({
test: validateIP,
});
-export const validateFirewallPorts = string().matches(
- CUSTOM_PORTS_VALIDATION_REGEX,
- CUSTOM_PORTS_ERROR_MESSAGE
-);
+export let CUSTOM_PORTS_ERROR_MESSAGE =
+ 'Ports must be an integer, range of integers, or a comma-separated list of integers.';
+
+const validatePort = (port: string): boolean => {
+ if (!port) {
+ CUSTOM_PORTS_ERROR_MESSAGE = 'Must be 1-65535';
+ return false;
+ }
+
+ const convertedPort = parseInt(port, 10);
+ if (!(1 <= convertedPort && convertedPort <= 65535)) {
+ CUSTOM_PORTS_ERROR_MESSAGE = 'Must be 1-65535';
+ return false;
+ }
+
+ if (String(convertedPort) !== port) {
+ CUSTOM_PORTS_ERROR_MESSAGE = 'Port must not have leading zeroes';
+ return false;
+ }
+
+ return true;
+};
+
+export const runCustomPortsValidation = (value: string): boolean => {
+ const portList = value?.split(',') || [];
+ let portLimitCount = 0;
+
+ for (const port of portList) {
+ const cleanedPort = port.trim();
+
+ if (cleanedPort.includes('-')) {
+ const portRange = cleanedPort.split('-');
+
+ if (!validatePort(portRange[0]) || !validatePort(portRange[1])) {
+ return false;
+ }
+
+ if (portRange.length !== 2) {
+ CUSTOM_PORTS_ERROR_MESSAGE = 'Ranges must have 2 values';
+ return false;
+ }
+
+ if (parseInt(portRange[0], 10) >= parseInt(portRange[1], 10)) {
+ CUSTOM_PORTS_ERROR_MESSAGE =
+ 'Range must start with a smaller number and end with a larger number';
+ return false;
+ }
+
+ portLimitCount += 2;
+ } else {
+ if (!validatePort(cleanedPort)) {
+ return false;
+ }
+ portLimitCount++;
+ }
+ }
+
+ if (portLimitCount > 15) {
+ CUSTOM_PORTS_ERROR_MESSAGE =
+ 'Number of ports or port range endpoints exceeded. Max allowed is 15';
+ return false;
+ }
+
+ return true;
+};
+
+const validateFirewallPorts = string().test({
+ name: 'firewall-ports',
+ message: CUSTOM_PORTS_ERROR_MESSAGE,
+ test: (value) => {
+ if (!value) {
+ return false;
+ }
+
+ try {
+ runCustomPortsValidation(value);
+ } catch (err) {
+ return false;
+ }
+ return true;
+ },
+});
const validFirewallRuleProtocol = ['ALL', 'TCP', 'UDP', 'ICMP', 'IPENCAP'];
export const FirewallRuleTypeSchema = object().shape({
From ffd6a142089b0465d6f1397e5033ce3d7775a768 Mon Sep 17 00:00:00 2001
From: Alban Bailly
Date: Wed, 28 Jun 2023 16:05:56 -0400
Subject: [PATCH 03/12] Fix: [M3-6800] increased test coverage
---
.../Rules/FirewallRuleDrawer.test.tsx | 47 +++++++++++++------
1 file changed, 33 insertions(+), 14 deletions(-)
diff --git a/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.test.tsx b/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.test.tsx
index 124d37fddb7..2715d6b6de8 100644
--- a/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.test.tsx
+++ b/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.test.tsx
@@ -121,7 +121,8 @@ describe('utilities', () => {
label: 'Firewalllabel',
addresses: 'All IPv4',
};
- expect(validateForm({ protocol: 'TCP', ports: '1', ...rest })).toEqual(
+ // SUCCESS CASES
+ expect(validateForm({ protocol: 'TCP', ports: '1234', ...rest })).toEqual(
{}
);
expect(
@@ -134,28 +135,46 @@ describe('utilities', () => {
{}
);
expect(
- validateForm({ protocol: 'TCP', ports: 'abc', ...rest })
- ).toHaveProperty(
- 'ports',
- 'Ports must be an integer, range of integers, or a comma-separated list of integers.'
- );
- expect(
- validateForm({ protocol: 'TCP', ports: '1--20', ...rest })
- ).toHaveProperty(
- 'ports',
- 'Ports must be an integer, range of integers, or a comma-separated list of integers.'
- );
+ validateForm({
+ protocol: 'TCP',
+ ports: '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15',
+ ...rest,
+ })
+ ).toEqual({});
expect(
validateForm({ protocol: 'TCP', ports: '1-2,3-4', ...rest })
+ ).toEqual({});
+ expect(
+ validateForm({ protocol: 'TCP', ports: '1,5-12', ...rest })
+ ).toEqual({});
+ // FAILURE CASES
+ expect(
+ validateForm({ protocol: 'TCP', ports: '1,21-12', ...rest })
).toHaveProperty(
'ports',
- 'Ports must be an integer, range of integers, or a comma-separated list of integers.'
+ 'Range must start with a smaller number and end with a larger number'
);
+ expect(
+ validateForm({ protocol: 'TCP', ports: '1-21-45', ...rest })
+ ).toHaveProperty('ports', 'Ranges must have 2 values');
+ expect(
+ validateForm({ protocol: 'TCP', ports: 'abc', ...rest })
+ ).toHaveProperty('ports', 'Must be 1-65535');
+ expect(
+ validateForm({ protocol: 'TCP', ports: '1--20', ...rest })
+ ).toHaveProperty('ports', 'Must be 1-65535');
expect(
validateForm({ protocol: 'TCP', ports: '-20', ...rest })
+ ).toHaveProperty('ports', 'Must be 1-65535');
+ expect(
+ validateForm({
+ protocol: 'TCP',
+ ports: '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16',
+ ...rest,
+ })
).toHaveProperty(
'ports',
- 'Ports must be an integer, range of integers, or a comma-separated list of integers.'
+ 'Number of ports or port range endpoints exceeded. Max allowed is 15'
);
});
it('validates label', () => {
From 55e61665ca4ee4fd628cd5a95264c0f7a4b3d496 Mon Sep 17 00:00:00 2001
From: Alban Bailly
Date: Wed, 28 Jun 2023 16:09:55 -0400
Subject: [PATCH 04/12] Added changeset: Firewall custom ports validation
---
packages/manager/.changeset/pr-9336-fixed-1687982995866.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 packages/manager/.changeset/pr-9336-fixed-1687982995866.md
diff --git a/packages/manager/.changeset/pr-9336-fixed-1687982995866.md b/packages/manager/.changeset/pr-9336-fixed-1687982995866.md
new file mode 100644
index 00000000000..af3816b78e1
--- /dev/null
+++ b/packages/manager/.changeset/pr-9336-fixed-1687982995866.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Fixed
+---
+
+Firewall custom ports validation ([#9336](https://github.com/linode/manager/pull/9336))
From c45465f69e2c454ca9826a2b50c5f28a51e710ad Mon Sep 17 00:00:00 2001
From: Alban Bailly
Date: Wed, 28 Jun 2023 16:10:41 -0400
Subject: [PATCH 05/12] Added changeset: Firewall custom port validation
---
.../validation/.changeset/pr-9336-fixed-1687983041491.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 packages/validation/.changeset/pr-9336-fixed-1687983041491.md
diff --git a/packages/validation/.changeset/pr-9336-fixed-1687983041491.md b/packages/validation/.changeset/pr-9336-fixed-1687983041491.md
new file mode 100644
index 00000000000..69266a068bb
--- /dev/null
+++ b/packages/validation/.changeset/pr-9336-fixed-1687983041491.md
@@ -0,0 +1,5 @@
+---
+"@linode/validation": Fixed
+---
+
+Firewall custom port validation ([#9336](https://github.com/linode/manager/pull/9336))
From fd75dc58051b7dd9fd1b2da0b8fa9d1e706b59cd Mon Sep 17 00:00:00 2001
From: Alban Bailly
Date: Wed, 28 Jun 2023 16:11:21 -0400
Subject: [PATCH 06/12] Fix: [M3-6800] cleanup
---
packages/validation/src/firewalls.schema.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/packages/validation/src/firewalls.schema.ts b/packages/validation/src/firewalls.schema.ts
index 38754ca85e1..9c73e59639a 100644
--- a/packages/validation/src/firewalls.schema.ts
+++ b/packages/validation/src/firewalls.schema.ts
@@ -5,8 +5,6 @@ import { array, mixed, number, object, string } from 'yup';
export const IP_ERROR_MESSAGE =
'Must be a valid IPv4 or IPv6 address or range.';
-// export const CUSTOM_PORTS_ERROR_MESSAGE =
-// 'Ports must be an integer, range of integers, or a comma-separated list of integers.';
export const CUSTOM_PORTS_VALIDATION_REGEX = /^(?:\d+|\d+-\d+|(?:\d+,\s*)*\d+)$/;
export const validateIP = (ipAddress?: string | null): boolean => {
From 559663aa42585ae3209edd7d2c4a06f6652cef7a Mon Sep 17 00:00:00 2001
From: Alban Bailly
Date: Wed, 28 Jun 2023 16:15:47 -0400
Subject: [PATCH 07/12] Fix: [M3-6800] moaaar cleanup
---
packages/validation/src/firewalls.schema.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/validation/src/firewalls.schema.ts b/packages/validation/src/firewalls.schema.ts
index 9c73e59639a..f5cc6718a8c 100644
--- a/packages/validation/src/firewalls.schema.ts
+++ b/packages/validation/src/firewalls.schema.ts
@@ -5,7 +5,6 @@ import { array, mixed, number, object, string } from 'yup';
export const IP_ERROR_MESSAGE =
'Must be a valid IPv4 or IPv6 address or range.';
-export const CUSTOM_PORTS_VALIDATION_REGEX = /^(?:\d+|\d+-\d+|(?:\d+,\s*)*\d+)$/;
export const validateIP = (ipAddress?: string | null): boolean => {
if (!ipAddress) {
From d1bed3fd4e38c7553bf53c41a3dda9aa8fe0313d Mon Sep 17 00:00:00 2001
From: Alban Bailly
Date: Wed, 28 Jun 2023 17:15:45 -0400
Subject: [PATCH 08/12] Fix: [M3-6800] better naming conventions and JSDoc
---
.../Rules/FirewallRuleDrawer.utils.ts | 4 ++--
packages/validation/src/firewalls.schema.ts | 16 +++++++++++++---
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.utils.ts b/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.utils.ts
index 5351b3fe68b..e19971e62a5 100644
--- a/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.utils.ts
+++ b/packages/manager/src/features/Firewalls/FirewallDetail/Rules/FirewallRuleDrawer.utils.ts
@@ -13,7 +13,7 @@ import {
} from 'src/features/Firewalls/shared';
import {
CUSTOM_PORTS_ERROR_MESSAGE,
- runCustomPortsValidation,
+ isCustomPortsValid,
} from '@linode/validation';
import type {
FirewallRuleProtocol,
@@ -332,7 +332,7 @@ export const validateForm = ({
if ((protocol === 'ICMP' || protocol === 'IPENCAP') && ports) {
errors.ports = `Ports are not allowed for ${protocol} protocols.`;
- } else if (ports && !runCustomPortsValidation(ports)) {
+ } else if (ports && !isCustomPortsValid(ports)) {
errors.ports = CUSTOM_PORTS_ERROR_MESSAGE;
}
diff --git a/packages/validation/src/firewalls.schema.ts b/packages/validation/src/firewalls.schema.ts
index f5cc6718a8c..df25c4d2a32 100644
--- a/packages/validation/src/firewalls.schema.ts
+++ b/packages/validation/src/firewalls.schema.ts
@@ -42,6 +42,11 @@ export const ipAddress = string().test({
export let CUSTOM_PORTS_ERROR_MESSAGE =
'Ports must be an integer, range of integers, or a comma-separated list of integers.';
+/**
+ * @param port
+ * @returns boolean
+ * @description Validates a single port or port range and sets the error message
+ */
const validatePort = (port: string): boolean => {
if (!port) {
CUSTOM_PORTS_ERROR_MESSAGE = 'Must be 1-65535';
@@ -62,8 +67,13 @@ const validatePort = (port: string): boolean => {
return true;
};
-export const runCustomPortsValidation = (value: string): boolean => {
- const portList = value?.split(',') || [];
+/**
+ * @param ports
+ * @returns boolean
+ * @description Validates a comma-separated list of ports and port ranges and sets the error message
+ */
+export const isCustomPortsValid = (ports: string): boolean => {
+ const portList = ports?.split(',') || [];
let portLimitCount = 0;
for (const port of portList) {
@@ -114,7 +124,7 @@ const validateFirewallPorts = string().test({
}
try {
- runCustomPortsValidation(value);
+ isCustomPortsValid(value);
} catch (err) {
return false;
}
From 17ae8a69abeee330e017933b68eb49d3625b078e Mon Sep 17 00:00:00 2001
From: Alban Bailly
Date: Thu, 29 Jun 2023 12:16:51 -0400
Subject: [PATCH 09/12] Fix: [M3-6800] Improved feedback
---
packages/validation/src/firewalls.schema.ts | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/packages/validation/src/firewalls.schema.ts b/packages/validation/src/firewalls.schema.ts
index df25c4d2a32..e1a2eeb6e4f 100644
--- a/packages/validation/src/firewalls.schema.ts
+++ b/packages/validation/src/firewalls.schema.ts
@@ -39,8 +39,7 @@ export const ipAddress = string().test({
test: validateIP,
});
-export let CUSTOM_PORTS_ERROR_MESSAGE =
- 'Ports must be an integer, range of integers, or a comma-separated list of integers.';
+export let CUSTOM_PORTS_ERROR_MESSAGE = '';
/**
* @param port
@@ -48,6 +47,9 @@ export let CUSTOM_PORTS_ERROR_MESSAGE =
* @description Validates a single port or port range and sets the error message
*/
const validatePort = (port: string): boolean => {
+ CUSTOM_PORTS_ERROR_MESSAGE =
+ 'Ports must be an integer, range of integers, or a comma-separated list of integers.';
+
if (!port) {
CUSTOM_PORTS_ERROR_MESSAGE = 'Must be 1-65535';
return false;
@@ -59,11 +61,15 @@ const validatePort = (port: string): boolean => {
return false;
}
- if (String(convertedPort) !== port) {
+ if (port.startsWith('0')) {
CUSTOM_PORTS_ERROR_MESSAGE = 'Port must not have leading zeroes';
return false;
}
+ if (String(convertedPort) !== port) {
+ return false;
+ }
+
return true;
};
From 1e16579ae70beb9f704220008299734553c32201 Mon Sep 17 00:00:00 2001
From: Alban Bailly
Date: Thu, 29 Jun 2023 15:15:38 -0400
Subject: [PATCH 10/12] remove unecessary changesets
---
packages/manager/.changeset/pr-9336-fixed-1687982995866.md | 5 -----
.../validation/.changeset/pr-9336-fixed-1687983041491.md | 5 -----
2 files changed, 10 deletions(-)
delete mode 100644 packages/manager/.changeset/pr-9336-fixed-1687982995866.md
delete mode 100644 packages/validation/.changeset/pr-9336-fixed-1687983041491.md
diff --git a/packages/manager/.changeset/pr-9336-fixed-1687982995866.md b/packages/manager/.changeset/pr-9336-fixed-1687982995866.md
deleted file mode 100644
index af3816b78e1..00000000000
--- a/packages/manager/.changeset/pr-9336-fixed-1687982995866.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@linode/manager": Fixed
----
-
-Firewall custom ports validation ([#9336](https://github.com/linode/manager/pull/9336))
diff --git a/packages/validation/.changeset/pr-9336-fixed-1687983041491.md b/packages/validation/.changeset/pr-9336-fixed-1687983041491.md
deleted file mode 100644
index 69266a068bb..00000000000
--- a/packages/validation/.changeset/pr-9336-fixed-1687983041491.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@linode/validation": Fixed
----
-
-Firewall custom port validation ([#9336](https://github.com/linode/manager/pull/9336))
From 622fb260cd5561597db365887729f34c863daabd Mon Sep 17 00:00:00 2001
From: Banks Nussman <115251059+bnussman-akamai@users.noreply.github.com>
Date: Wed, 28 Jun 2023 12:59:24 -0400
Subject: [PATCH 11/12] Cherry Picked 309337e - Linodes Clone Fix
---
packages/manager/CHANGELOG.md | 11 +-
packages/manager/package.json | 2 +-
packages/manager/src/App.tsx | 16 --
.../src/containers/withLinodes.container.ts | 121 ++++--------
.../src/features/Account/EnableManaged.tsx | 26 +--
.../src/features/Account/GlobalSettings.tsx | 41 ++--
.../src/features/Images/ImageSelect.test.tsx | 4 -
.../src/features/Images/ImagesDrawer.tsx | 9 +-
.../NodePoolsDisplay/NodeTable.tsx | 15 +-
.../Linodes/CloneLanding/CloneLanding.tsx | 134 ++++---------
.../features/Linodes/CloneLanding/Details.tsx | 8 +-
.../Linodes/LinodeSelect/LinodeSelect.tsx | 38 +---
.../features/Linodes/LinodeSelect/index.tsx | 2 -
.../Linodes/LinodesCreate/LinodeCreate.tsx | 2 +-
.../LinodesCreate/LinodeCreateContainer.tsx | 25 +--
.../features/Linodes/LinodesCreate/types.ts | 6 -
.../LinodesDetail/HostMaintenanceError.tsx | 4 +-
.../LinodeActivity/LinodeActivity.test.tsx | 18 --
.../LinodeActivity/LinodeActivity.tsx | 27 +--
.../LinodesDetail/LinodeActivity/index.ts | 2 -
.../LinodeBackup/BackupsPlaceholder.tsx | 2 +-
.../LinodeBackup/LinodeBackups.tsx | 2 +-
.../LinodeDetailErrorBoundary.tsx | 31 ---
.../LinodeNetworking/LinodeNetworking.tsx | 2 +-
.../LinodesDetail/LinodePermissionsError.tsx | 4 +-
.../LinodeRebuild/LinodeRebuildDialog.tsx | 4 +-
.../LinodeRescue/StandardRescueDialog.tsx | 2 +-
.../LinodeResize/LinodeResize.tsx | 4 +-
.../LinodeSettings/ImageAndPassword.test.tsx | 2 +-
.../LinodeSettings/ImageAndPassword.tsx | 33 +---
.../LinodeSettings/LinodeSettings.tsx | 2 +-
.../LinodeStorage/CreateDiskDrawer.tsx | 3 +-
.../LinodesDetail/LinodesDetail.container.tsx | 71 -------
.../Linodes/LinodesDetail/LinodesDetail.tsx | 72 +++----
.../LinodesDetailHeader/Notifications.tsx | 7 +-
.../features/Linodes/LinodesDetail/README.md | 159 ----------------
.../features/Linodes/LinodesDetail/index.tsx | 2 -
.../LinodesDetail/linodeDetailContext.tsx | 155 ---------------
.../manager/src/features/Linodes/index.tsx | 2 +-
.../NodeBalancers/ConfigNodeIPSelect.tsx | 2 +-
.../NotificationData/RenderProgressEvent.tsx | 13 +-
.../features/Search/SearchLanding.test.tsx | 4 -
.../src/features/Search/SearchLanding.tsx | 30 ++-
.../SupportTickets/SupportTicketDrawer.tsx | 179 ++++++------------
.../features/TopMenu/SearchBar/SearchBar.tsx | 41 ++--
.../Volumes/DestructiveVolumeDialog.tsx | 9 +-
.../Volumes/VolumeAttachmentDrawer.tsx | 2 +-
.../Volumes/VolumeCreate/CreateVolumeForm.tsx | 2 +-
packages/manager/src/hooks/useEntities.ts | 47 -----
.../manager/src/hooks/useExtendedLinode.ts | 57 ------
.../manager/src/hooks/useLinodeActions.ts | 43 -----
packages/manager/src/hooks/useLinodes.ts | 19 --
.../manager/src/hooks/useReduxLoad.test.ts | 25 ---
packages/manager/src/hooks/useReduxLoad.ts | 121 ------------
.../manager/src/queries/linodes/linodes.ts | 11 ++
.../src/store/linodes/linode.containers.ts | 33 ----
.../manager/src/utilities/testHelpersStore.ts | 3 -
packages/validation/CHANGELOG.md | 5 +
packages/validation/package.json | 2 +-
59 files changed, 304 insertions(+), 1414 deletions(-)
delete mode 100644 packages/manager/src/features/Linodes/LinodeSelect/index.tsx
delete mode 100644 packages/manager/src/features/Linodes/LinodesDetail/LinodeActivity/LinodeActivity.test.tsx
delete mode 100644 packages/manager/src/features/Linodes/LinodesDetail/LinodeActivity/index.ts
delete mode 100644 packages/manager/src/features/Linodes/LinodesDetail/LinodeDetailErrorBoundary.tsx
delete mode 100644 packages/manager/src/features/Linodes/LinodesDetail/LinodesDetail.container.tsx
delete mode 100644 packages/manager/src/features/Linodes/LinodesDetail/README.md
delete mode 100644 packages/manager/src/features/Linodes/LinodesDetail/index.tsx
delete mode 100644 packages/manager/src/features/Linodes/LinodesDetail/linodeDetailContext.tsx
delete mode 100644 packages/manager/src/hooks/useEntities.ts
delete mode 100644 packages/manager/src/hooks/useExtendedLinode.ts
delete mode 100644 packages/manager/src/hooks/useLinodeActions.ts
delete mode 100644 packages/manager/src/hooks/useLinodes.ts
delete mode 100644 packages/manager/src/hooks/useReduxLoad.test.ts
delete mode 100644 packages/manager/src/hooks/useReduxLoad.ts
delete mode 100644 packages/manager/src/store/linodes/linode.containers.ts
delete mode 100644 packages/manager/src/utilities/testHelpersStore.ts
diff --git a/packages/manager/CHANGELOG.md b/packages/manager/CHANGELOG.md
index 28a1647bd1b..ae479346b6f 100644
--- a/packages/manager/CHANGELOG.md
+++ b/packages/manager/CHANGELOG.md
@@ -4,8 +4,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
-## [2023-06-27] - v1.96.1
+## [2023-06-29] - v1.96.2
+
+### Fixed:
+- Issue where Cloud Manager was not displaying all linodes capable of being "cloned" ([#9294](https://github.com/linode/manager/pull/9294))
+- Firewall custom ports validation w/ unit tests ([#9336](https://github.com/linode/manager/pull/9336))
+### Tech Stories:
+
+- React Query - Linodes - General Refactors ([#9294](https://github.com/linode/manager/pull/9294))
+
+## [2023-06-27] - v1.96.1
### Fixed:
diff --git a/packages/manager/package.json b/packages/manager/package.json
index 81fd42b037a..ffe433c5228 100644
--- a/packages/manager/package.json
+++ b/packages/manager/package.json
@@ -2,7 +2,7 @@
"name": "linode-manager",
"author": "Linode",
"description": "The Linode Manager website",
- "version": "1.96.1",
+ "version": "1.96.2",
"private": true,
"bugs": {
"url": "https://github.com/Linode/manager/issues"
diff --git a/packages/manager/src/App.tsx b/packages/manager/src/App.tsx
index 61ce13db465..aeee3c078f4 100644
--- a/packages/manager/src/App.tsx
+++ b/packages/manager/src/App.tsx
@@ -20,7 +20,6 @@ import { ADOBE_ANALYTICS_URL, NUM_ADOBE_SCRIPTS } from './constants';
import { reportException } from './exceptionReporting';
import { useAuthentication } from './hooks/useAuthentication';
import useFeatureFlagsLoad from './hooks/useFeatureFlagLoad';
-import useLinodes from './hooks/useLinodes';
import { loadScript } from './hooks/useScript';
import { oauthClientsEventHandler } from './queries/accountOAuth';
import { databaseEventsHandler } from './queries/databases';
@@ -59,12 +58,6 @@ const BaseApp = withFeatureFlagProvider(
const { enqueueSnackbar } = useSnackbar();
- const {
- linodes: {
- error: { read: linodesError },
- },
- } = useLinodes();
-
const [goToOpen, setGoToOpen] = React.useState(false);
const theme = preferences?.theme;
@@ -263,15 +256,6 @@ const BaseApp = withFeatureFlagProvider(
};
}, [handleMigrationEvent]);
- /**
- * in the event that we encounter an "invalid OAuth token" error from the API,
- * we can simply refrain from rendering any content since the user will
- * imminently be redirected to the login page.
- */
- if (hasOauthError(linodesError)) {
- return null;
- }
-
return (
}>
{/** Accessibility helper */}
diff --git a/packages/manager/src/containers/withLinodes.container.ts b/packages/manager/src/containers/withLinodes.container.ts
index 7655fc204b8..cf3fc95186d 100644
--- a/packages/manager/src/containers/withLinodes.container.ts
+++ b/packages/manager/src/containers/withLinodes.container.ts
@@ -1,91 +1,40 @@
-import { Linode } from '@linode/api-v4/lib/linodes';
-import { APIError, Filter, Params } from '@linode/api-v4/lib/types';
-import { path } from 'ramda';
-import { connect, InferableComponentEnhancerWithProps } from 'react-redux';
-import { ApplicationState } from 'src/store';
-import { requestLinodes } from 'src/store/linodes/linode.requests';
-import { State } from 'src/store/linodes/linodes.reducer';
-import { LinodeWithMaintenanceAndDisplayStatus } from 'src/store/linodes/types';
-import { ThunkDispatch } from 'src/store/types';
-import { GetAllData } from 'src/utilities/getAll';
-
-export interface DispatchProps {
- getLinodes: (
- params?: Params,
- filters?: Filter
- ) => Promise>;
+import React from 'react';
+import { CreateLinodeRequest, Linode } from '@linode/api-v4/lib/linodes';
+import { APIError } from '@linode/api-v4/lib/types';
+import {
+ useAllLinodesQuery,
+ useCreateLinodeMutation,
+} from 'src/queries/linodes/linodes';
+
+interface Actions {
+ createLinode: (data: CreateLinodeRequest) => Promise;
}
-/* tslint:disable-next-line */
-export interface StateProps {
- linodesError?: APIError[];
- linodesLoading: State['loading'];
- linodesData: LinodeWithMaintenanceAndDisplayStatus[];
- linodesLastUpdated: State['lastUpdated'];
- linodesResults: State['results'];
+export interface WithLinodesProps {
+ linodesError: APIError[] | null;
+ linodesLoading: boolean;
+ linodesData: Linode[] | undefined;
+ linodeActions: Actions;
}
-type MapProps = (
- ownProps: OwnProps,
- linodes: Linode[],
- loading: boolean,
- error?: APIError[]
-) => ReduxStateProps & Partial;
-
-export type Props = DispatchProps & StateProps;
-
-interface Connected {
- (
- mapStateToProps: MapProps
- ): InferableComponentEnhancerWithProps<
- ReduxStateProps & Partial & DispatchProps & OwnProps,
- OwnProps
- >;
- (): InferableComponentEnhancerWithProps<
- ReduxStateProps & DispatchProps & OwnProps,
- OwnProps
- >;
-}
-
-const connected: Connected = (
- mapStateToProps?: MapProps
-) =>
- connect<
- (ReduxState & Partial) | StateProps,
- DispatchProps,
- OwnProps,
- ApplicationState
- >(
- (state, ownProps) => {
- const {
- loading,
- error,
- itemsById,
- lastUpdated,
- results,
- } = state.__resources.linodes;
- const linodes = Object.values(itemsById);
- if (mapStateToProps) {
- return mapStateToProps(
- ownProps,
- linodes,
- loading,
- path(['read'], error)
- );
- }
-
- return {
- linodesError: path(['read'], error),
- linodesLoading: loading,
- linodesData: linodes,
- linodesResults: results,
- linodesLastUpdated: lastUpdated,
- };
+export const withLinodes = (
+ Component: React.ComponentType
+) => (props: Props) => {
+ const {
+ data: linodesData,
+ isLoading: linodesLoading,
+ error: linodesError,
+ } = useAllLinodesQuery();
+
+ const { mutateAsync: createLinode } = useCreateLinodeMutation();
+
+ return React.createElement(Component, {
+ ...props,
+ linodesData,
+ linodesLoading,
+ linodesError,
+ linodeActions: {
+ createLinode,
},
- (dispatch: ThunkDispatch) => ({
- getLinodes: (params, filter) =>
- dispatch(requestLinodes({ params, filter })),
- })
- );
-
-export default connected;
+ });
+};
diff --git a/packages/manager/src/features/Account/EnableManaged.tsx b/packages/manager/src/features/Account/EnableManaged.tsx
index 84e2a859676..486c9682966 100644
--- a/packages/manager/src/features/Account/EnableManaged.tsx
+++ b/packages/manager/src/features/Account/EnableManaged.tsx
@@ -9,27 +9,20 @@ import Typography from 'src/components/core/Typography';
import ExternalLink from 'src/components/ExternalLink';
import Grid from '@mui/material/Unstable_Grid2';
import { SupportLink } from 'src/components/SupportLink';
-import withLinodes, {
- DispatchProps,
-} from 'src/containers/withLinodes.container';
import { pluralize } from 'src/utilities/pluralize';
import { updateAccountSettingsData } from 'src/queries/accountSettings';
import { useQueryClient } from 'react-query';
+import { useLinodesQuery } from 'src/queries/linodes/linodes';
interface Props {
isManaged: boolean;
}
-interface StateProps {
- linodeCount: number;
-}
-
-type CombinedProps = Props & StateProps & DispatchProps;
-
interface ContentProps {
isManaged: boolean;
openConfirmationModal: () => void;
}
+
export const ManagedContent = (props: ContentProps) => {
const { isManaged, openConfirmationModal } = props;
@@ -66,13 +59,16 @@ export const ManagedContent = (props: ContentProps) => {
);
};
-export const EnableManaged = (props: CombinedProps) => {
- const { isManaged, linodeCount } = props;
+export const EnableManaged = (props: Props) => {
+ const { isManaged } = props;
const queryClient = useQueryClient();
+ const { data: linodes } = useLinodesQuery();
const [isOpen, setOpen] = React.useState(false);
const [error, setError] = React.useState();
const [isLoading, setLoading] = React.useState(false);
+ const linodeCount = linodes?.results ?? 0;
+
const handleClose = () => {
setOpen(false);
setError(undefined);
@@ -94,7 +90,7 @@ export const EnableManaged = (props: CombinedProps) => {
.catch(handleError);
};
- const actions = () => (
+ const actions = (