From 941ff42656af6d9153e4eec7d964dbc28f78c74c Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Tue, 28 May 2024 15:24:24 -0400 Subject: [PATCH 01/10] add app sections --- .../Tabs/Marketplace/AppSection.tsx | 50 ++++++++++ .../Tabs/Marketplace/AppSelect.tsx | 96 ++++++++++++++----- .../features/OneClickApps/oneClickAppsv2.ts | 2 + .../src/features/OneClickApps/types.ts | 1 + packages/manager/src/queries/stackscripts.ts | 6 +- 5 files changed, 129 insertions(+), 26 deletions(-) create mode 100644 packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx new file mode 100644 index 00000000000..c66247094ea --- /dev/null +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx @@ -0,0 +1,50 @@ +import Grid from '@mui/material/Unstable_Grid2'; +import React from 'react'; + +import { Divider } from 'src/components/Divider'; +import { Stack } from 'src/components/Stack'; +import { Typography } from 'src/components/Typography'; +import { oneClickApps } from 'src/features/OneClickApps/oneClickAppsv2'; + +import { AppSelectionCard } from './AppSelectionCard'; + +import type { StackScript } from '@linode/api-v4'; + +interface Props { + onOpenDetailsDrawer: (stackscriptId: number) => void; + onSelect: (stackscript: StackScript) => void; + selectedStackscriptId: null | number | undefined; + stackscripts: StackScript[]; + title: string; +} + +export const AppSection = (props: Props) => { + const { + onOpenDetailsDrawer, + onSelect, + selectedStackscriptId, + stackscripts, + title, + } = props; + + return ( + + {title} + + + {stackscripts?.map((stackscript) => { + return ( + onOpenDetailsDrawer(stackscript.id)} + onSelect={() => onSelect(stackscript)} + /> + ); + })} + + + ); +}; diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSelect.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSelect.tsx index bb62cd608e3..e54c7ceec92 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSelect.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSelect.tsx @@ -1,4 +1,3 @@ -import Grid from '@mui/material/Unstable_Grid2'; import React from 'react'; import { useController, useFormContext } from 'react-hook-form'; @@ -14,10 +13,11 @@ import { oneClickApps } from 'src/features/OneClickApps/oneClickAppsv2'; import { useMarketplaceAppsQuery } from 'src/queries/stackscripts'; import { getDefaultUDFData } from '../StackScripts/UserDefinedFields/utilities'; -import { AppSelectionCard } from './AppSelectionCard'; +import { AppSection } from './AppSection'; import { categoryOptions } from './utilities'; import type { LinodeCreateFormValues } from '../../utilities'; +import type { StackScript } from '@linode/api-v4'; interface Props { /** @@ -37,6 +37,14 @@ export const AppSelect = (props: Props) => { true ); + const onSelect = (stackscript: StackScript) => { + setValue( + 'stackscript_data', + getDefaultUDFData(stackscript.user_defined_fields) + ); + field.onChange(stackscript.id); + }; + const renderContent = () => { if (isLoading) { return ( @@ -56,30 +64,68 @@ export const AppSelect = (props: Props) => { return ; } + // We will render this when we are filtering + // return ( + // + // {stackscripts?.map((stackscript) => { + // if (!oneClickApps[stackscript.id]) { + // return null; + // } + // return ( + // { + // setValue( + // 'stackscript_data', + // getDefaultUDFData(stackscript.user_defined_fields) + // ); + // field.onChange(stackscript.id); + // }} + // checked={field.value === stackscript.id} + // iconUrl={`/assets/${oneClickApps[stackscript.id].logo_url}`} + // key={stackscript.id} + // label={stackscript.label} + // onOpenDetailsDrawer={() => onOpenDetailsDrawer(stackscript.id)} + // /> + // ); + // })} + // + // ); + + const newApps = stackscripts.filter( + (stackscript) => oneClickApps[stackscript.id]?.isNew + ); + + const popularApps = stackscripts.slice(0, 10); + + // @ts-expect-error Can we use toSorted? 😣 + const allApps = stackscripts.toSorted((a, b) => + a.label.toLowerCase().localeCompare(b.label.toLowerCase()) + ); + return ( - - {stackscripts?.map((stackscript) => { - if (!oneClickApps[stackscript.id]) { - return null; - } - return ( - { - setValue( - 'stackscript_data', - getDefaultUDFData(stackscript.user_defined_fields) - ); - field.onChange(stackscript.id); - }} - checked={field.value === stackscript.id} - iconUrl={`/assets/${oneClickApps[stackscript.id].logo_url}`} - key={stackscript.id} - label={stackscript.label} - onOpenDetailsDrawer={() => onOpenDetailsDrawer(stackscript.id)} - /> - ); - })} - + + + + + ); }; diff --git a/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts b/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts index f8106bcd63e..d93730ee74f 100644 --- a/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts +++ b/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts @@ -2422,6 +2422,7 @@ export const oneClickApps: Record = { start: '1d76ba', }, description: `Secure, stable, and free alternative to popular video conferencing services. This app deploys four networked Jitsi nodes.`, + isNew: true, logo_url: 'jitsi.svg', name: 'Jitsi Cluster', related_guides: [ @@ -2436,6 +2437,7 @@ export const oneClickApps: Record = { }, 1350783: { alt_description: 'Open source, highly available, shared filesystem.', + isNew: true, alt_name: 'GlusterFS', categories: ['Development'], colors: { diff --git a/packages/manager/src/features/OneClickApps/types.ts b/packages/manager/src/features/OneClickApps/types.ts index 5e5bf88d501..d181d416468 100644 --- a/packages/manager/src/features/OneClickApps/types.ts +++ b/packages/manager/src/features/OneClickApps/types.ts @@ -5,6 +5,7 @@ export interface OCA { colors: Colors; description: string; href?: string; + isNew?: boolean; logo_url: string; name: string; related_guides?: Doc[]; diff --git a/packages/manager/src/queries/stackscripts.ts b/packages/manager/src/queries/stackscripts.ts index 5799751d14b..9dd389ff268 100644 --- a/packages/manager/src/queries/stackscripts.ts +++ b/packages/manager/src/queries/stackscripts.ts @@ -12,6 +12,7 @@ import { import { createQueryKeys } from '@lukemorales/query-key-factory'; import { useInfiniteQuery, useQuery } from '@tanstack/react-query'; +import { oneClickApps } from 'src/features/OneClickApps/oneClickAppsv2'; import { getOneClickApps } from 'src/features/StackScripts/stackScriptUtils'; import { EventHandlerData } from 'src/hooks/useEventHandlers'; import { getAll } from 'src/utilities/getAll'; @@ -30,7 +31,10 @@ const stackscriptQueries = createQueryKeys('stackscripts', { queryKey: [filter], }), marketplace: { - queryFn: () => getAllOCAsRequest(), + queryFn: async () => { + const stackscripts = await getAllOCAsRequest(); + return stackscripts.filter((s) => oneClickApps[s.id]); + }, queryKey: null, }, stackscript: (id: number) => ({ From 818c89f823385c081a37d7a14f7d0ed746d4f8df Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Wed, 29 May 2024 10:31:34 -0400 Subject: [PATCH 02/10] clean up and use `stort` insted of `toStorted` --- .../Tabs/Marketplace/AppSelect.tsx | 90 +++++++------------ .../Tabs/Marketplace/utilities.ts | 37 +++++++- 2 files changed, 67 insertions(+), 60 deletions(-) diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSelect.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSelect.tsx index e54c7ceec92..068ee84a5df 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSelect.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSelect.tsx @@ -1,3 +1,4 @@ +import Grid from '@mui/material/Unstable_Grid2'; import React from 'react'; import { useController, useFormContext } from 'react-hook-form'; @@ -14,7 +15,8 @@ import { useMarketplaceAppsQuery } from 'src/queries/stackscripts'; import { getDefaultUDFData } from '../StackScripts/UserDefinedFields/utilities'; import { AppSection } from './AppSection'; -import { categoryOptions } from './utilities'; +import { AppSelectionCard } from './AppSelectionCard'; +import { categoryOptions, getAppSections } from './utilities'; import type { LinodeCreateFormValues } from '../../utilities'; import type { StackScript } from '@linode/api-v4'; @@ -33,6 +35,8 @@ export const AppSelect = (props: Props) => { name: 'stackscript_id', }); + const filter = null; + const { data: stackscripts, error, isLoading } = useMarketplaceAppsQuery( true ); @@ -64,67 +68,37 @@ export const AppSelect = (props: Props) => { return ; } - // We will render this when we are filtering - // return ( - // - // {stackscripts?.map((stackscript) => { - // if (!oneClickApps[stackscript.id]) { - // return null; - // } - // return ( - // { - // setValue( - // 'stackscript_data', - // getDefaultUDFData(stackscript.user_defined_fields) - // ); - // field.onChange(stackscript.id); - // }} - // checked={field.value === stackscript.id} - // iconUrl={`/assets/${oneClickApps[stackscript.id].logo_url}`} - // key={stackscript.id} - // label={stackscript.label} - // onOpenDetailsDrawer={() => onOpenDetailsDrawer(stackscript.id)} - // /> - // ); - // })} - // - // ); - - const newApps = stackscripts.filter( - (stackscript) => oneClickApps[stackscript.id]?.isNew - ); - - const popularApps = stackscripts.slice(0, 10); + if (filter) { + return ( + + {stackscripts?.map((stackscript) => ( + onOpenDetailsDrawer(stackscript.id)} + onSelect={() => onSelect(stackscript)} + /> + ))} + + ); + } - // @ts-expect-error Can we use toSorted? 😣 - const allApps = stackscripts.toSorted((a, b) => - a.label.toLowerCase().localeCompare(b.label.toLowerCase()) - ); + const sections = getAppSections(stackscripts); return ( - - - + {sections.map(({ stackscripts, title }) => ( + + ))} ); }; diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/utilities.ts b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/utilities.ts index 2845ee7a3f4..8b47ffb4ee9 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/utilities.ts +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/utilities.ts @@ -1,10 +1,12 @@ -import { oneClickApps } from 'src/features/OneClickApps/oneClickApps'; +import { oneClickApps } from 'src/features/OneClickApps/oneClickAppsv2'; + +import type { StackScript } from '@linode/api-v4'; /** * Get all categories from our marketplace apps list so * we can generate a dynamic list of category options. */ -const categories = oneClickApps.reduce((acc, app) => { +const categories = Object.values(oneClickApps).reduce((acc, app) => { return [...acc, ...app.categories]; }, []); @@ -16,3 +18,34 @@ export const uniqueCategories = Array.from(new Set(categories)); export const categoryOptions = uniqueCategories.map((category) => ({ label: category, })); + +/** + * Returns an array of Marketplace app sections given an array + * of Marketplace app StackScripts + */ +export const getAppSections = (stackscripts: StackScript[]) => { + const newApps = stackscripts.filter( + (stackscript) => oneClickApps[stackscript.id]?.isNew + ); + + const popularApps = stackscripts.slice(0, 10); + + const allApps = [...stackscripts].sort((a, b) => + a.label.toLowerCase().localeCompare(b.label.toLowerCase()) + ); + + return [ + { + stackscripts: newApps, + title: 'All apps', + }, + { + stackscripts: popularApps, + title: 'Popular apps', + }, + { + stackscripts: allApps, + title: 'All apps', + }, + ]; +}; From 9456c8cc6434cb411577f79802a9aa492874d2b3 Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Wed, 29 May 2024 10:57:02 -0400 Subject: [PATCH 03/10] clean up and unit test --- .../Tabs/Marketplace/AppSection.test.tsx | 80 +++++++++++++++++++ .../Tabs/Marketplace/AppSection.tsx | 26 +++--- .../Tabs/Marketplace/utilities.ts | 5 +- .../src/features/OneClickApps/types.ts | 6 ++ 4 files changed, 102 insertions(+), 15 deletions(-) create mode 100644 packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.test.tsx diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.test.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.test.tsx new file mode 100644 index 00000000000..e65774076c6 --- /dev/null +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.test.tsx @@ -0,0 +1,80 @@ +import userEvent from '@testing-library/user-event'; +import React from 'react'; + +import { stackScriptFactory } from 'src/factories'; +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { AppSection } from './AppSection'; + +describe('AppSection', () => { + it('should render a title', () => { + const { getByText } = renderWithTheme( + + ); + + expect(getByText('Test title')).toBeVisible(); + }); + + it('should render apps', () => { + const app = stackScriptFactory.build({ + id: 0, + label: 'Linode Marketplace App', + }); + + const { getByText } = renderWithTheme( + + ); + + expect(getByText('Linode Marketplace App')).toBeVisible(); + }); + + it('should call `onOpenDetailsDrawer` when the details button is clicked for an app', async () => { + const app = stackScriptFactory.build({ id: 0 }); + const onOpenDetailsDrawer = vi.fn(); + + const { getByLabelText } = renderWithTheme( + + ); + + await userEvent.click(getByLabelText(`Info for "${app.label}"`)); + + expect(onOpenDetailsDrawer).toHaveBeenCalledWith(app.id); + }); + + it('should call `onSelect` when an app is clicked', async () => { + const app = stackScriptFactory.build({ id: 0 }); + const onSelect = vi.fn(); + + const { getByText } = renderWithTheme( + + ); + + await userEvent.click(getByText(app.label)); + + expect(onSelect).toHaveBeenCalledWith(app); + }); +}); diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx index c66247094ea..81f0dfed67c 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx @@ -28,22 +28,20 @@ export const AppSection = (props: Props) => { } = props; return ( - + {title} - + - {stackscripts?.map((stackscript) => { - return ( - onOpenDetailsDrawer(stackscript.id)} - onSelect={() => onSelect(stackscript)} - /> - ); - })} + {stackscripts?.map((stackscript) => ( + onOpenDetailsDrawer(stackscript.id)} + onSelect={() => onSelect(stackscript)} + /> + ))} ); diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/utilities.ts b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/utilities.ts index 8b47ffb4ee9..3fb682fee07 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/utilities.ts +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/utilities.ts @@ -24,12 +24,15 @@ export const categoryOptions = uniqueCategories.map((category) => ({ * of Marketplace app StackScripts */ export const getAppSections = (stackscripts: StackScript[]) => { + // To check if an app is 'new', we check our own 'oneClickApps' list for the 'isNew' value const newApps = stackscripts.filter( (stackscript) => oneClickApps[stackscript.id]?.isNew ); + // Items are ordered by popularity already, take the first 10 const popularApps = stackscripts.slice(0, 10); + // In the all apps section, show everything in alphabetical order const allApps = [...stackscripts].sort((a, b) => a.label.toLowerCase().localeCompare(b.label.toLowerCase()) ); @@ -37,7 +40,7 @@ export const getAppSections = (stackscripts: StackScript[]) => { return [ { stackscripts: newApps, - title: 'All apps', + title: 'New apps', }, { stackscripts: popularApps, diff --git a/packages/manager/src/features/OneClickApps/types.ts b/packages/manager/src/features/OneClickApps/types.ts index d181d416468..47110fcd0e5 100644 --- a/packages/manager/src/features/OneClickApps/types.ts +++ b/packages/manager/src/features/OneClickApps/types.ts @@ -5,6 +5,12 @@ export interface OCA { colors: Colors; description: string; href?: string; + /** + * Set isNew to `true` if you want the app to show up in the "New apps" + * section on the Linode Create flow. + * + * @note this value only affects Linode Create v2 + */ isNew?: boolean; logo_url: string; name: string; From 199a74ff2d70d8be760e1ee3df1cd41fef3e8c5a Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Wed, 29 May 2024 12:02:51 -0400 Subject: [PATCH 04/10] break up things into more components --- .../Tabs/Marketplace/AppSection.tsx | 4 +- .../Tabs/Marketplace/AppSelect.tsx | 88 +---------------- .../Tabs/Marketplace/AppsList.tsx | 98 +++++++++++++++++++ 3 files changed, 104 insertions(+), 86 deletions(-) create mode 100644 packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppsList.tsx diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx index 81f0dfed67c..29948e18034 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppSection.tsx @@ -28,9 +28,9 @@ export const AppSection = (props: Props) => { } = props; return ( - + {title} - + {stackscripts?.map((stackscript) => ( { const { onOpenDetailsDrawer } = props; - const { setValue } = useFormContext(); - const { field } = useController({ - name: 'stackscript_id', - }); - - const filter = null; - - const { data: stackscripts, error, isLoading } = useMarketplaceAppsQuery( - true - ); - - const onSelect = (stackscript: StackScript) => { - setValue( - 'stackscript_data', - getDefaultUDFData(stackscript.user_defined_fields) - ); - field.onChange(stackscript.id); - }; - - const renderContent = () => { - if (isLoading) { - return ( - - - - ); - } - if (error) { - return ; - } - - if (filter) { - return ( - - {stackscripts?.map((stackscript) => ( - onOpenDetailsDrawer(stackscript.id)} - onSelect={() => onSelect(stackscript)} - /> - ))} - - ); - } - - const sections = getAppSections(stackscripts); - - return ( - - {sections.map(({ stackscripts, title }) => ( - - ))} - - ); - }; + const { isLoading } = useMarketplaceAppsQuery(true); return ( @@ -131,7 +51,7 @@ export const AppSelect = (props: Props) => { /> - {renderContent()} + diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppsList.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppsList.tsx new file mode 100644 index 00000000000..59dfc3b7a07 --- /dev/null +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/AppsList.tsx @@ -0,0 +1,98 @@ +import Grid from '@mui/material/Unstable_Grid2'; +import React from 'react'; +import { useController, useFormContext } from 'react-hook-form'; + +import { Box } from 'src/components/Box'; +import { CircularProgress } from 'src/components/CircularProgress'; +import { ErrorState } from 'src/components/ErrorState/ErrorState'; +import { Stack } from 'src/components/Stack'; +import { oneClickApps } from 'src/features/OneClickApps/oneClickAppsv2'; +import { useMarketplaceAppsQuery } from 'src/queries/stackscripts'; + +import { getDefaultUDFData } from '../StackScripts/UserDefinedFields/utilities'; +import { AppSection } from './AppSection'; +import { AppSelectionCard } from './AppSelectionCard'; +import { getAppSections } from './utilities'; + +import type { LinodeCreateFormValues } from '../../utilities'; +import type { StackScript } from '@linode/api-v4'; + +interface Props { + /** + * Opens the Marketplace App details drawer for the given app + */ + onOpenDetailsDrawer: (stackscriptId: number) => void; +} + +export const AppsList = ({ onOpenDetailsDrawer }: Props) => { + const { data: stackscripts, error, isLoading } = useMarketplaceAppsQuery( + true + ); + + const filter = null; + + const { setValue } = useFormContext(); + const { field } = useController({ + name: 'stackscript_id', + }); + + const onSelect = (stackscript: StackScript) => { + setValue( + 'stackscript_data', + getDefaultUDFData(stackscript.user_defined_fields) + ); + field.onChange(stackscript.id); + }; + + if (isLoading) { + return ( + + + + ); + } + + if (error) { + return ; + } + + if (filter) { + return ( + + {stackscripts?.map((stackscript) => ( + onOpenDetailsDrawer(stackscript.id)} + onSelect={() => onSelect(stackscript)} + /> + ))} + + ); + } + + const sections = getAppSections(stackscripts); + + return ( + + {sections.map(({ stackscripts, title }) => ( + + ))} + + ); +}; From e036e7f3a1a03ef4e929c87aa020657880aa1a34 Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Thu, 30 May 2024 10:01:36 -0400 Subject: [PATCH 05/10] Added changeset: Linode Create Refactor - Marketplace App Sections --- .../.changeset/pr-10520-upcoming-features-1717077696131.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-10520-upcoming-features-1717077696131.md diff --git a/packages/manager/.changeset/pr-10520-upcoming-features-1717077696131.md b/packages/manager/.changeset/pr-10520-upcoming-features-1717077696131.md new file mode 100644 index 00000000000..1e549d4c12d --- /dev/null +++ b/packages/manager/.changeset/pr-10520-upcoming-features-1717077696131.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Linode Create Refactor - Marketplace App Sections ([#10520](https://github.com/linode/manager/pull/10520)) From f7880fd8b5794251d7655564525919a9a4807909 Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Fri, 31 May 2024 10:31:55 -0400 Subject: [PATCH 06/10] feedback @hana-linode --- .../Tabs/Marketplace/Marketplace.tsx | 2 +- .../UserDefinedFields.test.tsx | 50 + .../UserDefinedFields/UserDefinedFields.tsx | 62 +- .../src/features/OneClickApps/oneClickApps.ts | 2452 +---------------- 4 files changed, 109 insertions(+), 2457 deletions(-) diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/Marketplace.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/Marketplace.tsx index 492a79ca4ab..fbd93b5c363 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/Marketplace.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/Marketplace/Marketplace.tsx @@ -17,7 +17,7 @@ export const Marketplace = () => { return ( - + setDrawerStackScriptId(undefined)} diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.test.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.test.tsx index 35097a438ed..5c82e90e1cd 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.test.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.test.tsx @@ -5,6 +5,7 @@ import { HttpResponse, http, server } from 'src/mocks/testServer'; import { renderWithThemeAndHookFormContext } from 'src/utilities/testHelpers'; import { UserDefinedFields } from './UserDefinedFields'; +import { getDefaultUDFData } from './utilities'; import type { CreateLinodeRequest } from '@linode/api-v4'; @@ -58,4 +59,53 @@ describe('UserDefinedFields', () => { await findByLabelText(udf.label, { exact: false }); } }); + + it('should render a notice if this is a cluster', async () => { + const stackscript = stackScriptFactory.build({ + id: 0, + label: 'Marketplace App for Redis', + user_defined_fields: [ + { + default: '3', + label: 'Cluster Size', + name: 'cluster_size', + oneof: '3,5', + }, + ], + }); + + server.use( + http.get('*/linode/stackscripts/:id', () => { + return HttpResponse.json(stackscript); + }) + ); + + const { + findByText, + getByLabelText, + getByText, + } = renderWithThemeAndHookFormContext({ + component: , + useFormOptions: { + defaultValues: { + stackscript_data: getDefaultUDFData(stackscript.user_defined_fields), + stackscript_id: stackscript.id, + }, + }, + }); + + // Very the title renders + await findByText(`${stackscript.label} Setup`); + + // Verify the defuault cluster size is selected + expect(getByLabelText('3')).toBeChecked(); + + // Verify the cluster notice shows + expect(getByText('You are creating a cluster with 3 nodes.')).toBeVisible(); + + // Verify the details button renders + expect( + getByLabelText(`View details for ${stackscript.label}`) + ).toBeVisible(); + }); }); diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.tsx index bbb5c03c393..0e923d2b8d9 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.tsx @@ -1,24 +1,39 @@ import { CreateLinodeRequest } from '@linode/api-v4'; +import { decode } from 'he'; import React from 'react'; import { useFormContext, useWatch } from 'react-hook-form'; +import Info from 'src/assets/icons/info.svg'; import { Box } from 'src/components/Box'; +import { IconButton } from 'src/components/IconButton'; import { Notice } from 'src/components/Notice/Notice'; import { Paper } from 'src/components/Paper'; import { ShowMoreExpansion } from 'src/components/ShowMoreExpansion'; import { Stack } from 'src/components/Stack'; import { Typography } from 'src/components/Typography'; +import { oneClickApps } from 'src/features/OneClickApps/oneClickAppsv2'; import { useStackScriptQuery } from 'src/queries/stackscripts'; import { UserDefinedFieldInput } from './UserDefinedFieldInput'; import { separateUDFsByRequiredStatus } from './utilities'; -export const UserDefinedFields = () => { - const stackscriptId = useWatch({ - name: 'stackscript_id', - }); +interface Props { + /** + * Opens the Marketplace App details drawer for a given StackScript + * + * This is optional because we use this components for regular StackScripts too + * and they don't have details drawers + */ + onOpenDetailsDrawer?: (stackscriptId: number) => void; +} + +export const UserDefinedFields = ({ onOpenDetailsDrawer }: Props) => { + const { control, formState } = useFormContext(); - const { formState } = useFormContext(); + const [stackscriptId, stackscriptData] = useWatch({ + control, + name: ['stackscript_id', 'stackscript_data'], + }); const hasStackscriptSelected = stackscriptId !== null && stackscriptId !== undefined; @@ -34,6 +49,15 @@ export const UserDefinedFields = () => { userDefinedFields ); + const clusterSize = stackscriptData?.['cluster_size']; + + const isCluster = clusterSize !== null && clusterSize !== undefined; + + const marketplaceAppInfo = + stackscriptId !== null && stackscriptId !== undefined + ? oneClickApps[stackscriptId] + : undefined; + if (!stackscript || userDefinedFields?.length === 0) { return null; } @@ -41,13 +65,39 @@ export const UserDefinedFields = () => { return ( - {stackscript.label} Setup + {marketplaceAppInfo ? ( + + {`${stackscript.label} + + {decode(stackscript.label.replace('One-Click', ''))} Setup + + onOpenDetailsDrawer?.(stackscriptId!)} + size="large" + > + + + + ) : ( + {stackscript.label} Setup + )} {formState.errors.stackscript_data && ( )} + {isCluster && ( + + )} {requiredUDFs.map((field) => ( diff --git a/packages/manager/src/features/OneClickApps/oneClickApps.ts b/packages/manager/src/features/OneClickApps/oneClickApps.ts index 64f5906ca52..ff23648aa79 100644 --- a/packages/manager/src/features/OneClickApps/oneClickApps.ts +++ b/packages/manager/src/features/OneClickApps/oneClickApps.ts @@ -1,2456 +1,8 @@ -import { oneClickAppFactory } from 'src/factories/stackscripts'; +import { oneClickApps as newOneClickApps } from './oneClickAppsv2'; import type { OCA } from './types'; /** * @deprecated See oneClickAppsv2.ts */ -export const oneClickApps: OCA[] = [ - { - alt_description: 'Free open source control panel with a mobile app.', - alt_name: 'Free infrastructure control panel', - categories: ['Control Panels'], - colors: { - end: 'a3a3a3', - start: '20a53a', - }, - description: `Feature-rich alternative control panel for users who need critical control panel functionality but don’t need to pay for more niche premium features. aaPanel is open source and consistently maintained with weekly updates.`, - logo_url: 'aapanel.svg', - name: 'aaPanel', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/aapanel/', - title: 'Deploy aaPanel through the Linode Marketplace', - }, - ], - summary: - 'Popular open source free control panel with robust features and a mobile app.', - website: 'https://www.aapanel.com/reference.html', - }, - { - alt_description: - 'Free accounting software. QuickBooks alternative for freelancers and small businesses.', - alt_name: 'Open source accounting software', - categories: ['Productivity'], - colors: { - end: '55588b', - start: '6ea152', - }, - description: `Akaunting is a universal accounting software that helps small businesses run more efficiently. Track expenses, generate reports, manage your books, and get the other essential features to run your business from a single dashboard.`, - logo_url: 'akaunting.svg', - name: 'Akaunting', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/akaunting/', - title: 'Deploy Akaunting through the Linode Marketplace', - }, - ], - summary: - 'Free and open source accounting software you can use in your browser.', - website: 'https://akaunting.com', - }, - { - alt_description: - 'Free high-performance media streaming, including livestreaming.', - alt_name: 'Free media streaming app', - categories: ['Media and Entertainment'], - colors: { - end: '0a0a0a', - start: 'df0718', - }, - description: `Self-hosted free version to optimize and record video streaming for webinars, gaming, and more.`, - logo_url: 'antmediaserver.svg', - name: 'Ant Media Server: Community Edition', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/antmediaserver/', - title: 'Deploy Ant Media Server through the Linode Marketplace', - }, - ], - summary: 'A reliable, flexible and scalable video streaming solution.', - website: 'https://antmedia.io/', - }, - { - alt_description: - 'Low latency live streaming including WebRTC streaming, CMAF, and HLS.', - alt_name: 'Media streaming app', - categories: ['Media and Entertainment'], - colors: { - end: '0a0a0a', - start: 'df0718', - }, - description: `Ant Media Server makes it easy to set up a video streaming platform with ultra low latency. The Enterprise edition supports WebRTC Live Streaming in addition to CMAF and HLS streaming. Set up live restreaming to social media platforms to reach more viewers.`, - logo_url: 'antmediaserver.svg', - name: 'Ant Media Server: Enterprise Edition', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/antmediaenterpriseserver/', - title: - 'Deploy Ant Media Enterprise Edition through the Linode Marketplace', - }, - ], - summary: 'Highly scalable and feature-rich live video streaming platform.', - website: 'https://antmedia.io/', - }, - { - alt_description: - 'Open-source workflow management platform for data engineering pipelines.', - alt_name: 'Workflow management platform', - categories: ['Development'], - colors: { - end: 'E43921', - start: '00C7D4', - }, - description: `Programmatically author, schedule, and monitor workflows with a Python-based tool. Airflow provides full insight into the status and logs of your tasks, all in a modern web application.`, - logo_url: 'apacheairflow.svg', - name: 'Apache Airflow', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/apache-airflow/', - title: 'Deploy Apache Airflow through the Linode Marketplace', - }, - ], - summary: - 'Open source workflow management platform for data engineering pipelines.', - website: 'https://airflow.apache.org/', - }, - { - alt_description: - 'A self-hosted backend-as-a-service platform that provides developers with all the core APIs required to build any application.', - alt_name: 'Self-hosted backend-as-a-service', - categories: ['Development'], - colors: { - end: 'f02e65', - start: 'f02e65', - }, - description: `A self-hosted Firebase alternative for web, mobile & Flutter developers.`, - logo_url: 'appwrite.svg', - name: 'Appwrite', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/appwrite/', - title: 'Deploy Appwrite through the Linode Marketplace', - }, - ], - summary: - 'Appwrite is an open-source, cross-platform and technology-agnostic alternative to Firebase, providing all the core APIs necessary for web, mobile and Flutter development.', - website: 'https://appwrite.io/', - }, - { - alt_description: 'Free internet radio station management and hosting.', - alt_name: 'Online radio station builder', - categories: ['Media and Entertainment'], - colors: { - end: '0b1b64', - start: '1f8df5', - }, - description: `All aspects of running a radio station in one web interface so you can start your own station. Manage media, create playlists, and interact with listeners on one free platform.`, - logo_url: 'azuracast.svg', - name: 'Azuracast', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/azuracast/', - title: 'Deploy AzuraCast through the Linode Marketplace', - }, - ], - summary: 'Open source, self-hosted web radio tool.', - website: 'https://www.azuracast.com/', - }, - { - alt_description: 'Free penetration testing tool using client-side vectors.', - alt_name: 'Penetration testing tool for security research', - categories: ['Security'], - colors: { - end: '000f21', - start: '4a80a9', - }, - description: `Test the security posture of a client or application using client-side vectors, all powered by a simple API. This project is developed solely for lawful research and penetration testing.`, - logo_url: 'beef.svg', - name: 'BeEF', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/beef/', - title: 'Deploy BeEF through the Linode Marketplace', - }, - ], - summary: - 'Browser Exploitation Framework (BeEF) is an open source web browser penetration tool.', - website: 'https://github.com/beefproject/beef', - }, - { - alt_description: - 'Application builder for forms, portals, admin panels, and more.', - alt_name: 'Low-code application builder', - categories: ['Development'], - colors: { - end: '000000', - start: '9981f5', - }, - description: - 'Budibase is a modern, open source low-code platform for building modern business applications in minutes. Build, design and automate business apps, such as: admin panels, forms, internal tools, client portals and more. Before Budibase, it could take developers weeks to build simple CRUD apps; with Budibase, building CRUD apps takes minutes. When self-hosting please follow best practices for securing, updating and backing up your server.', - logo_url: 'budibase.svg', - name: 'Budibase', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/budibase/', - title: 'Deploy Budibase through the Linode Marketplace', - }, - ], - summary: 'Low-code platform for building modern business applications.', - website: 'https://docs.budibase.com/docs', - }, - { - alt_description: - 'Image hosting and sharing alternative to Google Photos and Flickr.', - alt_name: 'Photo library and image library', - categories: ['Media and Entertainment'], - colors: { - end: '8e44ad', - start: '23a8e0', - }, - description: `Chevereto is a full-featured image sharing solution that acts as an alternative to services like Google Photos or Flickr. Optimize image hosting by using external cloud storage (like Linode’s S3-compatible Object Storage) and connect to Chevereto using API keys.`, - logo_url: 'chevereto.svg', - name: 'Chevereto', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/chevereto/', - title: 'Deploy Chevereto through the Linode Marketplace', - }, - ], - summary: - 'Self-host your own open source image library to easily upload, collaborate, and share images on your terms.', - website: 'https://v3-docs.chevereto.com/', - }, - { - alt_description: - 'Host multiple apps on one server and control panel, including WordPress, GitLab, and Nextcloud.', - alt_name: 'Cloud app and website control panel', - categories: ['Website'], - colors: { - end: '212121', - start: '03a9f4', - }, - description: `Turnkey solution for running apps like WordPress, Rocket.Chat, NextCloud, GitLab, and OpenVPN.`, - logo_url: 'cloudron.svg', - name: 'Cloudron', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/cloudron/', - title: 'Deploy Cloudron through the Linode Marketplace', - }, - ], - summary: - 'End-to-end deployment and automatic updates for a range of essential applications.', - website: 'https://docs.cloudron.io', - }, - { - alt_description: - 'SQL and NoSQL database interface and monitoring for MySQL, PostgreSQL, and more.', - alt_name: 'Database monitoring', - categories: ['Databases'], - colors: { - end: '3f434c', - start: '0589de', - }, - description: `All-in-one interface for scripting and monitoring databases, including MySQL, MariaDB, Percona, PostgreSQL, Galera Cluster and more. Easily deploy database instances, manage with an included CLI, and automate performance monitoring.`, - logo_url: 'clustercontrol.svg', - name: 'ClusterControl', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/clustercontrol/', - title: 'Deploy ClusterControl through the Linode Marketplace', - }, - ], - summary: - 'All-in-one database deployment, management, and monitoring system.', - website: 'https://docs.severalnines.com/docs/clustercontrol/', - }, - { - alt_description: - 'Linux-based web hosting control panel for managing websites, servers, databases, and more.', - alt_name: 'Web server automation and control panel', - categories: ['Control Panels'], - colors: { - end: '141d25', - start: 'ff6c2c', - }, - description: `The cPanel & WHM® Marketplace App streamlines publishing and managing a website on your Linode. cPanel & WHM is a Linux® based web hosting control panel and platform that helps you create and manage websites, servers, databases and more with a suite of hosting automation and optimization tools.`, - logo_url: 'cpanel.svg', - name: 'cPanel', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/cpanel/', - title: 'Deploy cPanel through the Linode Marketplace', - }, - ], - summary: - 'The leading hosting automation platform that has simplified site and server management for 20 years.', - website: 'https://www.cpanel.net/', - }, - { - alt_description: - 'Web hosting control panel for managing websites, including WordPress.', - alt_name: 'Web hosting control panel', - categories: ['Control Panels'], - colors: { - end: '33cccc', - start: '3d596d', - }, - description: `Reduce setup time required to host websites and applications, including popular tools like OpenLiteSpeed WordPress.`, - logo_url: 'cyberpanel.svg', - name: 'CyberPanel', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/cyberpanel/', - title: 'Deploy CyberPanel through the Linode Marketplace', - }, - ], - summary: 'Next-generation hosting control panel by OpenLiteSpeed.', - website: 'https://docs.litespeedtech.com/cloud/images/cyberpanel/', - }, - { - alt_description: 'Open source community forum alternative to Reddit.', - alt_name: 'Chat forum', - categories: ['Media and Entertainment'], - colors: { - end: 'eae692', - start: '13b3ed', - }, - description: `Launch a sleek forum with robust integrations to popular tools like Slack and WordPress to start more conversations.`, - logo_url: 'discourse.svg', - name: 'Discourse', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/discourse/', - title: 'Deploy Discourse through the Linode Marketplace', - }, - ], - summary: - 'Open source community and discussion forum for customers, teams, fans, and more.', - website: 'https://www.discourse.org/', - }, - { - alt_description: 'Fast Python development with best practices.', - alt_name: 'Python framework', - categories: ['Development'], - colors: { - end: '136149', - start: '0a2e1f', - }, - description: `Django is a web development framework for the Python programming language. It enables rapid development, while favoring pragmatic and clean design.`, - logo_url: 'django.svg', - name: 'Django', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/django/', - title: 'Deploy Django through the Linode Marketplace', - }, - ], - summary: `A framework for simplifying the process of building your web applications more quickly and with less code.`, - website: 'https://www.djangoproject.com/', - }, - { - alt_description: - 'Popular container tool to build cloud-native applications.', - alt_name: 'Container builder', - categories: ['Development'], - colors: { - end: '1e65c9', - start: '2496ed', - }, - description: `Docker is a tool that enables you to create, deploy, and manage lightweight, stand-alone packages that contain everything needed to run an application (code, libraries, runtime, system settings, and dependencies).`, - logo_url: 'docker.svg', - name: 'Docker', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/docker/', - title: 'Deploy Docker through the Linode Marketplace', - }, - ], - summary: `Securely build, share and run modern applications anywhere.`, - website: 'https://www.docker.com/', - }, - { - alt_description: 'Secure website CMS.', - alt_name: 'CMS: content management system', - categories: ['Website'], - colors: { - end: '1b64a5', - start: '0678be', - }, - description: `Drupal is a content management system (CMS) designed for building custom websites for personal and business use. Built for high performance and scalability, Drupal provides the necessary tools to create rich, interactive community websites with forums, user blogs, and private messaging. Drupal also has support for personal publishing projects and can power podcasts, blogs, and knowledge-based systems, all within a single, unified platform.`, - logo_url: 'drupal.svg', - name: 'Drupal', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/drupal/', - title: 'Deploy Drupal through the Linode Marketplace', - }, - ], - summary: `Powerful content management system built on PHP and supported by a database engine.`, - website: 'https://www.drupal.org/', - }, - { - alt_description: - 'Flexible control panel to simplify SSL certificates and push code from GitHub.', - alt_name: 'Server control panel', - categories: ['Control Panels'], - colors: { - end: '000000', - start: '059669', - }, - description: `Deploy Node.js, Ruby, Python, PHP, Go, and Java applications via an intuitive control panel. Easily set up free SSL certificates, run commands with an in-browser terminal, and push your code from Github to accelerate development.`, - logo_url: 'easypanel.svg', - name: 'Easypanel', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/easypanel/', - title: 'Deploy Easypanel through the Linode Marketplace', - }, - ], - summary: 'Modern server control panel based on Docker.', - website: 'https://easypanel.io/', - }, - { - alt_description: 'File storage alternative to Dropbox and Google Drive.', - alt_name: 'File sharing', - categories: ['Productivity'], - colors: { - end: '0168ad', - start: '3e8cc1', - }, - description: `File synchronization across multiple users’ computers and other devices to keep everyone working without interruption.`, - logo_url: 'filecloud.svg', - name: 'FileCloud', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/filecloud/', - title: 'Deploy FileCloud through the Linode Marketplace', - }, - ], - summary: 'Enterprise file sharing to manage and sync from any device.', - website: 'https://www.getfilecloud.com', - }, - { - alt_description: 'Fast Python development with best practices.', - alt_name: 'Python framework', - categories: ['Development'], - colors: { - end: '1e2122', - start: '363b3d', - }, - description: `Flask is a lightweight WSGI web application framework written in Python. It is designed to make getting started quick and easy, with the ability to scale up to complex applications.`, - logo_url: 'flask.svg', - name: 'Flask', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/flask/', - title: 'Deploy Flask through the Linode Marketplace', - }, - ], - summary: `A quick light-weight web framework for Python that includes several utilities and libraries you can use to create a web application.`, - website: 'https://www.palletsprojects.com/p/flask/', - }, - { - alt_description: 'Free alternative to Trello and Asana.', - alt_name: 'Kanban board project management tool', - categories: ['Productivity'], - colors: { - end: '1d52ad', - start: '2997f8', - }, - description: `Create boards, assign tasks, and keep projects moving with a free and robust alternative to tools like Trello and Asana.`, - logo_url: 'focalboard.svg', - name: 'Focalboard', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/focalboard/', - title: 'Deploy Focalboard through the Linode Marketplace', - }, - ], - summary: 'Free open source project management tool.', - website: 'https://www.focalboard.com/', - }, - { - alt_description: 'SQL database.', - alt_name: 'SQL database', - categories: ['Databases'], - colors: { - end: '000000', - start: 'EC7704', - }, - description: `Galera provides a performant multi-master/active-active database solution with synchronous replication, to achieve high availability.`, - logo_url: 'galeramarketplaceocc.svg', - name: 'Galera Cluster', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/galera-cluster/', - title: 'Deploy Galera Cluster through the Linode Marketplace', - }, - ], - summary: `Multi-master MariaDB database cluster.`, - website: 'https://galeracluster.com/', - }, - { - alt_description: 'Open source, self-hosted Git management tool.', - alt_name: 'Git repository hosting', - categories: ['Development'], - colors: { - end: '34495e', - start: '609926', - }, - description: `Self-hosted Git service built and maintained by a large developer community.`, - logo_url: 'gitea.svg', - name: 'Gitea', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/gitea/', - title: 'Deploy Gitea through the Linode Marketplace', - }, - ], - summary: 'Git with a cup of tea - A painless self-hosted Git service.', - website: 'https://gitea.io/', - }, - { - alt_description: 'Popular Git management tool.', - alt_name: 'Git repository hosting', - categories: ['Development'], - colors: { - end: '21153e', - start: '48357d', - }, - description: `GitLab is a complete solution for all aspects of your software development. At its core, GitLab serves as your centralized Git repository. GitLab also features built-in tools that represent every task in your development workflow, from planning to testing to releasing. - Self-hosting your software development with GitLab offers total control of your codebase. At the same time, its familiar interface will ease collaboration for you and your team. GitLab is the most popular self-hosted Git repository, so you'll benefit from a robust set of integrated tools and an active community.`, - logo_url: 'gitlab.svg', - name: 'GitLab', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/gitlab/', - title: 'Deploy GitLab through the Linode Marketplace', - }, - ], - summary: - 'More than a self-hosted Git repository: use GitLab to manage all the stages of your DevOps life cycle.', - website: 'https://about.gitlab.com/', - }, - { - alt_description: - 'No-code platform for Kubernetes developers and operators.', - alt_name: 'Go Paddle', - categories: ['Development'], - colors: { - end: '252930', - start: '3a5bfd', - }, - description: `Provision multicloud clusters, containerize applications, and build DevOps pipelines. Gopaddle’s suite of templates and integrations helps eliminate manual errors and automate Kubernetes application releases.`, - logo_url: 'gopaddle.svg', - name: 'Gopaddle', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/gopaddle/', - title: 'Deploy Gopaddle through the Linode Marketplace', - }, - ], - summary: - 'Simple low-code platform for Kubernetes developers and operators.', - website: 'https://gopaddle.io/', - }, - { - alt_description: 'Open source, highly available, shared filesystem.', - alt_name: 'GlusterFS', - categories: ['Development'], - colors: { - end: '784900', - start: 'D4AC5C', - }, - description: - 'GlusterFS is an open source, software scalable network filesystem. This app deploys three GlusterFS servers and three GlusterFS clients.', - logo_url: 'glusterfs.svg', - name: 'GlusterFS Cluster', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/glusterfs-cluster/', - title: 'Deploy GlusterFS Cluster through the Linode Marketplace', - }, - ], - summary: 'Open source network filesystem.', - website: 'https://www.gluster.org/', - }, - { - alt_description: 'Markdown-based website CMS.', - alt_name: 'CMS: content management system', - categories: ['Website'], - colors: { - end: 'b987cf', - start: '1a0629', - }, - description: `Build websites on a CMS that prioritizes speed and simplicity over customization and integration support. Create your content in Markdown and take advantage of powerful taxonomy to customize relationships between pages and other content.`, - logo_url: 'grav.svg', - name: 'Grav', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/grav/', - title: 'Deploy Grav through the Linode Marketplace', - }, - ], - summary: 'Modern and open source flat-file content management system.', - website: 'https://getgrav.org/', - }, - { - alt_description: 'Desktop cloud hosting.', - alt_name: 'Virtual desktop', - categories: ['Development'], - colors: { - end: '213121', - start: '304730', - }, - description: `Access your desktop from any device with a browser to keep your desktop hosted in the cloud.`, - logo_url: 'guacamole.svg', - name: 'Guacamole', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/guacamole/', - title: 'Deploy Apache Guacamole through the Linode Marketplace', - }, - ], - summary: 'Free open source clientless remote desktop gateway.', - website: 'https://guacamole.apache.org/', - }, - { - alt_description: 'Web Application Firewall.', - alt_name: 'Community WAF', - categories: ['Security'], - colors: { - end: '00C1A9', - start: '22324F', - }, - description: `Harden your web applications and APIs against OWASP Top 10 attacks. Haltdos makes it easy to manage WAF settings and review logs in an intuitive web-based GUI.`, - logo_url: 'haltdos.svg', - name: 'HaltDOS Community WAF', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/haltdos-community-waf/', - title: 'Deploy Haltdos Community WAF through the Linode Marketplace', - }, - ], - summary: 'User-friendly web application firewall.', - website: 'https://www.haltdos.com/', - }, - { - alt_description: 'Container registry for Kubernetes.', - alt_name: 'Container registry for Kubernetes.', - categories: ['Development'], - colors: { - end: '4495d7', - start: '60b932', - }, - description: `Open source registry for images and containers. Linode recommends using Harbor with Linode Kubernetes Engine (LKE).`, - logo_url: 'harbor.svg', - name: 'Harbor', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/harbor/', - title: 'Deploy Harbor through the Linode Marketplace', - }, - ], - summary: 'Cloud native container registry for Kubernetes and more.', - website: 'https://goharbor.io/docs', - }, - { - alt_description: - 'HashiCorp containerization tool to use instead of or with Kubernetes', - alt_name: 'Container scheduler and orchestrator', - categories: ['Development'], - colors: { - end: '545556', - start: '60dea9', - }, - description: - 'A simple and flexible scheduler and orchestrator to deploy and manage containers and non-containerized applications across on-prem and clouds at scale.', - logo_url: 'nomad.svg', - name: 'HashiCorp Nomad Cluster', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/hashicorp-nomad-cluster', - title: 'Deploy HashiCorp Nomad Cluster through the Linode Marketplace', - }, - ], - summary: 'Flexible scheduling and orchestration for diverse workloads.', - website: 'https://www.nomadproject.io/docs', - }, - { - alt_description: - 'HashiCorp Nomad clients for horizontally scaling a Nomad One-Click Cluster', - alt_name: 'Container scheduler and orchestrator', - categories: ['Development'], - colors: { - end: '545556', - start: '60dea9', - }, - description: - 'A simple deployment of multiple clients to horizontally scale an existing Nomad One-Click Cluster.', - logo_url: 'nomad.svg', - name: 'HashiCorp Nomad Clients Cluster', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/hashicorp-nomad-clients-cluster', - title: - 'Deploy HashiCorp Nomad Clients Cluster through the Linode Marketplace', - }, - ], - summary: 'Flexible scheduling and orchestration for diverse workloads.', - website: 'https://www.nomadproject.io/docs', - }, - { - alt_description: - 'HashiCorp containerization tool to use instead of or with Kubernetes', - alt_name: 'Container scheduler and orchestrator', - categories: ['Development'], - colors: { - end: '545556', - start: '60dea9', - }, - description: - 'A simple and flexible scheduler and orchestrator to deploy and manage containers and non-containerized applications across on-prem and clouds at scale.', - logo_url: 'nomad.svg', - name: 'HashiCorp Nomad', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/hashicorp-nomad', - title: 'Deploy HashiCorp Nomad through the Linode Marketplace', - }, - ], - summary: 'Flexible scheduling and orchestration for diverse workloads.', - website: 'https://www.nomadproject.io/docs', - }, - { - alt_description: 'HashiCorp password and secrets management storage.', - alt_name: 'Security secrets management', - categories: ['Security'], - colors: { - end: '545556', - start: 'ffd712', - }, - description: - 'HashiCorp Vault is an open source, centralized secrets management system. It provides a secure and reliable way of storing and distributing secrets like API keys, access tokens, and passwords.', - logo_url: 'vault.svg', - name: 'HashiCorp Vault', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/hashicorp-vault', - title: 'Deploy HashiCorp Vault through the Linode Marketplace', - }, - ], - summary: 'An open source, centralized secrets management system.', - website: 'https://www.vaultproject.io/docs', - }, - { - alt_description: - 'Retool open-source alternative, with low-code UI components.', - alt_name: 'Low-code development platform', - categories: ['Security'], - colors: { - end: 'FF58BE', - start: '654AEC', - }, - description: - 'Illa Builder is a Retool open-source alternative, with low-code UI components for self-hosting the development of internal tools.', - logo_url: 'illabuilder.svg', - name: 'Illa Builder', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/illa-builder', - title: 'Deploy Illa Builder through the Linode Marketplace', - }, - ], - summary: 'An open-source, low-code development platform.', - website: 'https://github.com/illacloud/illa-builder', - }, - { - alt_description: 'CI/CD tool to delegate automation tasks and jobs.', - alt_name: 'Free automation tool', - categories: ['Development'], - colors: { - end: 'd24939', - start: 'd33833', - }, - description: `Jenkins is an open source automation tool which can build, test, and deploy your infrastructure.`, - logo_url: 'jenkins.svg', - name: 'Jenkins', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/jenkins/', - title: 'Deploy Jenkins through the Linode Marketplace', - }, - ], - summary: `A tool that gives you access to a massive library of plugins to support automation in your project's lifecycle.`, - website: 'https://jenkins.io/', - }, - { - alt_description: 'Enterprise-ready backups tool.', - alt_name: 'Server backups management and control panel', - categories: ['Control Panels'], - colors: { - end: '1f2c38', - start: 'ff6c2c', - }, - description: `Powerful and customizable backups for several websites and data all in the same interface. JetBackup integrates with any control panel via API, and has native support for cPanel and DirectAdmin. Easily backup your data to storage you already use, including Linode’s S3-compatible Object Storage.`, - logo_url: 'jetbackup.svg', - name: 'JetBackup', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/jetbackup/', - title: 'Deploy JetBackup through the Linode Marketplace', - }, - ], - summary: - 'Advanced customizable backups to integrate with your preferred control panel.', - website: 'https://docs.jetapps.com/', - }, - { - alt_description: 'Open source video conferencing alternative to Zoom.', - alt_name: 'Video chat and video conferencing', - categories: ['Media and Entertainment'], - colors: { - end: '949699', - start: '1d76ba', - }, - description: `Secure, stable, and free alternative to popular video conferencing services. Use built-in features to limit meeting access with passwords or stream on YouTube so anyone can attend.`, - logo_url: 'jitsi.svg', - name: 'Jitsi', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/jitsi/', - title: 'Deploy Jitsi through the Linode Marketplace', - }, - ], - summary: 'Free, open source video conferencing and communication platform.', - website: 'https://jitsi.org/', - }, - { - alt_description: - 'Open source video conferencing cluster, alternative to Zoom.', - alt_name: 'Video chat and video conferencing cluster', - categories: ['Media and Entertainment'], - colors: { - end: '949699', - start: '1d76ba', - }, - description: `Secure, stable, and free alternative to popular video conferencing services. This app deploys four networked Jitsi nodes.`, - logo_url: 'jitsi.svg', - name: 'Jitsi Cluster', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/jitsi-cluster/', - title: 'Deploy Jitsi Cluster through the Linode Marketplace', - }, - ], - summary: 'Free, open source video conferencing and communication platform.', - website: 'https://jitsi.org/', - }, - { - alt_description: 'Secure website CMS.', - alt_name: 'CMS: content management system', - categories: ['Website'], - colors: { - end: '5090cd', - start: 'f2a13e', - }, - description: `Free open source CMS optimized for building custom functionality and design.`, - logo_url: 'joomla.svg', - name: 'Joomla', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/joomla/', - title: 'Deploy Joomla through the Linode Marketplace', - }, - ], - summary: 'Flexible and security-focused content management system.', - website: 'https://www.joomla.org/', - }, - { - alt_description: - 'Digital note-taking application alternative to Evernote and OneNote.', - alt_name: 'Multimedia note-taking and digital notebook', - categories: ['Website'], - colors: { - end: '509df9', - start: '043872', - }, - description: `Capture your thoughts and securely access them from any device with a highly customizable note-taking software.`, - logo_url: 'joplin.svg', - name: 'Joplin', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/joplin/', - title: 'Deploy Joplin through the Linode Marketplace', - }, - ], - summary: 'Open source multimedia note-taking app.', - website: 'https://joplinapp.org/', - }, - { - alt_description: 'Data science notebook.', - alt_name: 'Data science and machine learning development environment.', - categories: ['Productivity'], - colors: { - end: '9e9e9e', - start: 'f37626', - }, - description: - 'JupyterLab is a cutting-edge web-based, interactive development environment, geared towards data science, machine learning and other scientific computing workflows.', - logo_url: 'jupyter.svg', - name: 'JupyterLab', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/jupyterlab/', - title: 'Deploy JupyterLab through the Linode Marketplace', - }, - ], - summary: 'Data science development environment.', - website: 'https://jupyter.org', - }, - { - alt_description: - 'Security research and testing platform with hundreds of tools for reverse engineering, penetration testing, and more.', - alt_name: 'Security research', - categories: ['Security'], - colors: { - end: '2fa1bc', - start: '267ff7', - }, - description: `Kali Linux is an open source, Debian-based Linux distribution that has become an industry-standard tool for penetration testing and security audits. Kali includes hundreds of free tools for reverse engineering, penetration testing and more. Kali prioritizes simplicity, making security best practices more accessible to everyone from cybersecurity professionals to hobbyists.`, - logo_url: 'kalilinux.svg', - name: 'Kali Linux', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/kali-linux/', - title: 'Deploy Kali Linux through the Linode Marketplace', - }, - ], - summary: - 'Popular Linux distribution and tool suite for penetration testing and security research.', - website: 'https://www.kali.org/', - }, - { - alt_description: 'Drag and drop website CMS.', - alt_name: 'CMS: content management system', - categories: ['Website'], - colors: { - end: '4395ff', - start: '0166ff', - }, - description: `Use Kepler Builder to easily design and build sites in WordPress - no coding or design knowledge necessary.`, - logo_url: 'keplerbuilder.svg', - name: 'Kepler Builder', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/kepler/', - title: 'Deploy Kepler through the Linode Marketplace', - }, - ], - summary: 'Powerful drag & drop WordPress website builder.', - website: 'https://kepler.app/', - }, - { - alt_description: 'Essential software stack for Linux applications.', - alt_name: 'Web stack', - categories: ['Stacks'], - colors: { - end: 'bfa477', - start: '3c4043', - }, - description: `The LAMP stack consists of the Linux operating system, the Apache HTTP Server, the MySQL relational database management system, and the PHP programming language. This software environment is a foundation for popular PHP application - frameworks like WordPress, Drupal, and Laravel. Upload your existing PHP application code to your new app or use a PHP framework to write a new application on the Linode.`, - logo_url: 'lamp_flame.svg', - name: 'LAMP', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/lamp-stack/', - title: 'Deploy a LAMP Stack through the Linode Marketplace', - }, - ], - summary: `Build PHP-based applications with the LAMP software stack: Linux, Apache, MySQL, and PHP.`, - }, - { - alt_description: 'Essential software stack for Linux applications.', - alt_name: 'Web stack', - categories: ['Stacks'], - colors: { - end: '005138', - start: '2e7d32', - }, - description: `LEMP provides a platform for applications that is compatible with the LAMP stack for nearly all applications; however, because NGINX is able to serve more pages at once with a more predictable memory usage profile, it may be more suited to high demand situations.`, - logo_url: 'lemp.svg', - name: 'LEMP', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/lemp-stack/', - title: 'Deploy a LEMP Stack through the Linode Marketplace', - }, - ], - summary: `The LEMP stack replaces the Apache web server component with NGINX (“Engine-X”), providing the E in the acronym: Linux, NGINX, MySQL/MariaDB, PHP.`, - }, - { - alt_description: - 'LinuxGSM is a command line utility that simplifies self-hosting multiplayer game servers.', - alt_name: 'Multiplayer Game Servers', - categories: ['Games'], - colors: { - end: 'F6BD0C', - start: '000000', - }, - description: `Self hosted multiplayer game servers.`, - logo_url: 'linuxgsm.svg', - name: 'LinuxGSM', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/linuxgsm/', - title: 'Deploy LinuxGSM through the Linode Marketplace', - }, - ], - summary: 'Simple command line multiplayer game servers.', - website: 'https://docs.linuxgsm.com', - }, - { - alt_description: 'Optimized control panel server.', - alt_name: 'Web server control panel', - categories: ['Website'], - colors: { - end: '6e92c7', - start: '353785', - }, - description: `High-performance LiteSpeed web server equipped with WHM/cPanel and WHM LiteSpeed Plugin.`, - logo_url: 'litespeedcpanel.svg', - name: 'LiteSpeed cPanel', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/litespeed-cpanel/', - title: 'Deploy LiteSpeed cPanel through the Linode Marketplace', - }, - ], - summary: 'Next-generation web server with cPanel and WHM.', - website: 'https://docs.litespeedtech.com/cp/cpanel/', - }, - { - alt_description: 'Audio and video streaming with E2E data encryption.', - alt_name: 'Live streaming', - categories: ['Media and Entertainment'], - colors: { - end: '4d8eff', - start: '346ee0', - }, - description: `Stream live audio or video while maximizing customer engagement with advanced built-in features. Liveswitch provides real-time monitoring, audience polling, and end-to-end (E2E) data encryption.`, - logo_url: 'liveswitch.svg', - name: 'LiveSwitch', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/liveswitch/', - title: 'Deploy LiveSwitch through the Linode Marketplace', - }, - ], - summary: 'High quality and reliable interactive live streaming.', - website: 'https://www.liveswitch.io/', - }, - { - alt_description: 'FFmpeg encoder plugins.', - alt_name: 'Premium video encoding', - categories: ['Media and Entertainment'], - colors: { - end: '041125', - start: '6DBA98', - }, - description: `MainConcept FFmpeg Plugins Demo is suited for both VOD and live production workflows, with advanced features such as Hybrid GPU acceleration and xHE-AAC audio format.`, - logo_url: 'mainconcept.svg', - name: 'MainConcept FFmpeg Plugins Demo', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/mainconcept-ffmpeg-plugins-demo/', - title: - 'Deploy MainConcept FFmpeg Plugins Demo through the Linode Marketplace', - }, - ], - summary: - 'MainConcept FFmpeg Plugins Demo contains advanced video encoding tools.', - website: 'https://www.mainconcept.com/ffmpeg', - }, - { - alt_description: 'Live video encoding engine.', - alt_name: 'Real time video encoding', - categories: ['Media and Entertainment'], - colors: { - end: '041125', - start: '6DBA98', - }, - description: `MainConcept Live Encoder Demo is a powerful all-in-one encoding engine designed to simplify common broadcast and OTT video workflows.`, - logo_url: 'mainconcept.svg', - name: 'MainConcept Live Encoder Demo', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/mainconcept-live-encoder-demo/', - title: - 'Deploy MainConcept Live Encoder Demo through the Linode Marketplace', - }, - ], - summary: 'MainConcept Live Encoder is a real time video encoding engine.', - website: 'https://www.mainconcept.com/live-encoder', - }, - { - alt_description: 'Panasonic camera format encoder.', - alt_name: 'Media encoding into professional file formats.', - categories: ['Media and Entertainment'], - colors: { - end: '041125', - start: '6DBA98', - }, - description: `MainConcept P2 AVC ULTRA Transcoder Demo is an optimized Docker container for file-based transcoding of media files into professional Panasonic camera formats like P2 AVC-Intra, P2 AVC LongG and AVC-intra RP2027.v1 and AAC High Efficiency v2 formats into an MP4 container.`, - logo_url: 'mainconcept.svg', - name: 'MainConcept P2 AVC ULTRA Transcoder Demo', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/mainconcept-p2-avc-ultra-demo/', - title: - 'Deploy MainConcept P2 AVC ULTRA Transcoder Demo through the Linode Marketplace', - }, - ], - summary: - 'MainConcept P2 AVC ULTRA Transcoder is a Docker container for file-based transcoding of media files into professional Panasonic camera formats.', - website: 'https://www.mainconcept.com/transcoders', - }, - { - alt_description: 'Sony camera format encoder.', - alt_name: 'Media encoding into professional file formats.', - categories: ['Media and Entertainment'], - colors: { - end: '041125', - start: '6DBA98', - }, - description: `MainConcept XAVC Transcoder Demo is an optimized Docker container for file-based transcoding of media files into professional Sony camera formats like XAVC-Intra, XAVC Long GOP and XAVC-S.`, - logo_url: 'mainconcept.svg', - name: 'MainConcept XAVC Transcoder Demo', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/mainconcept-xavc-transcoder-demo/', - title: - 'Deploy MainConcept XAVC Transcoder Demo through the Linode Marketplace', - }, - ], - summary: - 'MainConcept XAVC Transcoder is a Docker container for file-based transcoding of media files into professional Sony camera formats.', - website: 'https://www.mainconcept.com/transcoders', - }, - { - alt_description: 'Sony XDCAM format encoder.', - alt_name: 'Media encoding into professional file formats.', - categories: ['Media and Entertainment'], - colors: { - end: '041125', - start: '6DBA98', - }, - description: `MainConcept XDCAM Transcoder Demo is an optimized Docker container for file-based transcoding of media files into professional Sony camera formats like XDCAM HD, XDCAM EX, XDCAM IMX and DVCAM (XDCAM DV).`, - logo_url: 'mainconcept.svg', - name: 'MainConcept XDCAM Transcoder Demo', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/mainconcept-xdcam-transcoder-demo/', - title: - 'Deploy MainConcept XDCAM Transcoder Demo through the Linode Marketplace', - }, - ], - summary: - 'MainConcept XDCAM Transcoder is a Docker container for file-based transcoding of media files into professional Sony camera formats.', - website: 'https://www.mainconcept.com/transcoders', - }, - { - alt_description: 'Open source Twitter alternative.', - alt_name: 'Open source social media', - categories: ['Media and Entertainment'], - colors: { - end: '563ACC', - start: '6364FF', - }, - description: `Mastodon is an open-source and decentralized micro-blogging platform, supporting federation and public access to the server.`, - logo_url: 'mastodon.svg', - name: 'Mastodon', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/mastodon/', - title: 'Deploy Mastodon through the Linode Marketplace', - }, - ], - summary: - 'Mastodon is an open-source and decentralized micro-blogging platform.', - website: 'https://docs.joinmastodon.org/', - }, - { - alt_description: 'Angular and Node.js stack.', - alt_name: 'Web framework', - categories: ['Development'], - colors: { - end: '686868', - start: '323232', - }, - description: `MEAN is a full-stack JavaScript-based framework which accelerates web application development much faster than other frameworks. All involved technologies are well-established, offer robust feature sets, and are well-supported by their maintaining organizations. These characteristics make them a great choice for your applications.`, - logo_url: 'mean.svg', - name: 'MEAN', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/mean-stack/', - title: 'Deploy a MEAN Stack through the Linode Marketplace', - }, - ], - summary: `A MEAN (MongoDB, Express, Angular, Node.js) stack is a free and open-source web software bundle used to build modern web applications.`, - website: 'http://meanjs.org/', - }, - { - alt_description: 'React and Node.js stack.', - alt_name: 'Web stack', - categories: [], - colors: { - end: '256291', - start: '30383a', - }, - description: `MERN is a full stack platform that contains everything you need to build a web application: MongoDB, a document database used to persist your application's data; Express, which serves as the web application framework; React, used to build your application's user interfaces; - and Node.js, which serves as the run-time environment for your application. All of these technologies are well-established, offer robust feature sets, and are well-supported by their maintaining organizations. These characteristics make them a great choice for your applications. Upload your - existing MERN website code to your new Linode, or use MERN's scaffolding tool to start writing new web applications on the Linode.`, - logo_url: 'mern.svg', - name: 'MERN', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/mern-stack/', - title: 'Deploy a MERN Stack through the Linode Marketplace', - }, - ], - summary: `Build production-ready apps with the MERN stack: MongoDB, Express, React, and Node.js.`, - }, - { - alt_description: 'Drag and drop website CMS.', - alt_name: 'Website builder', - categories: ['Development'], - colors: { - end: '4592ff', - start: '4592ff', - }, - description: `Microweber is an easy Drag and Drop website builder and a powerful CMS of a new generation, based on the PHP Laravel Framework.`, - logo_url: 'microweber.svg', - name: 'Microweber', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/microweber/', - title: 'Deploy Microweber through the Linode Marketplace', - }, - ], - summary: `Drag and drop CMS and website builder.`, - website: 'https://microweber.com/', - }, - { - alt_description: 'Classic open world survival crafting game.', - alt_name: 'World building game', - categories: ['Games'], - colors: { - end: 'd0c8c4', - start: '97948f', - }, - description: `With over 100 million users around the world, Minecraft is the most popular online game of all time. Less of a game and more of a lifestyle choice, you and other players are free to build and explore in a 3D generated world made up of millions of mineable blocks. Collect resources by leveling mountains, - taming forests, and venturing out to sea. Choose a home from the varied list of biomes like ice worlds, flower plains, and jungles. Build ancient castles or modern mega cities, and fill them with redstone circuit contraptions and villagers. Fight off nightly invasions of Skeletons, Zombies, and explosive - Creepers, or adventure to the End and the Nether to summon the fabled End Dragon and the chaotic Wither. If that is not enough, Minecraft is also highly moddable and customizable. You decide the rules when hosting your own Minecraft server for you and your friends to play together in this highly addictive game.`, - logo_url: 'minecraft.svg', - name: 'Minecraft: Java Edition', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/minecraft/', - title: 'Deploy a Minecraft Server through the Linode Marketplace', - }, - ], - summary: `Build, explore, and adventure in your own 3D generated world.`, - website: 'https://www.minecraft.net/', - }, - { - alt_description: 'Open source course builder and education tool.', - alt_name: 'Online course CMS', - categories: ['Website'], - colors: { - end: '494949', - start: 'ff7800', - }, - description: `Robust open-source learning platform enabling online education for more than 200 million users around the world. Create personalized learning environments within a secure and integrated system built for all education levels with an intuitive interface, drag-and-drop features, and accessible documentation.`, - logo_url: 'moodle.svg', - name: 'Moodle', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/moodle/', - title: 'Deploy Moodle through the Linode Marketplace', - }, - ], - summary: - 'World’s most popular learning management system built and maintained by an active developer community.', - website: 'https://docs.moodle.org/', - }, - { - alt_description: 'SQL database.', - alt_name: 'SQL database', - categories: ['Databases'], - colors: { - end: '8a9177', - start: '1d758f', - }, - description: `MySQL, or MariaDB for Linux distributions, is primarily used for web and server applications, including as a component of the industry-standard LAMP and LEMP stacks.`, - logo_url: 'mysql.svg', - name: 'MySQL/MariaDB', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/mysql/', - title: 'Deploy MySQL/MariaDB through the Linode Marketplace', - }, - ], - summary: `World's most popular open source database.`, - website: 'https://www.mysql.com/', - }, - { - alt_description: `Microservice centeric stream processing.`, - alt_name: 'Microservice messaging bus', - categories: ['Development'], - colors: { - end: '000000', - start: '0086FF', - }, - description: - 'NATS is a distributed PubSub technology that enables applications to securely communicate across any combination of cloud vendors, on-premise, edge, web and mobile, and devices.', - logo_url: 'nats.svg', - name: 'NATS Single Node', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/nats-single-node/', - title: 'Deploy NATS single node through the Linode Marketplace', - }, - ], - summary: 'Cloud native application messaging service.', - website: 'https://nats.io', - }, - { - alt_description: - 'File storage alternative to Dropbox and office suite alternative to Microsoft Office.', - alt_name: 'File storage management & business tool suite', - categories: ['Productivity'], - colors: { - end: '2a2a36', - start: '16a5f3', - }, - description: `Nextcloud AIO stands for Nextcloud All In One, and provides easy deployment and maintenance for popular Nextcloud tools. AIO includes Nextcloud, Nextcloud Office, OnlyOffice, and high-performance backend features.`, - logo_url: 'nextcloud.svg', - name: 'Nextcloud', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/nextcloud/', - title: 'Deploy Nextcloud through the Linode Marketplace', - }, - ], - summary: `A safe home for all your data.`, - }, - { - alt_description: - 'File storage and sharing alternative to Dropbox and Google Drive.', - alt_name: 'File sharing', - categories: ['Productivity'], - colors: { - end: '252730', - start: '1f4c8f', - }, - description: `Securely share and collaborate Linode S3 object storage files/folders with your internal or external users such as customers, partners, vendors, etc with fine access control and a simple interface. Nirvashare easily integrates with many external identity providers such as Active Directory, GSuite, AWS SSO, KeyClock, etc.`, - logo_url: 'nirvashare.svg', - name: 'NirvaShare', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/nirvashare/', - title: 'Deploy NirvaShare through the Linode Marketplace', - }, - ], - summary: - 'Secure file sharing for better collaboration with employees, partners, vendors, and more.', - website: 'https://nirvashare.com/setup-guide/', - }, - { - alt_description: - 'Versatile cross-platform JavaScript run-time (runtime) environment.', - alt_name: 'JavaScript environment', - categories: ['Development'], - colors: { - end: '333333', - start: '3d853c', - }, - description: `NodeJS is a free, open-source, and cross-platform JavaScript run-time environment that lets developers write command line tools and server-side scripts outside of a browser.`, - logo_url: 'nodejs.svg', - name: 'NodeJS', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/nodejs/', - title: 'Deploy NodeJS through the Linode Marketplace', - }, - ], - summary: - 'Popular and versatile open source JavaScript run-time environment.', - website: 'https://nodejs.org/', - }, - { - alt_description: - 'Open source marketing and business platform with a CRM and email marketing.', - alt_name: 'Marketing tool suite', - categories: ['Productivity'], - colors: { - end: '027e84', - start: '55354c', - }, - description: `Odoo is a free and comprehensive business app suite of tools that seamlessly integrate. Choose what you need to manage your business on a single platform, including a CRM, email marketing tools, essential project management functions, and more.`, - logo_url: 'odoo.svg', - name: 'Odoo', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/odoo/', - title: 'Deploy Odoo through the Linode Marketplace', - }, - ], - summary: - 'Open source, all-in-one business app suite with more than 7 million users.', - website: 'https://www.odoo.com/', - }, - { - alt_description: 'Office Suite', - alt_name: 'Office Docs', - categories: ['Productivity'], - colors: { - end: 'ff6f3d', - start: 'ffa85b', - }, - description: `Create and collaborate on text documents, spreadsheets, and presentations compatible with popular file types including .docx, .xlsx, and more. Additional features include real-time editing, paragraph locking while co-editing, and version history.`, - logo_url: 'onlyoffice.svg', - name: 'ONLYOFFICE Docs', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/onlyoffice/', - title: 'Deploy ONLYOFFICE Docs through the Linode Marketplace', - }, - ], - summary: 'Open source comprehensive office suite.', - website: 'https://www.onlyoffice.com/', - }, - { - alt_description: 'Fast Python development with best practices.', - alt_name: 'Python framework', - categories: ['Development'], - colors: { - end: '5cbf8a', - start: '318640', - }, - description: `Simple deployment for OLS web server, Python LSAPI, and CertBot.`, - logo_url: 'openlitespeeddjango.svg', - name: 'OpenLiteSpeed Django', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/openlitespeed-django/', - title: 'Deploy OpenLiteSpeed Django through the Linode Marketplace', - }, - ], - summary: 'OLS web server with Django development framework.', - website: 'https://docs.litespeedtech.com/cloud/images/django/', - }, - { - alt_description: - 'Versatile cross-platform JavaScript run-time (runtime) environment.', - alt_name: 'JavaScript environment', - categories: ['Development'], - colors: { - end: '33cccc', - start: '3d596d', - }, - description: `High-performance open source web server with Node and CertBot, in addition to features like HTTP/3 support and easy SSL setup.`, - logo_url: 'openlitespeednodejs.svg', - name: 'OpenLiteSpeed NodeJS', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/openlitespeed-nodejs/', - title: 'Deploy OpenLiteSpeed Node.js through the Linode Marketplace', - }, - ], - summary: 'OLS web server with NodeJS JavaScript runtime environment.', - website: 'https://docs.litespeedtech.com/cloud/images/nodejs/', - }, - { - alt_description: 'Ruby web application framework with development tools.', - alt_name: 'Ruby web application framework.', - categories: ['Development'], - colors: { - end: 'd94b7a', - start: '8e1a4a', - }, - description: `Easy setup to run Ruby apps in the cloud and take advantage of OpenLiteSpeed server features like SSL, HTTP/3 support, and RewriteRules.`, - logo_url: 'openlitespeedrails.svg', - name: 'OpenLiteSpeed Rails', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/openlitespeed-rails/', - title: 'Deploy OpenLiteSpeed Rails through the Linode Marketplace ', - }, - ], - summary: 'OLS web server with Ruby and CertBot.', - website: 'https://docs.litespeedtech.com/cloud/images/rails/', - }, - { - alt_description: 'Popular website content management system.', - alt_name: 'CMS: content management system', - categories: ['Website'], - colors: { - end: '3d596d', - start: '33cccc', - }, - description: `Accelerated and scalable hosting for WordPress. Includes OpenLiteSpeed, PHP, MySQL Server, WordPress, and LiteSpeed Cache.`, - logo_url: 'openlitespeedwordpress.svg', - name: 'OpenLiteSpeed WordPress', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/openlitespeed-wordpress/', - title: 'Deploy OpenLiteSpeed Wordpress through the Linode Marketplace', - }, - ], - summary: 'Blazing fast, open source alternative to LiteSpeed Web Server.', - website: 'https://openlitespeed.org/', - }, - { - alt_description: 'Popular virtual private network.', - alt_name: 'Free VPN', - categories: ['Security'], - colors: { - end: '193766', - start: 'ea7e20', - }, - description: `OpenVPN is a widely trusted, free, and open-source virtual private network application. OpenVPN creates network tunnels between groups of computers that are not on the same local network, and it uses OpenSSL to encrypt your traffic.`, - logo_url: 'openvpn.svg', - name: 'OpenVPN', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/openvpn/', - title: 'Deploy OpenVPN through the Linode Marketplace', - }, - ], - summary: `Open-source virtual private network (VPN) application. OpenVPN securely connects your computer to your servers, or to the public Internet.`, - website: 'https://openvpn.net/', - }, - { - alt_description: 'Video and audio live streaming alternative to Twitch.', - alt_name: 'Live streaming app', - categories: ['Media and Entertainment'], - colors: { - end: '2086e1', - start: '7871ff', - }, - description: `A live streaming and chat server for use with existing popular broadcasting software.`, - logo_url: 'owncast.svg', - name: 'Owncast', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/owncast/', - title: 'Deploy Owncast through the Linode Marketplace', - }, - ], - summary: - 'The standalone “Twitch in a Box” open source streaming and chat solution.', - website: 'https://owncast.online/', - }, - { - alt_description: 'Self-hosted file sharing and collaboration platform.', - alt_name: 'Collabrative file sharing', - categories: ['Productivity'], - colors: { - end: '041e42', - start: '041e42', - }, - description: `LAMP-stack-based server application that allows you to access your files from anywhere in a secure way.`, - logo_url: 'owncloud.svg', - name: 'ownCloud', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/owncloud/', - title: 'Deploy ownCloud through the Linode Marketplace', - }, - ], - summary: - 'Dropbox and OneDrive alternative that lets you remain in control of your files.', - website: 'https://doc.owncloud.com/docs/next/', - }, - { - alt_description: 'Password Manager', - alt_name: 'Passbolt', - categories: ['Security'], - colors: { - end: 'D40101', - start: '171717', - }, - description: `Passbolt is an open-source password manager designed for teams and businesses. It allows users to securely store, share and manage passwords.`, - logo_url: 'passbolt.svg', - name: 'Passbolt', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/passbolt/', - title: 'Deploy Passbolt through the Linode Marketplace', - }, - ], - summary: 'Open-source password manager for teams and businesses.', - website: 'https://www.passbolt.com/', - }, - { - alt_description: 'Password Manager', - alt_name: 'Pass Key', - categories: ['Security'], - colors: { - end: '3A5EFF', - start: '709cff', - }, - description: `Self-host a password manager designed to simplify and secure your digital life. Passky is a streamlined version of paid password managers designed for everyone to use.`, - logo_url: 'passky.svg', - name: 'Passky', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/passky/', - title: 'Deploy Passky through the Linode Marketplace', - }, - ], - summary: 'Simple open source password manager.', - website: 'https://passky.org/', - }, - { - alt_description: 'Open source project management tool.', - alt_name: 'Ticket management project management tool', - categories: ['Productivity'], - colors: { - end: '0a0a0a', - start: '4cff4c', - }, - description: `Open source alternative to paid ticket management solutions with essential features including a streamlined task list, project and client management, and ticket prioritization.`, - logo_url: 'peppermint.svg', - name: 'Peppermint', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/peppermint/', - title: 'Deploy Peppermint through the Linode Marketplace', - }, - ], - summary: 'Simple yet scalable open source ticket management.', - website: 'https://peppermint.sh/', - }, - { - alt_description: - 'Web interface for MySQL/MariaDB operations and server administration.', - alt_name: 'SQL database GUI', - categories: ['Databases'], - colors: { - end: '6c78af', - start: 'f89d10', - }, - description: `Intuitive web interface for MySQL and MariaDB operations, including importing/exporting data, administering multiple servers, and global database search.`, - logo_url: 'phpmyadmin.svg', - name: 'phpMyAdmin', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/phpmyadmin/', - title: 'Deploy phpMyAdmin through the Linode Marketplace', - }, - ], - summary: 'Popular free administration tool for MySQL and MariaDB.', - website: 'https://www.phpmyadmin.net/', - }, - { - alt_description: 'Popular DNS privacy sinkhole.', - alt_name: 'Network ad blocking', - categories: ['Security'], - colors: { - end: 'f60d1a', - start: '96060c', - }, - description: `Protect your network and devices from unwanted content. Avoid ads in non-browser locations with a free, lightweight, and comprehensive privacy solution you can self-host.`, - logo_url: 'pihole.svg', - name: 'Pi-hole', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/pihole/', - title: 'Deploy Pi-hole through the Linode Marketplace', - }, - ], - summary: 'Free, open source, and highly scalable DNS sinkhole.', - website: 'https://pi-hole.net/', - }, - { - alt_description: 'Popular WordPress server management.', - alt_name: 'WordPress control panel', - categories: ['Control Panels'], - colors: { - end: '4b5868', - start: '53bce6', - }, - description: `Plesk is a leading WordPress and website management platform and control panel. Plesk lets you build and manage multiple websites from a single dashboard to configure web services, email, and other applications. Plesk features hundreds of extensions, plus a complete WordPress toolkit. Use the Plesk One-Click App to manage websites hosted on your Linode.`, - logo_url: 'plesk.svg', - name: 'Plesk', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/plesk/', - title: 'Deploy Plesk through the Linode Marketplace', - }, - ], - summary: - 'A secure, scalable, and versatile website and WordPress management platform.', - website: 'https://www.plesk.com/', - }, - { - alt_description: - 'Video / media library storage and sharing across TVs, phones, computers, and more.', - alt_name: 'Media server', - categories: [], - colors: { - end: '332c37', - start: 'e5a00d', - }, - description: `Organize, stream, and share your media library with friends, in addition to free live TV in 220+ countries.`, - logo_url: 'plex.svg', - name: 'Plex', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/plex/', - title: 'Deploy Plex Media Server through the Linode Marketplace', - }, - ], - summary: - 'Media server and streaming service to stay entertained across devices.', - website: 'https://www.plex.tv/', - }, - { - alt_description: 'MySQL alternative for SQL database.', - alt_name: 'SQL database', - categories: ['Databases'], - colors: { - end: '254078', - start: '326690', - }, - description: `PostgreSQL is a popular open source relational database system that provides many advanced configuration options that can help optimize your database’s performance in a production environment.`, - logo_url: 'postgresql.svg', - name: 'PostgreSQL', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/postgresql/', - title: 'Deploy PostgreSQL through the Linode Marketplace', - }, - ], - summary: `The PostgreSQL relational database system is a powerful, scalable, and standards-compliant open-source database platform.`, - website: 'https://www.postgresql.org/', - }, - { - alt_description: 'MySQL alternative for SQL database.', - alt_name: 'SQL database', - categories: ['Databases'], - colors: { - end: '254078', - start: '326690', - }, - description: `PostgreSQL is a popular open source relational database system that provides many advanced configuration options that can help optimize your database’s performance in a production environment.`, - logo_url: 'postgresqlmarketplaceocc.svg', - name: 'PostgreSQL Cluster', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/postgresql-cluster/', - title: 'Deploy PostgreSQL Cluster through the Linode Marketplace', - }, - ], - summary: `The PostgreSQL relational database system is a powerful, scalable, and standards-compliant open-source database platform.`, - website: 'https://www.postgresql.org/', - }, - { - alt_description: 'Virtual private network for businesses and teams.', - alt_name: 'Enterprise VPN', - categories: ['Security'], - colors: { - end: '2e72d2', - start: '2e4153', - }, - description: `User-friendly VPN for both individual and commercial use. Choose from three pricing plans.`, - logo_url: 'pritunl.svg', - name: 'Pritunl', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/pritunl/', - title: 'Deploy Pritunl through the Linode Marketplace', - }, - ], - summary: 'Enterprise open source VPN.', - website: 'https://docs.pritunl.com/docs', - }, - { - alt_description: 'Monitoring server.', - alt_name: 'Server monitoring and visualization', - categories: ['Monitoring'], - colors: { - end: 'e6522c', - start: 'f9b716', - }, - description: `Free industry-standard monitoring tools that work better together. Prometheus is a powerful monitoring software tool that collects metrics from configurable data points at given intervals, evaluates rule expressions, and can trigger alerts if some condition is observed. Use Grafana to create visuals, monitor, store, and share metrics with your team to keep tabs on your infrastructure.`, - logo_url: 'prometheusgrafana.svg', - name: 'Prometheus & Grafana', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/prometheus-grafana/', - title: 'Deploy Prometheus & Grafana through the Linode Marketplace', - }, - ], - summary: 'Open source metrics and monitoring for real-time insights.', - website: 'https://prometheus.io/docs/visualization/grafana/', - }, - { - alt_description: 'Server work queue management.', - alt_name: 'Message broker', - categories: ['Development'], - colors: { - end: 'ff6600', - start: 'a9b5af', - }, - description: `Connect and scale applications with asynchronous messaging and highly available work queues, all controlled through an intuitive management UI.`, - logo_url: 'rabbitmq.svg', - name: 'RabbitMQ', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/rabbitmq/', - title: 'Deploy RabbitMQ through the Linode Marketplace', - }, - ], - summary: 'Most popular open source message broker.', - website: 'https://www.rabbitmq.com/', - }, - { - alt_description: 'In-memory caching database.', - alt_name: 'High performance database', - categories: ['Databases'], - colors: { - end: '722b20', - start: '222222', - }, - description: `Redis® is an open-source, in-memory, data-structure store, with the optional ability to write and persist data to a disk, which can be used as a key-value database, cache, and message broker. Redis® features built-in transactions, replication, and support for a variety of data structures such as strings, hashes, lists, sets, and others.

*Redis is a registered trademark of Redis Ltd. Any rights therein are reserved to Redis Ltd. Any use by Akamai Technologies is for referential purposes only and does not indicate any sponsorship, endorsement or affiliation between Redis and Akamai Technologies.`, - logo_url: 'redis.svg', - name: 'Marketplace App for Redis®', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/redis/', - title: 'Deploy Redis® through the Linode Marketplace', - }, - ], - summary: - 'Flexible, in-memory, NoSQL database service supported in many different coding languages.', - website: 'https://redis.io/', - }, - { - alt_description: 'In-memory caching database.', - alt_name: 'High performance database', - categories: ['Databases'], - colors: { - end: '722b20', - start: '222222', - }, - description: `Redis® is an open-source, in-memory, data-structure store, with the optional ability to write and persist data to a disk, which can be used as a key-value database, cache, and message broker. Redis® features built-in transactions, replication, and support for a variety of data structures such as strings, hashes, lists, sets, and others.

*Redis is a registered trademark of Redis Ltd. Any rights therein are reserved to Redis Ltd. Any use by Akamai Technologies is for referential purposes only and does not indicate any sponsorship, endorsement or affiliation between Redis and Akamai Technologies.`, - logo_url: 'redissentinelmarketplaceocc.svg', - name: 'Marketplace App for Redis® Sentinel Cluster', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/redis-cluster/', - title: - 'Deploy Redis® Sentinel Cluster through the Linode Marketplace', - }, - ], - summary: - 'Flexible, in-memory, NoSQL database service supported in many different coding languages.', - website: 'https://redis.io/', - }, - { - alt_description: 'Free alternative to Trello and Asana.', - alt_name: 'Kanban board project management tool', - categories: ['Productivity'], - colors: { - end: '555555', - start: 'f47564', - }, - description: `Restyaboard is an open-source alternative to Trello, but with additional smart features like offline sync, diff /revisions, nested comments, multiple view layouts, chat, and more.`, - logo_url: 'restyaboard.svg', - name: 'Restyaboard', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/restyaboard/', - title: 'Deploy Restyaboard through the Linode Marketplace', - }, - ], - summary: 'Free and open source project management tool.', - website: 'https://restya.com', - }, - { - alt_description: 'Free alternative to Slack, Microsoft Teams, and Skype.', - alt_name: 'Chat software', - categories: ['Productivity'], - colors: { - end: '030d1a', - start: 'f5445c', - }, - description: `Put data privacy first with an alternative to programs like Slack and Microsoft Teams.`, - logo_url: 'rocketchat.svg', - name: 'Rocket.Chat', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/rocketchat/', - title: 'Deploy Rocket.Chat through the Linode Marketplace', - }, - ], - summary: 'Feature-rich self-hosted chat and collaboration platform.', - website: 'https://docs.rocket.chat/', - }, - { - alt_description: 'Ruby web application framework with development tools.', - alt_name: 'Web application framework', - categories: ['Development'], - colors: { - end: 'fa9999', - start: '722b20', - }, - description: `Rails is a web application development framework written in the Ruby programming language. It is designed to make programming web applications easier by giving every developer a number of common tools they need to get started. Ruby on Rails empowers you to accomplish more with less code.`, - logo_url: 'rubyonrails.svg', - name: 'Ruby on Rails', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/ruby-on-rails/', - title: 'Deploy Ruby on Rails through the Linode Marketplace', - }, - ], - summary: `Ruby on Rails is a web framework that allows web designers and developers to implement dynamic, fully featured web applications.`, - website: 'https://rubyonrails.org/', - }, - { - alt_description: 'Database low-code/no-code application builder.', - alt_name: 'Low-code application builder', - categories: ['Development'], - colors: { - end: 'ff8e42', - start: '995ad9', - }, - description: `Build applications without writing a single line of code. Saltcorn is a free platform that allows you to build an app with an intuitive point-and-click, drag-and-drop UI.`, - logo_url: 'saltcorn.svg', - name: 'Saltcorn', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/saltcorn/', - title: 'Deploy Saltcorn through the Linode Marketplace', - }, - ], - summary: 'Open source, no-code database application builder.', - website: 'https://saltcorn.com/', - }, - { - alt_description: 'A safe home for all your data.', - alt_name: - 'Spreadsheet style interface with the power of a relational database.', - categories: ['Productivity'], - colors: { - end: 'FF8000', - start: 'FF8000', - }, - description: `Self-hosted database for a variety of management projects.`, - logo_url: 'seatable.svg', - name: 'Seatable', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/seatable/', - title: 'Deploy Seatable through the Linode Marketplace', - }, - ], - summary: - 'Collaborative web interface for data backed project and process management.', - website: 'https://seatable.io/docs/?lang=auto', - }, - { - alt_description: 'Limited user, hardened SSH, Fail2Ban Linode server.', - alt_name: 'Secure server tool', - categories: ['Security'], - colors: { - end: '32363b', - start: '01b058', - }, - description: `Save time on securing your Linode by deploying an instance pre-configured with some basic security best practices: limited user account access, hardened SSH, and Fail2Ban for SSH Login Protection.`, - logo_url: 'secureyourserver.svg', - name: 'Secure Your Server', - related_guides: [ - { - href: 'https://www.linode.com/docs/guides/set-up-and-secure/', - title: 'Securing your Server', - }, - ], - summary: `Harden your Linode before you deploy with the Secure Your Server One-Click App.`, - }, - { - alt_description: 'Host multiple sites on a Linode.', - alt_name: 'Website control panel', - categories: ['Control Panels'], - colors: { - end: 'a25c57', - start: '4c3148', - }, - description: `Host multiple sites on a single server while managing apps, firewall, databases, backups, system users, cron jobs, SSL and email– all in an intuitive interface.`, - logo_url: 'serverwand.svg', - name: 'ServerWand', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/serverwand/', - title: 'Deploy ServerWand through the Linode Marketplace', - }, - ], - summary: - 'Magical control panel for hosting websites and managing your servers.', - website: 'https://serverwand.com/', - }, - { - alt_description: 'Secure SOCKS5 web proxy with data encryption.', - alt_name: 'VPN proxy', - categories: ['Security'], - colors: { - end: '8d8d8d', - start: '227dc0', - }, - description: - 'Shadowsocks is a lightweight SOCKS5 web proxy tool. A full setup requires a Linode server to host the Shadowsocks daemon, and a client installed on PC, Mac, Linux, or a mobile device. Unlike other proxy software, Shadowsocks traffic is designed to be both indiscernible from other traffic to third-party monitoring tools, and also able to disguise itself as a normal direct connection. Data passing through Shadowsocks is encrypted for additional security and privacy.', - logo_url: 'shadowsocks.svg', - name: 'Shadowsocks', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/shadowsocks/', - title: 'Deploy Shadowsocks through the Linode Marketplace', - }, - ], - summary: - 'A secure socks5 proxy, designed to protect your Internet traffic.', - website: 'https://shadowsocks.org/', - }, - { - alt_description: 'Data security, data observability, data automation.', - alt_name: 'Data management', - categories: ['Development'], - colors: { - end: 'ed0181', - start: 'f89f24', - }, - description: `Popular data-to-everything platform with advanced security, observability, and automation features for machine learning and AI.`, - logo_url: 'splunk.svg', - name: 'Splunk', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/splunk/', - title: 'Deploy Splunk through the Linode Marketplace', - }, - ], - summary: - 'All-in-one database deployment, management, and monitoring system.', - website: 'https://docs.splunk.com/Documentation/Splunk', - }, - { - alt_description: 'A private by design messaging platform.', - alt_name: 'Anonymous messaging platform.', - categories: ['Productivity'], - colors: { - end: '70f0f9', - start: '11182f', - }, - description: `SimpleX Chat - The first messaging platform that has no user identifiers of any kind - 100% private by design. SMP server is the relay server used to pass messages in SimpleX network. XFTP is a new file transfer protocol focussed on meta-data protection. This One-Click APP will deploy both SMP and XFTP servers.`, - logo_url: 'simplexchat.svg', - name: 'SimpleX Chat', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/simplex/', - title: 'Deploy SimpleX chat through the Linode Marketplace', - }, - ], - summary: 'Private by design messaging server.', - website: 'https://simplex.chat', - }, - { - alt_description: - 'A simple SQL interface to store and search unstructured data.', - alt_name: 'SuperinsightDB', - categories: ['Databases'], - colors: { - end: 'C54349', - start: 'E6645F', - }, - description: `Superinsight provides a simple SQL interface to store and search unstructured data. Superinsight is built on top of PostgreSQL to take advantage of powerful extensions and features, plus the ability to run machine learning operations using SQL statements.`, - logo_url: 'superinsight.svg', - name: 'Superinsight', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/superinsight/', - title: 'Deploy Superinsight through the Linode Marketplace', - }, - ], - summary: 'Relational database for unstructured data.', - website: 'https://www.superinsight.ai/', - }, - { - alt_description: - 'Infrastructure monitoring and aler alternative to Uptime Robot.', - alt_name: 'Infrastructure monitoring', - categories: ['Monitoring'], - colors: { - end: 'baecca', - start: '67de92', - }, - description: `Uptime Kuma is self-hosted alternative to Uptime Robot. Get real-time performance insights for HTTP(s), TCP/ HTTP(s) Keyword, Ping, DNS Record, and more. Monitor everything you need in one UI dashboard, or customize how you receive alerts with a wide range of supported integrations.`, - logo_url: 'uptimekuma.svg', - name: 'Uptime Kuma', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/uptime-kuma/', - title: 'Deploy Uptime Kuma through the Linode Marketplace', - }, - ], - summary: 'Free, comprehensive, and “fancy” monitoring solution.', - website: 'https://github.com/louislam/uptime-kuma', - }, - { - alt_description: 'Virtual private network.', - alt_name: 'VPN', - categories: ['Security'], - colors: { - end: '1a32b1', - start: '2ec1cf', - }, - description: `UTunnel VPN is a robust cloud-based VPN server software solution. With UTunnel VPN, businesses could easily set up secure remote access to their business network. UTunnel comes with a host of business-centric features including site-to-site connectivity, single sign-on integration, 2-factor authentication, etc.`, - logo_url: 'utunnel.svg', - name: 'UTunnel VPN', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/utunnel/', - title: 'Deploy UTunnel VPN through the Linode Marketplace', - }, - ], - summary: - 'A powerful, user-friendly Virtual Private Network (VPN) server application that supports multiple VPN protocols.', - website: 'https://www.utunnel.io/linode-vpn-server.html', - }, - { - alt_description: 'Time series database and database monitoring/metrics.', - alt_name: 'Database monitoring', - categories: ['Databases'], - colors: { - end: 'af3e56', - start: '6a1e6e', - }, - description: `VictoriaMetrics is designed to collect, store, and process real-time metrics.`, - logo_url: 'victoriametricssingle.svg', - name: 'VictoriaMetrics Single', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/victoriametrics-single/', - title: 'Deploy VictoriaMetrics Single through the Linode Marketplace', - }, - ], - summary: - 'Free and open source time series database (TSDB) and monitoring solution.', - website: 'https://victoriametrics.com/', - }, - { - alt_description: 'Fancy development text editor.', - alt_name: 'Text editor', - categories: ['Development'], - colors: { - end: '0066b8', - start: '23a9f2', - }, - description: `Launch a portable development environment to speed up tests, downloads, and more.`, - logo_url: 'vscodeserver.svg', - name: 'VS Code Server', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/vscode/', - title: 'Deploy VS Code through the Linode Marketplace', - }, - ], - summary: 'Run VS code in the cloud, right from your browser.', - website: 'https://github.com/cdr/code-server', - }, - { - alt_description: 'Virtual private network.', - alt_name: 'WireGuard VPN', - categories: ['Security'], - colors: { - end: '333333', - start: '1f76b7', - }, - description: `Feature-rich, self-hosted VPN based on WireGuardÂŽ protocol, plus convenient features like single sign-on, real-time bandwidth monitoring, and unlimited users/devices.`, - logo_url: 'warpspeed.svg', - name: 'WarpSpeed', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/warpspeed/', - title: 'Deploy WarpSpeed VPN through the Linode Marketplace', - }, - ], - summary: 'Secure low-latency VPN powered by WireGuardÂŽ protocol.', - website: 'https://bunker.services/products/warpspeed', - }, - { - alt_description: - 'Security analytics for intrusion attempts and user action monitoring.', - alt_name: 'Security monitoring', - categories: ['Security'], - colors: { - end: 'ffb600', - start: '00a9e5', - }, - description: `Infrastructure monitoring solution to detect threats, intrusion attempts, unauthorized user actions, and provide security analytics.`, - logo_url: 'wazuh.svg', - name: 'Wazuh', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/wazuh/', - title: 'Deploy Wazuh through the Linode Marketplace', - }, - ], - summary: 'Free open source security monitoring solution.', - website: 'https://documentation.wazuh.com/current/index.html', - }, - { - alt_description: - 'Control panel to deploy and manage LAMP stack applications.', - alt_name: 'Single user control panel', - categories: ['Control Panels'], - colors: { - end: '445289', - start: 'f1b55d', - }, - description: `Lightweight control panel with a suite of features to streamline app management.`, - logo_url: 'webuzo.svg', - name: 'Webuzo', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/webuzo/', - title: 'Deploy Webuzo through the Linode Marketplace', - }, - ], - summary: - 'LAMP stack and single user control panel to simplify app deployment in the cloud.', - website: 'http://www.webuzo.com/', - }, - { - alt_description: 'Virtual private network.', - alt_name: 'Free VPN', - categories: ['Security'], - colors: { - end: '51171a', - start: '88171a', - }, - description: `Configuring WireGuard® is as simple as configuring SSH. A connection is established by an exchange of public keys between server and client, and only a client whose public key is present in the server's configuration file is considered authorized. WireGuard sets up - standard network interfaces which behave similarly to other common network interfaces, like eth0. This makes it possible to configure and manage WireGuard interfaces using standard networking tools such as ifconfig and ip. "WireGuard" is a registered trademark of Jason A. Donenfeld.`, - logo_url: 'wireguard.svg', - name: 'WireGuard®', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/wireguard/', - title: 'Deploy WireGuard through the Linode Marketplace', - }, - ], - summary: `Modern VPN which utilizes state-of-the-art cryptography. It aims to be faster and leaner than other VPN protocols and has a smaller source code footprint.`, - website: 'https://www.wireguard.com/', - }, - { - alt_description: 'Popular secure WordPress ecommerce online store plugin.', - alt_name: 'Ecommerce site', - categories: ['Website'], - colors: { - end: '743b8a', - start: '96588a', - }, - description: `With WooCommerce, you can securely sell both digital and physical goods, and take payments via major credit cards, bank transfers, PayPal, and other providers like Stripe. With more than 300 extensions to choose from, WooCommerce is extremely flexible.`, - logo_url: 'woocommerce.svg', - name: 'WooCommerce', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/woocommerce/', - title: 'Deploy WooCommerce through the Linode Marketplace', - }, - ], - summary: `Highly customizable, secure, open source eCommerce platform built to integrate with Wordpress.`, - website: 'https://woocommerce.com/features/', - }, - { - alt_description: 'Popular website content management system.', - alt_name: 'CMS: content management system', - categories: ['Website'], - colors: { - end: '135478', - start: '176086', - }, - description: `With 60 million users around the globe, WordPress is the industry standard for custom websites such as blogs, news sites, personal websites, and anything in-between. With a focus on best in class usability and flexibility, you can have a customized website up and running in minutes.`, - logo_url: 'wordpress.svg', - name: 'WordPress', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/wordpress/', - title: 'Deploy WordPress through the Linode Marketplace', - }, - ], - summary: - 'Flexible, open source content management system (CMS) for content-focused websites of any kind.', - website: 'https://wordpress.org/', - }, - { - alt_description: 'Web interface for managing Docker containers.', - alt_name: 'Docker GUI', - categories: ['Development'], - colors: { - end: 'c4c4c4', - start: '41b883', - }, - description: `Simplify Docker deployments and make containerization easy for anyone to use. Please note: Yacht is still in alpha and is not recommended for production use.`, - logo_url: 'yacht.svg', - name: 'Yacht', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/yacht/', - title: 'Deploy Yacht through the Linode Marketplace', - }, - ], - summary: 'Intuitive web interface for managing Docker containers.', - website: 'https://github.com/SelfhostedPro/Yacht/', - }, - { - alt_description: 'Enterprise infrastructure and IT resource montioring.', - alt_name: 'Infrastructure monitoring', - categories: ['Monitoring'], - colors: { - end: '252730', - start: 'd40000', - }, - description: `Monitor, track performance and maintain availability for network servers, devices, services and other IT resources– all in one tool.`, - logo_url: 'zabbix.svg', - name: 'Zabbix', - related_guides: [ - { - href: - 'https://www.linode.com/docs/products/tools/marketplace/guides/zabbix/', - title: 'Deploy Zabbix through the Linode Marketplace', - }, - ], - summary: 'Enterprise-class open source distributed monitoring solution.', - website: 'https://www.zabbix.com', - }, - { - ...oneClickAppFactory.build({ - name: 'E2E Test App', - }), - }, -]; +export const oneClickApps: OCA[] = Object.values(newOneClickApps); From 6269ac17abad4dcd2a8b2e47440561bbfffff541 Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Fri, 31 May 2024 10:52:46 -0400 Subject: [PATCH 07/10] make `oneClickAppsv2` the source of truth --- .../core/oneClickApps/one-click-apps.spec.ts | 9 +- .../src/containers/withMarketplaceApps.ts | 4 +- .../Linodes/LinodesCreate/utilities.test.ts | 13 +- .../Linodes/LinodesCreate/utilities.tsx | 11 +- .../features/StackScripts/stackScriptUtils.ts | 122 +----------------- 5 files changed, 16 insertions(+), 143 deletions(-) diff --git a/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts b/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts index 604f7550039..88b3caf6623 100644 --- a/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts +++ b/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts @@ -19,9 +19,8 @@ import { } from 'support/intercepts/feature-flags'; import { makeFeatureFlagData } from 'support/util/feature-flags'; import { mapStackScriptLabelToOCA } from 'src/features/OneClickApps/utils'; -import { baseApps } from 'src/features/StackScripts/stackScriptUtils'; import { stackScriptFactory } from 'src/factories/stackscripts'; -import { oneClickApps } from 'src/features/OneClickApps/oneClickApps'; +import { oneClickApps } from 'src/features/OneClickApps/oneClickAppsv2'; import type { StackScript } from '@linode/api-v4'; import type { OCA } from '@src/features/OneClickApps/types'; @@ -42,7 +41,7 @@ describe('OneClick Apps (OCA)', () => { const stackScripts: StackScript[] = xhr.response?.body.data ?? []; const trimmedApps: StackScript[] = filterOneClickApps({ - baseApps, + baseAppIds: Object.keys(oneClickApps).map(Number), newApps: {}, queryResults: stackScripts, }); @@ -65,7 +64,7 @@ describe('OneClick Apps (OCA)', () => { // This is only true for the apps defined in `oneClickApps.ts` expect( mapStackScriptLabelToOCA({ - oneClickApps, + oneClickApps: Object.values(oneClickApps), stackScriptLabel: decodedLabel, }) ).to.not.be.undefined; @@ -82,7 +81,7 @@ describe('OneClick Apps (OCA)', () => { stackScriptCandidate.should('exist').click(); const app: OCA | undefined = mapStackScriptLabelToOCA({ - oneClickApps, + oneClickApps: Object.values(oneClickApps), stackScriptLabel: candidateApp.label, }); diff --git a/packages/manager/src/containers/withMarketplaceApps.ts b/packages/manager/src/containers/withMarketplaceApps.ts index f5040df7241..17a0a56073e 100644 --- a/packages/manager/src/containers/withMarketplaceApps.ts +++ b/packages/manager/src/containers/withMarketplaceApps.ts @@ -2,7 +2,7 @@ import { StackScript } from '@linode/api-v4'; import React from 'react'; import { useLocation } from 'react-router-dom'; -import { baseApps } from 'src/features/StackScripts/stackScriptUtils'; +import { oneClickApps } from 'src/features/OneClickApps/oneClickAppsv2'; import { useFlags } from 'src/hooks/useFlags'; import { useMarketplaceAppsQuery } from 'src/queries/stackscripts'; import { getQueryParamFromQueryString } from 'src/utilities/queryParams'; @@ -34,7 +34,7 @@ export const withMarketplaceApps = ( const { data, error, isLoading } = useMarketplaceAppsQuery(enabled); const newApps = flags.oneClickApps || []; - const allowedApps = Object.keys({ ...baseApps, ...newApps }); + const allowedApps = Object.keys({ ...oneClickApps, ...newApps }); const filteredApps = (data ?? []).filter((script) => { return ( diff --git a/packages/manager/src/features/Linodes/LinodesCreate/utilities.test.ts b/packages/manager/src/features/Linodes/LinodesCreate/utilities.test.ts index 0dd7619430b..8a18835cce1 100644 --- a/packages/manager/src/features/Linodes/LinodesCreate/utilities.test.ts +++ b/packages/manager/src/features/Linodes/LinodesCreate/utilities.test.ts @@ -50,12 +50,7 @@ describe('trimOneClickFromLabel', () => { }); describe('filterOneClickApps', () => { - const baseApps = { - 1: 'Base App 1', - 2: 'Base App 2', - 3: 'Base App 3', - 4: 'Base App 4', - }; + const baseAppIds = [1, 2, 3, 4]; const newApps = { 5: 'New App 1', 6: 'New App 2', @@ -78,7 +73,7 @@ describe('filterOneClickApps', () => { it('filters OneClickApps and trims labels, excluding StackScripts with Helpers', () => { // feeding 4 Ids (1,2,3,4) getting 3 back const filteredOCAsWithHelpersLabel = filterOneClickApps({ - baseApps, + baseAppIds, newApps, queryResults: queryResultsWithHelpers, }); @@ -86,7 +81,7 @@ describe('filterOneClickApps', () => { // feeding 4 Ids (5,6,7,8) getting 4 back const filteredOCAsWithoutHelpersLabel = filterOneClickApps({ - baseApps, + baseAppIds, newApps, queryResults: queryResultsWithoutHelpers, }); @@ -97,7 +92,7 @@ describe('filterOneClickApps', () => { it('handles empty queryResults', () => { const emptyQueryResults: StackScript[] = []; const filteredOCAs = filterOneClickApps({ - baseApps, + baseAppIds, newApps, queryResults: emptyQueryResults, }); diff --git a/packages/manager/src/features/Linodes/LinodesCreate/utilities.tsx b/packages/manager/src/features/Linodes/LinodesCreate/utilities.tsx index 73b5d99dba4..68144a1aed7 100644 --- a/packages/manager/src/features/Linodes/LinodesCreate/utilities.tsx +++ b/packages/manager/src/features/Linodes/LinodesCreate/utilities.tsx @@ -51,7 +51,7 @@ export const trimOneClickFromLabel = (stackScript: StackScript) => { }; interface FilteredOCAs { - baseApps: Record; + baseAppIds: number[]; newApps: Record | never[]; queryResults: StackScript[]; } @@ -64,18 +64,17 @@ interface FilteredOCAs { * @returns an array of OCA StackScripts */ export const filterOneClickApps = ({ - baseApps, + baseAppIds, newApps, queryResults, }: FilteredOCAs) => { - const allowedApps = Object.keys({ ...baseApps, ...newApps }); + const allowedAppIds = [...baseAppIds, ...Object.keys(newApps).map(Number)]; + // Don't display One-Click Helpers to the user // Filter out any apps that we don't have info for const filteredApps: StackScript[] = queryResults.filter( (app: StackScript) => { - return ( - !app.label.match(/helpers/i) && allowedApps.includes(String(app.id)) - ); + return !app.label.match(/helpers/i) && allowedAppIds.includes(app.id); } ); return filteredApps.map((app) => trimOneClickFromLabel(app)); diff --git a/packages/manager/src/features/StackScripts/stackScriptUtils.ts b/packages/manager/src/features/StackScripts/stackScriptUtils.ts index f66cb6420c1..144645ead73 100644 --- a/packages/manager/src/features/StackScripts/stackScriptUtils.ts +++ b/packages/manager/src/features/StackScripts/stackScriptUtils.ts @@ -2,7 +2,7 @@ import { Grant } from '@linode/api-v4/lib/account'; import { StackScript, getStackScripts } from '@linode/api-v4/lib/stackscripts'; import { Filter, Params, ResourcePage } from '@linode/api-v4/lib/types'; -import { StackScriptsRequest } from './types'; +import type { StackScriptsRequest } from './types'; export type StackScriptCategory = 'account' | 'community'; @@ -13,126 +13,6 @@ export const emptyResult: ResourcePage = { results: 0, }; -/** - * We need a way to make sure that newly added SS that meet - * our filtering criteria don't automatically end up being - * shown to the user before we've updated Cloud to support them. - */ -export const baseApps = { - '401697': 'WordPress - Latest One-Click', - '401698': 'Drupal - Latest One-Click', - '401701': 'LAMP One-Click', - '401702': 'MERN One-Click', - '401706': 'WireGuard - Latest One-Click', - '401707': 'GitLab - Latest One-Click', - '401708': 'WooCommerce - Latest One-Click', - '401709': 'Minecraft - Latest One-Click', - '401719': 'OpenVPN - Latest One-Click', - '593835': 'Plesk One-Click', - '595742': 'cPanel One-Click', - '604068': 'Shadowsocks - Latest One-Click', - '606691': 'LEMP - Latest One-Click', - '607026': 'MySQL - Latest One-Click', - '607401': 'Jenkins - Latest One-Click', - '607433': 'Docker - Latest One-Click', - '607488': 'Redis One-Click', - '609018': 'phpMYAdmin', - '609048': 'Ruby on Rails One-Click', - '609175': 'Django One-Click', - '609392': 'Flask One-Click', - '611376': 'PostgreSQL One-Click', - '611895': 'MEAN One-Click', - '632758': 'Nextcloud', - '662118': 'Azuracast', - '662119': 'Plex', - '662121': 'Jitsi', - '688890': 'RabbitMQ', - '688891': 'Discourse', - '688902': 'Webuzo', - '688903': 'Code Server', - '688911': 'Gitea', - '688912': 'Kepler Builder One-Click', - '688914': 'Guacamole', - '691620': 'FileCloud', - '691621': 'Cloudron', - '691622': 'OpenLiteSpeed', - '692092': 'Secure Your Server', - '741206': 'CyberPanel', - '741207': 'Yacht', - '741208': 'Zabbix', - '774829': 'ServerWand', - '804143': 'Peppermint', - '804144': 'Ant Media Server', - '804172': 'Owncast', - '869127': 'Moodle', - '869129': 'aaPanel', - '869153': 'Splunk', - '869155': 'Chevereto', - '869156': 'NirvaShare', - '869158': 'ClusterControl', - '869623': 'JetBackup', - '912262': 'Harbor', - '912264': 'Rocket.Chat', - '913276': 'Wazuh', - '913277': 'BeEF', - '923029': 'OpenLiteSpeed Django', - '923030': 'OpenLiteSpeed Rails', - '923031': 'OpenLiteSpeed NodeJS', - '923032': 'LiteSpeed cPanel', - '923033': 'Akaunting', - '923036': 'Restyaboard', - '923037': 'WarpSpeed', - '925530': 'UTunnel VPN', - '925722': 'Pritunl', - '954759': 'VictoriaMetrics', - '970522': 'Pi-hole', - '970523': 'Uptime Kuma', - '970559': 'Grav', - '970561': 'NodeJS', - '971042': 'Saltcorn', - '971043': 'Odoo', - '971045': 'Focalboard', - '985364': 'Prometheus & Grafana', - '985372': 'Joomla', - '985374': 'Ant Media Enterprise Edition', - '985380': 'Joplin', - '1008123': 'Liveswitch', - '1008125': 'Easypanel', - '1017300': 'Kali Linux', - '1037036': 'Budibase', - '1037037': 'HashiCorp Nomad', - '1037038': 'HashiCorp Vault', - '1051714': 'Microweber', - '1068726': 'PostgreSQL Cluster', - '1088136': 'Galera Cluster', - '1096122': 'Mastodon', - '1102900': 'Apache Airflow', - '1102902': 'HaltDOS Community WAF', - '1102904': 'Superinsight', - '1102905': 'Gopaddle', - '1102906': 'Passky', - '1102907': 'ONLYOFFICE Docs', - '1132204': 'Redis Sentinel Cluster', - '1160816': 'ownCloud', - '1160820': 'Appwrite', - '1177225': 'Seatable', - '1177605': 'Illa Builder', - '1226544': 'HashiCorp Nomad Cluster', - '1226545': 'HashiCorp Nomad Clients Cluster', - '1243759': 'MainConcept FFmpeg Plugins Demo', - '1243760': 'MainConcept Live Encoder Demo', - '1243762': 'MainConcept P2 AVC ULTRA Transcoder Demo', - '1243763': 'MainConcept XAVC Transcoder Demo', - '1243764': 'MainConcept XDCAM Transcoder Demo', - '1243780': 'SimpleX Chat', - '1298017': 'JupyterLab', - '1308539': 'NATS Single Node', - '1329430': 'Passbolt', - '1329462': 'LinuxGSM', - '1350733': 'Jitsi Cluster', - '1350783': 'GlusterFS Cluster', -}; - const oneClickFilter = [ { '+and': [ From 7cb9e9ff00945a3abab65374a55e3d55aa7902b0 Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Fri, 31 May 2024 10:58:01 -0400 Subject: [PATCH 08/10] use client side icon url --- .../Tabs/StackScripts/UserDefinedFields/UserDefinedFields.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.tsx index 0e923d2b8d9..8e3df1374bb 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Tabs/StackScripts/UserDefinedFields/UserDefinedFields.tsx @@ -70,7 +70,7 @@ export const UserDefinedFields = ({ onOpenDetailsDrawer }: Props) => { {`${stackscript.label} {decode(stackscript.label.replace('One-Click', ''))} Setup From 85ea3bcc9bb985ec7833b8c962f95af4a761bebd Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Fri, 31 May 2024 11:39:18 -0400 Subject: [PATCH 09/10] fix scrolling errors into view --- .../features/Linodes/LinodeCreatev2/index.tsx | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/index.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/index.tsx index 5ea6cd3f874..341bebcfc9b 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/index.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/index.tsx @@ -1,4 +1,4 @@ -import React, { useRef } from 'react'; +import React, { useEffect, useRef } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { useHistory } from 'react-router-dom'; @@ -14,7 +14,6 @@ import { useCloneLinodeMutation, useCreateLinodeMutation, } from 'src/queries/linodes/linodes'; -import { scrollErrorIntoViewV2 } from 'src/utilities/scrollErrorIntoViewV2'; import { Access } from './Access'; import { Actions } from './Actions'; @@ -46,6 +45,8 @@ import { VLAN } from './VLAN'; import { VPC } from './VPC/VPC'; import type { SubmitHandler } from 'react-hook-form'; +import { isEmpty } from '@linode/api-v4'; +import { scrollErrorIntoView } from 'src/utilities/scrollErrorIntoView'; export const LinodeCreatev2 = () => { const { params, setParams } = useLinodeCreateQueryParams(); @@ -97,6 +98,18 @@ export const LinodeCreatev2 = () => { } }; + const previousSubmitCount = useRef(0); + + useEffect(() => { + if ( + !isEmpty(form.formState.errors) && + form.formState.submitCount > previousSubmitCount.current + ) { + scrollErrorIntoView(undefined, { behavior: 'smooth' }); + } + previousSubmitCount.current = form.formState.submitCount; + }, [form.formState]); + return ( @@ -105,12 +118,7 @@ export const LinodeCreatev2 = () => { docsLink="https://www.linode.com/docs/guides/platform/get-started/" title="Create" /> -
- scrollErrorIntoViewV2(formRef) - )} - ref={formRef} - > + From 90b76243ce9fca16280536991c101811b9d66c5b Mon Sep 17 00:00:00 2001 From: Banks Nussman Date: Mon, 3 Jun 2024 12:06:37 -0400 Subject: [PATCH 10/10] update which apps are new --- .../manager/src/features/Linodes/LinodeCreatev2/index.tsx | 4 ++-- packages/manager/src/features/OneClickApps/oneClickAppsv2.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/index.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/index.tsx index 341bebcfc9b..49ba44f093f 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/index.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/index.tsx @@ -1,3 +1,4 @@ +import { isEmpty } from '@linode/api-v4'; import React, { useEffect, useRef } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { useHistory } from 'react-router-dom'; @@ -14,6 +15,7 @@ import { useCloneLinodeMutation, useCreateLinodeMutation, } from 'src/queries/linodes/linodes'; +import { scrollErrorIntoView } from 'src/utilities/scrollErrorIntoView'; import { Access } from './Access'; import { Actions } from './Actions'; @@ -45,8 +47,6 @@ import { VLAN } from './VLAN'; import { VPC } from './VPC/VPC'; import type { SubmitHandler } from 'react-hook-form'; -import { isEmpty } from '@linode/api-v4'; -import { scrollErrorIntoView } from 'src/utilities/scrollErrorIntoView'; export const LinodeCreatev2 = () => { const { params, setParams } = useLinodeCreateQueryParams(); diff --git a/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts b/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts index c2816a609c8..e447e0246f6 100644 --- a/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts +++ b/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts @@ -2422,7 +2422,6 @@ export const oneClickApps: Record = { start: '1d76ba', }, description: `Secure, stable, and free alternative to popular video conferencing services. This app deploys four networked Jitsi nodes.`, - isNew: true, logo_url: 'jitsi.svg', name: 'Jitsi Cluster', related_guides: [ @@ -2437,7 +2436,6 @@ export const oneClickApps: Record = { }, 1350783: { alt_description: 'Open source, highly available, shared filesystem.', - isNew: true, alt_name: 'GlusterFS', categories: ['Development'], colors: { @@ -2468,6 +2466,7 @@ export const oneClickApps: Record = { start: '333333', }, description: `Couchbase Enterprise Server is a high-performance NoSQL database, built for scale. Couchbase Server is designed with memory-first architecture, built-in cache and workload isolation.`, + isNew: true, logo_url: 'couchbase.svg', name: 'Couchbase Cluster', related_guides: [ @@ -2490,6 +2489,7 @@ export const oneClickApps: Record = { start: '00C7D4', }, description: `Apache Kafka supports a wide range of applications from log aggregation to real-time analytics. Kafka provides a foundation for building data pipelines, event-driven architectures, or stream processing applications.`, + isNew: true, logo_url: 'apachekafka.svg', name: 'Apache Kafka Cluster', related_guides: [