Skip to content

Commit

Permalink
🚀 v0.7.1 ! Bug fixes and QOL improvements
Browse files Browse the repository at this point in the history
### Features
* ✨ Changing deluge/qbittorent to use href instead of origin by @VinnyVynce in #178
* ✨ Transmission Integration by @ajnart in #181
* ✨ Add different URL for API calls by @ajnart in #180
* ✨Password / Login Page by @ajnart in #179
* ✨ Ability to toggle categories by @ajnart in #177
* ✨ Add settings to change title and icons by @Aimsucks in #184
* ✨ Color, shade, app opacity, and background customizations by @Aimsucks in #188
* ✨ Calendar indication about date and w-e with secondary color by @Darkham42 in #193
* ✨ More Information in Torrents Module by @LarveyOfficial in #195
* ✨ Could position widgets at left by @Darkham42 in #197
* ✨ Configure calendar widget to show Sunday first by @ajnart in #224
* ✨Service Addition Overhaul by @LarveyOfficial in #229
* ✨ Slidable service span in customizations  by @Aimsucks in #222
### Tweaks
🔧 Make credentials non-required for torrents by @ajnart in #223
### Bug fixes
* 🐛Fix completed torrents progress color by @LarveyOfficial in #227
* 🐛Tiles could be moved accidentally on mobiles by @ajnart in #226
* 🐛 Cannot open "New Tab URL" on mobile by @ajnart in #225
* 🐛 Fix Calendar Item Duplication by @LarveyOfficial in #249
* 🐛Fix URL for Radarr and other services by @LarveyOfficial in #250
* 🐛 Fix Calendar not loading content when a service fails by @LarveyOfficial in #230
* 🐛 Calendar current day for light theme by @Darkham42 in #194
* 🐛 Fix for timezone issues by @LarveyOfficial in #186
* 🐛 Fix Sonarr Incorrect Dates by @LarveyOfficial in #189
* 🐛 Fix for origin URL not containing path in API request URL by @Aimsucks in #221
  • Loading branch information
ajnart authored Jun 20, 2022
2 parents 778988d + 91a249d commit 7dc205f
Show file tree
Hide file tree
Showing 17 changed files with 333 additions and 160 deletions.
2 changes: 1 addition & 1 deletion data/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export const REPO_URL = 'ajnart/homarr';
export const CURRENT_VERSION = 'v0.7.0';
export const CURRENT_VERSION = 'v0.7.1';
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "homarr",
"version": "0.7.0",
"version": "0.7.1",
"description": "Homarr - A homepage for your server.",
"repository": {
"type": "git",
Expand Down
298 changes: 176 additions & 122 deletions src/components/AppShelf/AddAppShelfItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ import {
Title,
Anchor,
Text,
Tabs,
MultiSelect,
ScrollArea,
Switch,
} from '@mantine/core';
import { useForm } from '@mantine/form';
import { useEffect, useState } from 'react';
import { IconApps as Apps } from '@tabler/icons';
import { v4 as uuidv4 } from 'uuid';
import { useDebouncedValue } from '@mantine/hooks';
import { useConfig } from '../../tools/state';
import { ServiceTypeList } from '../../tools/types';
import { ServiceTypeList, StatusCodes } from '../../tools/types';

export function AddItemShelfButton(props: any) {
const [opened, setOpened] = useState(false);
Expand Down Expand Up @@ -113,6 +117,8 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } &
username: props.username ?? (undefined as unknown as string),
password: props.password ?? (undefined as unknown as string),
openedUrl: props.openedUrl ?? (undefined as unknown as string),
status: props.status ?? ['200'],
newTab: props.newTab ?? true,
},
validate: {
apiKey: () => null,
Expand All @@ -133,6 +139,12 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } &
}
return null;
},
status: (value: string[]) => {
if (!value.length) {
return 'Please select a status code';
}
return null;
},
},
});

