🎨 Rename "services" to "apps" in entire project

This commit is contained in:
Manuel Ruwe
2022-12-18 22:27:01 +01:00
parent 1e0a90f2ac
commit 661c05bc50
69 changed files with 661 additions and 495 deletions

View File

@@ -2,18 +2,18 @@ import { SelectItem } from '@mantine/core';
import { closeModal, ContextModalProps } from '@mantine/modals';
import { useConfigContext } from '../../../../config/provider';
import { useConfigStore } from '../../../../config/store';
import { ServiceType } from '../../../../types/service';
import { AppType } from '../../../../types/app';
import { ChangePositionModal } from './ChangePositionModal';
type ChangeServicePositionModalInnerProps = {
service: ServiceType;
type ChangeAppPositionModalInnerProps = {
app: AppType;
};
export const ChangeServicePositionModal = ({
export const ChangeAppPositionModal = ({
id,
context,
innerProps,
}: ContextModalProps<ChangeServicePositionModalInnerProps>) => {
}: ContextModalProps<ChangeAppPositionModalInnerProps>) => {
const { name: configName } = useConfigContext();
const updateConfig = useConfigStore((x) => x.updateConfig);
@@ -24,9 +24,9 @@ export const ChangeServicePositionModal = ({
updateConfig(configName, (previousConfig) => ({
...previousConfig,
services: [
...previousConfig.services.filter((x) => x.id !== innerProps.service.id),
{ ...innerProps.service, shape: { location: { x, y }, size: { width, height } } },
apps: [
...previousConfig.apps.filter((x) => x.id !== innerProps.app.id),
{ ...innerProps.app, shape: { location: { x, y }, size: { width, height } } },
],
}));
context.closeModal(id);
@@ -45,10 +45,10 @@ export const ChangeServicePositionModal = ({
onCancel={handleCancel}
widthData={widthData}
heightData={heightData}
initialX={innerProps.service.shape.location.x}
initialY={innerProps.service.shape.location.y}
initialWidth={innerProps.service.shape.size.width}
initialHeight={innerProps.service.shape.size.height}
initialX={innerProps.app.shape.location.x}
initialY={innerProps.app.shape.location.y}
initialWidth={innerProps.app.shape.size.width}
initialHeight={innerProps.app.shape.size.height}
/>
);
};

View File

@@ -13,32 +13,32 @@ import { useTranslation } from 'next-i18next';
import { useState } from 'react';
import { useConfigContext } from '../../../../config/provider';
import { useConfigStore } from '../../../../config/store';
import { ServiceType } from '../../../../types/service';
import { AppType } from '../../../../types/app';
import { AppearanceTab } from './Tabs/AppereanceTab/AppereanceTab';
import { BehaviourTab } from './Tabs/BehaviourTab/BehaviourTab';
import { GeneralTab } from './Tabs/GeneralTab/GeneralTab';
import { IntegrationTab } from './Tabs/IntegrationTab/IntegrationTab';
import { NetworkTab } from './Tabs/NetworkTab/NetworkTab';
import { DebouncedServiceIcon } from './Tabs/Shared/DebouncedServiceIcon';
import { EditServiceModalTab } from './Tabs/type';
import { DebouncedAppIcon } from './Tabs/Shared/DebouncedAppIcon';
import { EditAppModalTab } from './Tabs/type';
const serviceUrlRegex =
const appUrlRegex =
'(https?://(?:www.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9].[^\\s]{2,}|www.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9].[^\\s]{2,}|https?://(?:www.|(?!www))[a-zA-Z0-9]+.[^\\s]{2,}|www.[a-zA-Z0-9]+.[^\\s]{2,})';
export const EditServiceModal = ({
export const EditAppModal = ({
context,
id,
innerProps,
}: ContextModalProps<{ service: ServiceType; allowServiceNamePropagation: boolean }>) => {
}: ContextModalProps<{ app: AppType; allowAppNamePropagation: boolean }>) => {
const { t } = useTranslation();
const { name: configName, config } = useConfigContext();
const updateConfig = useConfigStore((store) => store.updateConfig);
const [allowServiceNamePropagation, setAllowServiceNamePropagation] = useState<boolean>(
innerProps.allowServiceNamePropagation
const [allowAppNamePropagation, setAllowAppNamePropagation] = useState<boolean>(
innerProps.allowAppNamePropagation
);
const form = useForm<ServiceType>({
initialValues: innerProps.service,
const form = useForm<AppType>({
initialValues: innerProps.app,
validate: {
name: (name) => (!name ? 'Name is required' : null),
url: (url) => {
@@ -46,7 +46,7 @@ export const EditServiceModal = ({
return 'Url is required';
}
if (!url.match(serviceUrlRegex)) {
if (!url.match(appUrlRegex)) {
return 'Value is not a valid url';
}
@@ -67,7 +67,7 @@ export const EditServiceModal = ({
return null;
}
if (!url.match(serviceUrlRegex)) {
if (!url.match(appUrlRegex)) {
return 'Uri override is not a valid uri';
}
@@ -78,21 +78,21 @@ export const EditServiceModal = ({
validateInputOnChange: true,
});
const onSubmit = (values: ServiceType) => {
const onSubmit = (values: AppType) => {
if (!configName) {
return;
}
updateConfig(configName, (previousConfig) => ({
...previousConfig,
services: [...previousConfig.services.filter((x) => x.id !== form.values.id), form.values],
apps: [...previousConfig.apps.filter((x) => x.id !== form.values.id), form.values],
}));
// also close the parent modal
context.closeAll();
};
const [activeTab, setActiveTab] = useState<EditServiceModalTab>('general');
const [activeTab, setActiveTab] = useState<EditAppModalTab>('general');
const closeModal = () => {
context.closeModal(id);
@@ -125,17 +125,17 @@ export const EditServiceModal = ({
</Alert>
))}
<Stack spacing={0} align="center" my="lg">
<DebouncedServiceIcon form={form} width={120} height={120} />
<DebouncedAppIcon form={form} width={120} height={120} />
<Text align="center" weight="bold" size="lg" mt="md">
{form.values.name ?? 'New Service'}
{form.values.name ?? 'New App'}
</Text>
</Stack>
<form onSubmit={form.onSubmit(onSubmit)}>
<Tabs
value={activeTab}
onTabChange={(tab) => setActiveTab(tab as EditServiceModalTab)}
onTabChange={(tab) => setActiveTab(tab as EditAppModalTab)}
defaultValue="general"
>
<Tabs.List grow>
@@ -181,8 +181,8 @@ export const EditServiceModal = ({
<NetworkTab form={form} />
<AppearanceTab
form={form}
disallowServiceNameProgagation={() => setAllowServiceNamePropagation(false)}
allowServiceNamePropagation={allowServiceNamePropagation}
disallowAppNameProgagation={() => setAllowAppNamePropagation(false)}
allowAppNamePropagation={allowAppNamePropagation}
/>
<IntegrationTab form={form} />
</Tabs>
@@ -199,9 +199,3 @@ export const EditServiceModal = ({
</>
);
};
const useStyles = createStyles(() => ({
serviceImage: {
objectFit: 'contain',
},
}));

View File

@@ -1,20 +1,20 @@
import { createStyles, Flex, Tabs, TextInput } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form';
import { useTranslation } from 'next-i18next';
import { ServiceType } from '../../../../../../types/service';
import { DebouncedServiceIcon } from '../Shared/DebouncedServiceIcon';
import { AppType } from '../../../../../../types/app';
import { DebouncedAppIcon } from '../Shared/DebouncedAppIcon';
import { IconSelector } from './IconSelector/IconSelector';
interface AppearanceTabProps {
form: UseFormReturnType<ServiceType, (values: ServiceType) => ServiceType>;
disallowServiceNameProgagation: () => void;
allowServiceNamePropagation: boolean;
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
disallowAppNameProgagation: () => void;
allowAppNamePropagation: boolean;
}
export const AppearanceTab = ({
form,
disallowServiceNameProgagation,
allowServiceNamePropagation,
disallowAppNameProgagation,
allowAppNamePropagation,
}: AppearanceTabProps) => {
const { t } = useTranslation('');
const { classes } = useStyles();
@@ -25,9 +25,9 @@ export const AppearanceTab = ({
<TextInput
defaultValue={form.values.appearance.iconUrl}
className={classes.textInput}
icon={<DebouncedServiceIcon form={form} width={20} height={20} />}
label="Service Icon"
description="Logo of your service displayed in your dashboard. Must return a body content containg an image"
icon={<DebouncedAppIcon form={form} width={20} height={20} />}
label="App Icon"
description="Logo of your app displayed in your dashboard. Must return a body content containg an image"
variant="default"
withAsterisk
required
@@ -40,9 +40,9 @@ export const AppearanceTab = ({
iconUrl: item.url,
},
});
disallowServiceNameProgagation();
disallowAppNameProgagation();
}}
allowServiceNamePropagation={allowServiceNamePropagation}
allowAppNamePropagation={allowAppNamePropagation}
form={form}
/>
</Flex>

View File

@@ -21,17 +21,17 @@ import { ICON_PICKER_SLICE_LIMIT } from '../../../../../../../../data/constants'
import { useRepositoryIconsQuery } from '../../../../../../../tools/hooks/useRepositoryIconsQuery';
import { IconSelectorItem } from '../../../../../../../types/iconSelector/iconSelectorItem';
import { WalkxcodeRepositoryIcon } from '../../../../../../../types/iconSelector/repositories/walkxcodeIconRepository';
import { ServiceType } from '../../../../../../../types/service';
import { AppType } from '../../../../../../../types/app';
interface IconSelectorProps {
form: UseFormReturnType<ServiceType, (values: ServiceType) => ServiceType>;
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
onChange: (icon: IconSelectorItem) => void;
allowServiceNamePropagation: boolean;
allowAppNamePropagation: boolean;
}
export const IconSelector = ({
onChange,
allowServiceNamePropagation,
allowAppNamePropagation,
form,
}: IconSelectorProps) => {
const { data, isLoading } = useRepositoryIconsQuery<WalkxcodeRepositoryIcon>({
@@ -48,7 +48,7 @@ export const IconSelector = ({
const [debouncedValue] = useDebouncedValue(form.values.name, 500);
useEffect(() => {
if (allowServiceNamePropagation !== true) {
if (allowAppNamePropagation !== true) {
return;
}

View File

@@ -2,10 +2,10 @@ import { Tabs, TextInput, Switch, Text } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form';
import { IconClick } from '@tabler/icons';
import { useTranslation } from 'next-i18next';
import { ServiceType } from '../../../../../../types/service';
import { AppType } from '../../../../../../types/app';
interface BehaviourTabProps {
form: UseFormReturnType<ServiceType, (values: ServiceType) => ServiceType>;
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
}
export const BehaviourTab = ({ form }: BehaviourTabProps) => {
@@ -15,8 +15,8 @@ export const BehaviourTab = ({ form }: BehaviourTabProps) => {
<TextInput
icon={<IconClick size={16} />}
label="On click url"
description="Overrides the service URL when clicking on the service"
placeholder="URL that should be opened instead when clicking on the service"
description="Overrides the app URL when clicking on the app"
placeholder="URL that should be opened instead when clicking on the app"
variant="default"
mb="md"
{...form.getInputProps('behaviour.onClickUrl')}

View File

@@ -2,12 +2,12 @@ import { Tabs, Text, TextInput } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form';
import { IconCursorText, IconLink } from '@tabler/icons';
import { useTranslation } from 'next-i18next';
import { ServiceType } from '../../../../../../types/service';
import { EditServiceModalTab } from '../type';
import { AppType } from '../../../../../../types/app';
import { EditAppModalTab } from '../type';
interface GeneralTabProps {
form: UseFormReturnType<ServiceType, (values: ServiceType) => ServiceType>;
openTab: (tab: EditServiceModalTab) => void;
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
openTab: (tab: EditAppModalTab) => void;
}
export const GeneralTab = ({ form, openTab }: GeneralTabProps) => {
@@ -16,9 +16,9 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => {
<Tabs.Panel value="general" pt="lg">
<TextInput
icon={<IconCursorText size={16} />}
label="Service name"
description="Used for displaying the service on the dashboard"
placeholder="My example service"
label="App name"
description="Used for displaying the app on the dashboard"
placeholder="My example app"
variant="default"
mb="md"
withAsterisk
@@ -26,10 +26,10 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => {
/>
<TextInput
icon={<IconLink size={16} />}
label="Service url"
label="App url"
description={
<Text>
URL that will be opened when clicking on the service. Can be overwritten using
URL that will be opened when clicking on the app. Can be overwritten using
<Text
onClick={() => openTab('behaviour')}
variant="link"

View File

@@ -7,13 +7,13 @@ import {
IntegrationField,
integrationFieldDefinitions,
integrationFieldProperties,
ServiceIntegrationPropertyType,
ServiceIntegrationType,
ServiceType,
} from '../../../../../../../../types/service';
AppIntegrationPropertyType,
AppIntegrationType,
AppType,
} from '../../../../../../../../types/app';
interface IntegrationSelectorProps {
form: UseFormReturnType<ServiceType, (item: ServiceType) => ServiceType>;
form: UseFormReturnType<AppType, (item: AppType) => AppType>;
}
export const IntegrationSelector = ({ form }: IntegrationSelectorProps) => {
@@ -53,9 +53,9 @@ export const IntegrationSelector = ({ form }: IntegrationSelectorProps) => {
},
].filter((x) => Object.keys(integrationFieldProperties).includes(x.value));
const getNewProperties = (value: string | null): ServiceIntegrationPropertyType[] => {
const getNewProperties = (value: string | null): AppIntegrationPropertyType[] => {
if (!value) return [];
const integrationType = value as ServiceIntegrationType['type'];
const integrationType = value as AppIntegrationType['type'];
if (integrationType === null) {
return [];
}
@@ -77,7 +77,7 @@ export const IntegrationSelector = ({ form }: IntegrationSelectorProps) => {
return (
<Select
label="Integration configuration"
description="Treats this service as the selected integration and provides you with per-service configuration"
description="Treats this app as the selected integration and provides you with per-app configuration"
placeholder="Select your desired configuration"
itemComponent={SelectItemComponent}
data={data}

View File

@@ -5,13 +5,13 @@ import {
IntegrationField,
integrationFieldDefinitions,
integrationFieldProperties,
ServiceIntegrationPropertyType,
ServiceType,
} from '../../../../../../../../types/service';
AppIntegrationPropertyType,
AppType,
} from '../../../../../../../../types/app';
import { GenericSecretInput } from '../InputElements/GenericSecretInput';
interface IntegrationOptionsRendererProps {
form: UseFormReturnType<ServiceType, (values: ServiceType) => ServiceType>;
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
}
export const IntegrationOptionsRenderer = ({ form }: IntegrationOptionsRendererProps) => {
@@ -34,7 +34,7 @@ export const IntegrationOptionsRenderer = ({ form }: IntegrationOptionsRendererP
const type = Object.entries(integrationFieldDefinitions).find(
([k, v]) => k === property
)![1].type;
const newProperty: ServiceIntegrationPropertyType = {
const newProperty: AppIntegrationPropertyType = {
type,
field: property as IntegrationField,
isDefined: false,

View File

@@ -2,12 +2,12 @@ import { Alert, Divider, Tabs, Text } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form';
import { IconAlertTriangle } from '@tabler/icons';
import { useTranslation } from 'next-i18next';
import { ServiceType } from '../../../../../../types/service';
import { AppType } from '../../../../../../types/app';
import { IntegrationSelector } from './Components/InputElements/IntegrationSelector';
import { IntegrationOptionsRenderer } from './Components/IntegrationOptionsRenderer/IntegrationOptionsRenderer';
interface IntegrationTabProps {
form: UseFormReturnType<ServiceType, (values: ServiceType) => ServiceType>;
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
}
export const IntegrationTab = ({ form }: IntegrationTabProps) => {

View File

@@ -2,10 +2,10 @@ import { Tabs, Switch, MultiSelect } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form';
import { useTranslation } from 'next-i18next';
import { StatusCodes } from '../../../../../../tools/acceptableStatusCodes';
import { ServiceType } from '../../../../../../types/service';
import { AppType } from '../../../../../../types/app';
interface NetworkTabProps {
form: UseFormReturnType<ServiceType, (values: ServiceType) => ServiceType>;
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
}
export const NetworkTab = ({ form }: NetworkTabProps) => {
@@ -14,7 +14,7 @@ export const NetworkTab = ({ form }: NetworkTabProps) => {
<Tabs.Panel value="network" pt="lg">
<Switch
label="Enable status checker"
description="Sends a simple HTTP / HTTPS request to check if your service is online"
description="Sends a simple HTTP / HTTPS request to check if your app is online"
mb="md"
defaultChecked={form.values.network.enabledStatusChecker}
{...form.getInputProps('network.enabledStatusChecker')}
@@ -23,7 +23,7 @@ export const NetworkTab = ({ form }: NetworkTabProps) => {
<MultiSelect
required
label="HTTP status codes"
description="Determines what response codes are allowed for this service to be 'Online'"
description="Determines what response codes are allowed for this app to be 'Online'"
data={StatusCodes}
clearable
searchable

View File

@@ -4,21 +4,21 @@ import Image from 'next/image';
import { createStyles, Loader } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form';
import { useDebouncedValue } from '@mantine/hooks';
import { ServiceType } from '../../../../../../types/service';
import { AppType } from '../../../../../../types/app';
interface DebouncedServiceIconProps {
interface DebouncedAppIconProps {
width: number;
height: number;
form: UseFormReturnType<ServiceType, (values: ServiceType) => ServiceType>;
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
debouncedWaitPeriod?: number;
}
export const DebouncedServiceIcon = ({
export const DebouncedAppIcon = ({
form,
width,
height,
debouncedWaitPeriod = 1000,
}: DebouncedServiceIconProps) => {
}: DebouncedAppIconProps) => {
const { classes } = useStyles();
const [debouncedIconImageUrl] = useDebouncedValue(
form.values.appearance.iconUrl,

View File

@@ -1,4 +1,4 @@
export type EditServiceModalTab =
export type EditAppModalTab =
| 'general'
| 'behaviour'
| 'network'

View File

@@ -23,7 +23,7 @@ export const AvailableIntegrationElements = ({
<SelectorBackArrow onClickBack={onClickBack} />
<Text mb="md" color="dimmed">
Integrations interact with your services, to provide you with more control over your
Integrations interact with your apps, to provide you with more control over your
applications. They usually require a few configurations before use.
</Text>

View File

@@ -4,7 +4,7 @@ import { useTranslation } from 'next-i18next';
import { ReactNode } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { openContextModalGeneric } from '../../../../../../tools/mantineModalManagerExtensions';
import { ServiceType } from '../../../../../../types/service';
import { AppType } from '../../../../../../types/app';
import { useStyles } from '../Shared/styles';
interface AvailableElementTypesProps {
@@ -24,16 +24,16 @@ export const AvailableElementTypes = ({
<Space h="lg" />
<Group spacing="md" grow>
<ElementItem
name="Service"
name="Apps"
icon={<IconBox size={40} strokeWidth={1.3} />}
onClick={() => {
openContextModalGeneric<{ service: ServiceType; allowServiceNamePropagation: boolean }>(
openContextModalGeneric<{ app: AppType; allowAppNamePropagation: boolean }>(
{
modal: 'editService',
modal: 'editApp',
innerProps: {
service: {
app: {
id: uuidv4(),
name: 'Your service',
name: 'Your app',
url: 'https://homarr.dev',
appearance: {
iconUrl: '/imgs/logo/logo.png',
@@ -67,7 +67,7 @@ export const AvailableElementTypes = ({
properties: [],
},
},
allowServiceNamePropagation: true,
allowAppNamePropagation: true,
},
size: 'xl',
}

View File

@@ -16,7 +16,7 @@ export const AvailableStaticTypes = ({ onClickBack }: AvailableStaticTypesProps)
<Text mb="md" color="dimmed">
Static elements provide you additional control over your dashboard. They are static, because
they don&apos;t integrate with any services and their content never changes.
they don&apos;t integrate with any apps and their content never changes.
</Text>
<Grid>