diff --git a/.env.example b/.env.example
index 1cf90ef9b..c36af831a 100644
--- a/.env.example
+++ b/.env.example
@@ -10,4 +10,10 @@ NEXTAUTH_SECRET="anything"
# Disable analytics
NEXT_PUBLIC_DISABLE_ANALYTICS="true"
-DEFAULT_COLOR_SCHEME="light"
\ No newline at end of file
+DEFAULT_COLOR_SCHEME="light"
+
+# Unraid API Configuration
+UNRAID_HOST=192.168.10.20
+UNRAID_API_KEY=your-api-key-here
+UNRAID_USE_SSL=false
+UNRAID_PORT=80
\ No newline at end of file
diff --git a/docker-compose.unraid.yml b/docker-compose.unraid.yml
index b4ea4b89b..856fe1402 100644
--- a/docker-compose.unraid.yml
+++ b/docker-compose.unraid.yml
@@ -1,12 +1,10 @@
version: "3.8"
services:
- homarr-unraid:
+ unmarr:
image: git.xtrm-lab.org/jazzymc/homarr:latest
- container_name: homarr-unraid-ui
+ container_name: unmarr
restart: unless-stopped
- ports:
- - "7576:7575"
environment:
# Unraid API Configuration
- UNRAID_HOST=192.168.10.20
@@ -17,18 +15,28 @@ services:
- TZ=Europe/Sofia
- DATABASE_URL=file:/data/db.sqlite
- AUTH_TRUST_HOST=true
- - NEXTAUTH_URL=http://192.168.10.20:7576
+ - NEXTAUTH_URL=https://unmarr.xtrm-lab.org
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-changeme}
volumes:
- - /mnt/user/appdata/homarr-unraid/data:/data
- - /mnt/user/appdata/homarr-unraid/configs:/app/data/configs
+ - /mnt/user/appdata/unmarr/data:/data
+ - /mnt/user/appdata/unmarr/configs:/app/data/configs
networks:
- - unraid-net
+ dockerproxy:
+ ipv4_address: 172.18.0.5
labels:
+ # Traefik
+ - "traefik.enable=true"
+ - "traefik.constraint=valid"
+ - "traefik.http.routers.unmarr.rule=Host(`unmarr.xtrm-lab.org`)"
+ - "traefik.http.routers.unmarr.entrypoints=https"
+ - "traefik.http.routers.unmarr.tls=true"
+ - "traefik.http.routers.unmarr.tls.certresolver=cloudflare"
+ - "traefik.http.services.unmarr.loadbalancer.server.port=7575"
+ # Unraid
- "net.unraid.docker.managed=true"
- "net.unraid.docker.icon=https://homarr.dev/img/logo.png"
- - "net.unraid.docker.webui=http://[IP]:[PORT:7576]"
+ - "net.unraid.docker.webui=https://unmarr.xtrm-lab.org"
networks:
- unraid-net:
- driver: bridge
+ dockerproxy:
+ external: true
diff --git a/scripts/build-and-push.sh b/scripts/build-and-push.sh
index 20922a0c1..de2745410 100755
--- a/scripts/build-and-push.sh
+++ b/scripts/build-and-push.sh
@@ -32,14 +32,7 @@ echo "Image: ${REGISTRY}/${IMAGE_NAME}:${TAG}"
echo ""
echo "To deploy on Unraid:"
echo "1. SSH to Unraid: ssh root@192.168.10.20 -p 422"
-echo "2. Create directory: mkdir -p /mnt/user/appdata/homarr-unraid/{data,configs}"
-echo "3. Pull image: docker pull ${REGISTRY}/${IMAGE_NAME}:${TAG}"
-echo "4. Run container:"
-echo " docker run -d \\"
-echo " --name homarr-unraid-ui \\"
-echo " -p 7576:7575 \\"
-echo " -e UNRAID_HOST=192.168.10.20 \\"
-echo " -e UNRAID_API_KEY=YOUR_API_KEY \\"
-echo " -v /mnt/user/appdata/homarr-unraid/data:/data \\"
-echo " -v /mnt/user/appdata/homarr-unraid/configs:/app/data/configs \\"
-echo " ${REGISTRY}/${IMAGE_NAME}:${TAG}"
+echo "2. Create directory: mkdir -p /mnt/user/appdata/unmarr/{data,configs}"
+echo "3. Copy docker-compose.unraid.yml to Unraid"
+echo "4. Set UNRAID_API_KEY in environment"
+echo "5. Run: docker compose -f docker-compose.unraid.yml up -d"
diff --git a/src/components/Unraid/Dashboard/ArrayCard.tsx b/src/components/Unraid/Dashboard/ArrayCard.tsx
index 6a4f23b95..ffbf3f6a8 100644
--- a/src/components/Unraid/Dashboard/ArrayCard.tsx
+++ b/src/components/Unraid/Dashboard/ArrayCard.tsx
@@ -21,7 +21,7 @@ import {
IconPlayerPlay,
IconPlayerStop,
IconTemperature,
- IconHardDrive,
+ IconDisc,
} from '@tabler/icons-react';
import type { UnraidArray, ArrayDisk, ArrayState } from '~/lib/unraid/types';
@@ -81,7 +81,7 @@ function DiskRow({ disk }: { disk: ArrayDisk }) {
-
+
{disk.name}
diff --git a/src/components/Unraid/Dashboard/DockerCard.tsx b/src/components/Unraid/Dashboard/DockerCard.tsx
index d28097ef7..d64a883d1 100644
--- a/src/components/Unraid/Dashboard/DockerCard.tsx
+++ b/src/components/Unraid/Dashboard/DockerCard.tsx
@@ -179,7 +179,7 @@ export function DockerCard({
-
+
{sortedContainers.length === 0 ? (
@@ -197,7 +197,7 @@ export function DockerCard({
))
)}
-
+
);
}
diff --git a/src/components/Unraid/Dashboard/VmsCard.tsx b/src/components/Unraid/Dashboard/VmsCard.tsx
index eee9e2a69..e2e227ef1 100644
--- a/src/components/Unraid/Dashboard/VmsCard.tsx
+++ b/src/components/Unraid/Dashboard/VmsCard.tsx
@@ -248,7 +248,7 @@ export function VmsCard({
-
+
{sortedVms.length === 0 ? (
@@ -269,7 +269,7 @@ export function VmsCard({
))
)}
-
+
);
}
diff --git a/src/lib/unraid/client.ts b/src/lib/unraid/client.ts
index 88c6f5a56..84fbf9441 100644
--- a/src/lib/unraid/client.ts
+++ b/src/lib/unraid/client.ts
@@ -22,6 +22,7 @@ import type {
UnraidApiResponse,
UnraidArray,
UpsDevice,
+ User,
VirtualMachine,
} from './types';
@@ -255,6 +256,38 @@ export class UnraidClient {
return data.customization;
}
+ // ============================================================================
+ // USERS (STUB - Unraid GraphQL API does not expose user management yet)
+ // ============================================================================
+
+ async getUsers(): Promise {
+ // TODO: Implement when Unraid GraphQL API supports user queries
+ return [];
+ }
+
+ // ============================================================================
+ // SYSLOG (STUB - Unraid GraphQL API does not expose syslog yet)
+ // ============================================================================
+
+ async getSyslog(lines = 100): Promise {
+ // TODO: Implement when Unraid GraphQL API supports syslog queries
+ return [];
+ }
+
+ // ============================================================================
+ // NOTIFICATION ACTIONS
+ // ============================================================================
+
+ async markNotificationRead(id: string): Promise<{ success: boolean }> {
+ // TODO: Implement when Unraid GraphQL API supports marking notifications read
+ return { success: true };
+ }
+
+ async markAllNotificationsRead(): Promise<{ success: boolean }> {
+ // TODO: Implement when Unraid GraphQL API supports bulk notification actions
+ return { success: true };
+ }
+
// ============================================================================
// DASHBOARD (COMPOSITE QUERY)
// ============================================================================
diff --git a/src/lib/unraid/types.ts b/src/lib/unraid/types.ts
index 4b7600f03..2cd15cb9b 100644
--- a/src/lib/unraid/types.ts
+++ b/src/lib/unraid/types.ts
@@ -278,6 +278,8 @@ export interface Vms {
// SHARES TYPES
// ============================================================================
+export type ShareSecurityLevel = 'PUBLIC' | 'SECURE' | 'PRIVATE';
+
export interface Share {
name: string;
comment: string;
@@ -292,7 +294,17 @@ export interface Share {
splitLevel: number;
allocator: 'highwater' | 'fillup' | 'mostfree';
export: string;
- security: string;
+ security: ShareSecurityLevel;
+}
+
+// ============================================================================
+// USER TYPES
+// ============================================================================
+
+export interface User {
+ id: string;
+ name: string;
+ description?: string;
}
// ============================================================================
diff --git a/src/pages/unraid/array/index.tsx b/src/pages/unraid/array/index.tsx
index 13a5a8b76..fdd72ded3 100644
--- a/src/pages/unraid/array/index.tsx
+++ b/src/pages/unraid/array/index.tsx
@@ -31,7 +31,7 @@ import {
import { notifications } from '@mantine/notifications';
import {
IconDatabase,
- IconHardDrive,
+ IconDisc,
IconTemperature,
IconPlayerPlay,
IconPlayerStop,
@@ -93,7 +93,7 @@ function DiskDetailsRow({ disk }: { disk: ArrayDisk }) {
variant="light"
color={disk.spunDown ? 'gray' : getStatusColor(disk.status)}
>
-
+
@@ -530,7 +530,7 @@ export default function ArrayPage() {
}>
Parity ({array.parities.length})
- }>
+ }>
Data Disks ({array.disks.length})
}>
@@ -647,7 +647,7 @@ export default function ArrayPage() {
|
-
+
{device.name}
|
diff --git a/src/pages/unraid/settings/identification.tsx b/src/pages/unraid/settings/identification.tsx
index 5b67cc9a7..cc7df46ae 100644
--- a/src/pages/unraid/settings/identification.tsx
+++ b/src/pages/unraid/settings/identification.tsx
@@ -59,8 +59,8 @@ export default function IdentificationSettingsPage() {
if (vars && !form.isTouched()) {
form.setValues({
name: vars.name || '',
- description: vars.comment || '',
- model: vars.flashProduct || '',
+ description: vars.description || '',
+ model: vars.model || '',
timezone: vars.timezone || '',
});
}
@@ -155,7 +155,7 @@ export default function IdentificationSettingsPage() {
Linux Kernel
- {info?.versions.linux || 'Unknown'}
+ {info?.os.kernel || 'Unknown'}
@@ -166,7 +166,7 @@ export default function IdentificationSettingsPage() {
CPU
- {info?.cpu.model || 'Unknown'}
+ {info?.cpu.brand || 'Unknown'}
@@ -177,7 +177,7 @@ export default function IdentificationSettingsPage() {
Motherboard
- {info?.motherboard?.product || 'Unknown'}
+ {info?.baseboard?.model || 'Unknown'}
@@ -207,19 +207,19 @@ export default function IdentificationSettingsPage() {
- {/* Flash Drive */}
+ {/* Server Model */}
- Flash Drive
+ Hardware
- Product
+ Model
- {vars?.flashProduct || 'Unknown'}
+ {vars?.model || 'Unknown'}
@@ -227,10 +227,10 @@ export default function IdentificationSettingsPage() {
- Vendor
+ Protocol
- {vars?.flashVendor || 'Unknown'}
+ {vars?.protocol || 'Unknown'}
@@ -238,10 +238,10 @@ export default function IdentificationSettingsPage() {
- GUID
+ Port
- {vars?.flashGuid || 'Unknown'}
+ {vars?.port || 'Unknown'}
diff --git a/src/pages/unraid/settings/notifications.tsx b/src/pages/unraid/settings/notifications.tsx
index ee254d7e5..625398a22 100644
--- a/src/pages/unraid/settings/notifications.tsx
+++ b/src/pages/unraid/settings/notifications.tsx
@@ -74,8 +74,8 @@ function getImportanceIcon(importance: NotificationImportance) {
}
}
-function formatDate(timestamp: number): string {
- return new Date(timestamp * 1000).toLocaleDateString('en-US', {
+function formatDate(timestamp: string): string {
+ return new Date(timestamp).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
diff --git a/src/pages/unraid/tools/diagnostics.tsx b/src/pages/unraid/tools/diagnostics.tsx
index e28b188f3..b53c6481f 100644
--- a/src/pages/unraid/tools/diagnostics.tsx
+++ b/src/pages/unraid/tools/diagnostics.tsx
@@ -289,7 +289,7 @@ export default function DiagnosticsPage() {
Linux Kernel
- {info?.versions.linux || 'Unknown'}
+ {info?.os.kernel || 'Unknown'}
@@ -309,7 +309,7 @@ export default function DiagnosticsPage() {
CPU
- {info?.cpu.model || 'Unknown'}
+ {info?.cpu.brand || 'Unknown'}
diff --git a/src/pages/unraid/tools/syslog.tsx b/src/pages/unraid/tools/syslog.tsx
index 89cf2dd95..b0d96159d 100644
--- a/src/pages/unraid/tools/syslog.tsx
+++ b/src/pages/unraid/tools/syslog.tsx
@@ -108,7 +108,7 @@ export default function SyslogPage() {
error,
refetch,
} = api.unraid.syslog.useQuery(
- { lines: 500 },
+ undefined,
{
refetchInterval: autoScroll ? 5000 : false,
}
@@ -116,7 +116,7 @@ export default function SyslogPage() {
useEffect(() => {
if (syslog) {
- setLines(syslog.lines || []);
+ setLines(syslog || []);
}
}, [syslog]);
diff --git a/src/server/api/routers/unraid/router.ts b/src/server/api/routers/unraid/router.ts
index 43a3e0dbd..806c998bf 100644
--- a/src/server/api/routers/unraid/router.ts
+++ b/src/server/api/routers/unraid/router.ts
@@ -337,6 +337,52 @@ export const unraidRouter = createTRPCRouter({
return client.archiveNotification(input.id);
}),
+ // ============================================================================
+ // USERS
+ // ============================================================================
+
+ /**
+ * Get users
+ */
+ users: protectedProcedure.query(async () => {
+ const client = getUnraidClient();
+ return client.getUsers();
+ }),
+
+ // ============================================================================
+ // SYSLOG
+ // ============================================================================
+
+ /**
+ * Get syslog lines
+ */
+ syslog: protectedProcedure.query(async () => {
+ const client = getUnraidClient();
+ return client.getSyslog();
+ }),
+
+ // ============================================================================
+ // NOTIFICATION ACTIONS
+ // ============================================================================
+
+ /**
+ * Mark notification as read
+ */
+ markNotificationRead: protectedProcedure
+ .input(notificationIdSchema)
+ .mutation(async ({ input }) => {
+ const client = getUnraidClient();
+ return client.markNotificationRead(input.id);
+ }),
+
+ /**
+ * Mark all notifications as read
+ */
+ markAllNotificationsRead: protectedProcedure.mutation(async () => {
+ const client = getUnraidClient();
+ return client.markAllNotificationsRead();
+ }),
+
// ============================================================================
// SERVICES
// ============================================================================
diff --git a/src/styles/orchis/theme.ts b/src/styles/orchis/theme.ts
index fcbb1d273..89aa9e505 100644
--- a/src/styles/orchis/theme.ts
+++ b/src/styles/orchis/theme.ts
@@ -4,7 +4,7 @@
* https://github.com/vinceliuice/Orchis-theme
*/
-import { MantineProviderProps, MantineThemeColors, Tuple } from '@mantine/core';
+import { MantineThemeOverride, Tuple } from '@mantine/core';
// ============================================================================
// ORCHIS COLOR PALETTE
@@ -159,7 +159,7 @@ const orchisOrange: Tuple = [
// MANTINE THEME CONFIGURATION
// ============================================================================
-export const orchisColors: MantineThemeColors = {
+export const orchisColors: Record> = {
// Override default colors with Orchis palette
blue: orchisBlue,
gray: orchisGrey,
@@ -176,7 +176,7 @@ export const orchisColors: MantineThemeColors = {
surface: orchisGrey,
};
-export const orchisTheme: MantineProviderProps['theme'] = {
+export const orchisTheme: MantineThemeOverride = {
// Color configuration
colors: orchisColors,
primaryColor: 'blue',
@@ -192,21 +192,21 @@ export const orchisTheme: MantineProviderProps['theme'] = {
// Border radius - Orchis uses 12px as default
radius: {
- xs: 4,
- sm: 6,
- md: 12, // Default Orchis corner radius
- lg: 18, // Window radius
- xl: 24,
+ xs: '4px',
+ sm: '6px',
+ md: '12px', // Default Orchis corner radius
+ lg: '18px', // Window radius
+ xl: '24px',
},
defaultRadius: 'md',
// Spacing - Orchis base is 6px
spacing: {
- xs: 4,
- sm: 6,
- md: 12,
- lg: 18,
- xl: 24,
+ xs: '4px',
+ sm: '6px',
+ md: '12px',
+ lg: '18px',
+ xl: '24px',
},
// Shadows - Material Design elevation
|