Expand Down Expand Up @@ -167,6 +179,12 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } &
</Center>
<form
onSubmit={form.onSubmit(() => {
if (JSON.stringify(form.values.status) === JSON.stringify(['200'])) {
form.values.status = undefined;
}
if (form.values.newTab === true) {
form.values.newTab = undefined;
}
// If service already exists, update it.
if (config.services && config.services.find((s) => s.id === form.values.id)) {
setConfig({
Expand All @@ -191,131 +209,167 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } &
form.reset();
})}
>
<Group direction="column" grow>
<TextInput
required
label="Service name"
placeholder="Plex"
{...form.getInputProps('name')}
/>
<Tabs grow>
<Tabs.Tab label="Options">
<ScrollArea style={{ height: 500 }} scrollbarSize={4}>
<Group direction="column" grow>
<TextInput
required
label="Service name"
placeholder="Plex"
{...form.getInputProps('name')}
/>

<TextInput
required
label="Icon URL"
placeholder="/favicon.svg"
{...form.getInputProps('icon')}
/>
<TextInput
required
label="Service URL"
placeholder="http://localhost:7575"
{...form.getInputProps('url')}
/>
<TextInput
label="New tab URL"
placeholder="http://sonarr.example.com"
{...form.getInputProps('openedUrl')}
/>
<Select
label="Service type"
defaultValue="Other"
placeholder="Pick one"
required
searchable
data={ServiceTypeList}
{...form.getInputProps('type')}
/>
<Select
label="Category"
data={categoryList}
placeholder="Select a category or create a new one"
nothingFound="Nothing found"
searchable
clearable
creatable
onClick={(e) => {
e.preventDefault();
}}
getCreateLabel={(query) => `+ Create "${query}"`}
onCreate={(query) => {}}
{...form.getInputProps('category')}
/>
<LoadingOverlay visible={isLoading} />
{(form.values.type === 'Sonarr' ||
form.values.type === 'Radarr' ||
form.values.type === 'Lidarr' ||
form.values.type === 'Readarr') && (
<>
<TextInput
required
label="API key"
placeholder="Your API key"
value={form.values.apiKey}
onChange={(event) => {
form.setFieldValue('apiKey', event.currentTarget.value);
}}
error={form.errors.apiKey && 'Invalid API key'}
/>
<Text
style={{
alignSelf: 'center',
fontSize: '0.75rem',
textAlign: 'center',
color: 'gray',
}}
>
Tip: Get your API key{' '}
<Anchor
target="_blank"
weight="bold"
style={{ fontStyle: 'inherit', fontSize: 'inherit' }}
href={`${hostname}/settings/general`}
>
here.
</Anchor>
</Text>
</>
)}
{form.values.type === 'qBittorrent' && (
<>
<TextInput
required
label="Username"
placeholder="admin"
value={form.values.username}
onChange={(event) => {
form.setFieldValue('username', event.currentTarget.value);
}}
error={form.errors.username && 'Invalid username'}
/>
<TextInput
<TextInput
required
label="Icon URL"
placeholder="/favicon.svg"
{...form.getInputProps('icon')}
/>
<TextInput
required
label="Service URL"
placeholder="http://localhost:7575"
{...form.getInputProps('url')}
/>
<TextInput
label="On Click URL"
placeholder="http://sonarr.example.com"
{...form.getInputProps('openedUrl')}
/>
<Select
label="Service type"
defaultValue="Other"
placeholder="Pick one"
required
searchable
data={ServiceTypeList}
{...form.getInputProps('type')}
/>
<Select
label="Category"
data={categoryList}
placeholder="Select a category or create a new one"
nothingFound="Nothing found"
searchable
clearable
creatable
onClick={(e) => {
e.preventDefault();
}}
getCreateLabel={(query) => `+ Create "${query}"`}
onCreate={(query) => {}}
{...form.getInputProps('category')}
/>
<LoadingOverlay visible={isLoading} />
{(form.values.type === 'Sonarr' ||
form.values.type === 'Radarr' ||
form.values.type === 'Lidarr' ||
form.values.type === 'Readarr') && (
<>
<TextInput
required
label="API key"
placeholder="Your API key"
value={form.values.apiKey}
onChange={(event) => {
form.setFieldValue('apiKey', event.currentTarget.value);
}}
error={form.errors.apiKey && 'Invalid API key'}
/>
<Text
style={{
alignSelf: 'center',
fontSize: '0.75rem',
textAlign: 'center',
color: 'gray',
}}
>
Tip: Get your API key{' '}
<Anchor
target="_blank"
weight="bold"
style={{ fontStyle: 'inherit', fontSize: 'inherit' }}
href={`${hostname}/settings/general`}
>
here.
</Anchor>
</Text>
</>
)}
{form.values.type === 'qBittorrent' && (
<>
<TextInput
required
label="Username"
placeholder="admin"
value={form.values.username}
onChange={(event) => {
form.setFieldValue('username', event.currentTarget.value);
}}
error={form.errors.username && 'Invalid username'}
/>
<TextInput
required
label="Password"
placeholder="adminadmin"
value={form.values.password}
onChange={(event) => {
form.setFieldValue('password', event.currentTarget.value);
}}
error={form.errors.password && 'Invalid password'}
/>
</>
)}
{(form.values.type === 'Deluge' ||
form.values.type === 'Transmission' ||
form.values.type === 'qBittorrent') && (
<>
<TextInput
label="Username"
placeholder="admin"
value={form.values.username}
onChange={(event) => {
form.setFieldValue('username', event.currentTarget.value);
}}
error={form.errors.username && 'Invalid username'}
/>
<TextInput
label="Password"
placeholder="password"
value={form.values.password}
onChange={(event) => {
form.setFieldValue('password', event.currentTarget.value);
}}
error={form.errors.password && 'Invalid password'}
/>
</>
)}
</Group>
</ScrollArea>
</Tabs.Tab>
<Tabs.Tab label="Advanced Options">
<Group direction="column" grow>
<MultiSelect
required
label="Password"
placeholder="adminadmin"
value={form.values.password}
onChange={(event) => {
form.setFieldValue('password', event.currentTarget.value);
}}
error={form.errors.password && 'Invalid password'}
label="HTTP Status Codes"
data={StatusCodes}
placeholder="Select valid status codes"
clearButtonLabel="Clear selection"
nothingFound="Nothing found"
defaultValue={['200']}
clearable
searchable
{...form.getInputProps('status')}
/>
</>
)}
{(form.values.type === 'Deluge' || form.values.type === 'Transmission') && (
<>
<TextInput
required
label="Password"
placeholder="password"
value={form.values.password}
onChange={(event) => {
form.setFieldValue('password', event.currentTarget.value);
}}
error={form.errors.password && 'Invalid password'}
<Switch
label="Open service in new tab"
defaultChecked={form.values.newTab}
{...form.getInputProps('newTab')}
/>
</>
)}
</Group>

</Group>
</Tabs.Tab>
</Tabs>
<Group grow position="center" mt="xl">
<Button type="submit">{props.message ?? 'Add service'}</Button>
</Group>
Expand Down
18 changes: 15 additions & 3 deletions src/components/AppShelf/AppShelf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,16 @@ const AppShelf = (props: any) => {
const { colorScheme } = useMantineColorScheme();

const sensors = useSensors(
useSensor(TouchSensor, {}),
useSensor(TouchSensor, {
activationConstraint: {
delay: 500,
tolerance: 5,
},
}),
useSensor(MouseSensor, {
// Require the mouse to move by 10 pixels before activating
activationConstraint: {
delay: 250,
delay: 500,
tolerance: 5,
},
})
Expand Down Expand Up @@ -101,7 +106,14 @@ const AppShelf = (props: any) => {
<SortableContext items={config.services}>
<Grid gutter="xl" align="center">
{filtered.map((service) => (
<Grid.Col key={service.id} span={6} xl={2} xs={4} sm={3} md={3}>
<Grid.Col
key={service.id}
span={6}
xl={config.settings.appCardWidth || 2}
xs={4}
sm={3}
md={3}
>
<SortableAppShelfItem service={service} key={service.id} id={service.id} />
</Grid.Col>
))}
Expand Down
Loading

0 comments on commit 7dc205f

Please sign in to comment.