Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/dev/configs/api.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "4.28.2",
"version": "4.29.2",
"extraOrigins": [],
"sandbox": true,
"ssoSubIds": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing';

import { beforeEach, describe, expect, it, vi } from 'vitest';

import {
AutoStartEntry,
DockerAutostartService,
} from '@app/unraid-api/graph/resolvers/docker/docker-autostart.service.js';
import { DockerAutostartService } from '@app/unraid-api/graph/resolvers/docker/docker-autostart.service.js';
import { DockerContainer } from '@app/unraid-api/graph/resolvers/docker/docker.model.js';

// Mock store getters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';

import { AppError } from '@app/core/errors/app-error.js';
import { DockerLogService } from '@app/unraid-api/graph/resolvers/docker/docker-log.service.js';
import { DockerContainerLogs } from '@app/unraid-api/graph/resolvers/docker/docker.model.js';

// Mock dependencies
const mockExeca = vi.fn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ export class DockerTailscaleService {
);

const dnsName = rawStatus.Self.DNSName;
const actualHostname = dnsName ? dnsName.split('.')[0] : undefined;

let relayName: string | undefined;
if (rawStatus.Self.Relay && derpMap) {
Expand Down
1 change: 0 additions & 1 deletion api/src/unraid-api/graph/resolvers/docker/docker.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
Field,
Float,
GraphQLISODateTime,
ID,
InputType,
Int,
ObjectType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ import { DockerLogService } from '@app/unraid-api/graph/resolvers/docker/docker-
import { DockerManifestService } from '@app/unraid-api/graph/resolvers/docker/docker-manifest.service.js';
import { DockerNetworkService } from '@app/unraid-api/graph/resolvers/docker/docker-network.service.js';
import { DockerPortService } from '@app/unraid-api/graph/resolvers/docker/docker-port.service.js';
import {
ContainerPortType,
ContainerState,
DockerContainer,
} from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
import { ContainerState, DockerContainer } from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.service.js';
import { NotificationsService } from '@app/unraid-api/graph/resolvers/notifications/notifications.service.js';

Expand Down
4 changes: 2 additions & 2 deletions api/src/unraid-api/graph/resolvers/docker/docker.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ export class DockerService {
await this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY);
this.logger.debug(`Invalidated container cache after pausing ${id}`);

let containers = await this.getContainers({ skipCache: true });
let containers: DockerContainer[];
let updatedContainer: DockerContainer | undefined;
for (let i = 0; i < 5; i++) {
await sleep(500);
Expand Down Expand Up @@ -349,7 +349,7 @@ export class DockerService {
await this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY);
this.logger.debug(`Invalidated container cache after unpausing ${id}`);

let containers = await this.getContainers({ skipCache: true });
let containers: DockerContainer[];
let updatedContainer: DockerContainer | undefined;
for (let i = 0; i < 5; i++) {
await sleep(500);
Expand Down
4 changes: 2 additions & 2 deletions api/src/unraid-api/organizer/organizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ export interface MoveItemsToPositionParams {
* Combines moveEntriesToFolder with position-based insertion.
*/
export function moveItemsToPosition(params: MoveItemsToPositionParams): OrganizerView {
const { view, sourceEntryIds, destinationFolderId, position, resources } = params;
const { view, sourceEntryIds, destinationFolderId, position } = params;

const movedView = moveEntriesToFolder({ view, sourceEntryIds, destinationFolderId });

Expand Down Expand Up @@ -743,7 +743,7 @@ export interface CreateFolderWithItemsParams {
* Combines createFolder + moveItems + positioning in a single atomic operation.
*/
export function createFolderWithItems(params: CreateFolderWithItemsParams): OrganizerView {
const { view, folderId, folderName, parentId, sourceEntryIds = [], position, resources } = params;
const { view, folderId, folderName, parentId, sourceEntryIds = [], position } = params;

let newView = createFolderInView({
view,
Expand Down
6 changes: 2 additions & 4 deletions web/src/components/Common/BaseTreeTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,7 @@ function createCellWrapper(
});
}

function wrapColumnHeaderRenderer(
header: ColumnHeaderRenderer | undefined
): ColumnHeaderRenderer | undefined {
function wrapColumnHeaderRenderer(header: ColumnHeaderRenderer | undefined): ColumnHeaderRenderer {
if (typeof header === 'function') {
return function wrappedHeaderRenderer(this: unknown, ...args: unknown[]) {
const result = (header as (...args: unknown[]) => unknown).apply(this, args);
Expand Down Expand Up @@ -481,7 +479,7 @@ const processedColumns = computed<TableColumn<TreeRow<T>>[]>(() => {
createSelectColumn(),
...props.columns.map((col, colIndex) => {
const originalHeader = col.header as ColumnHeaderRenderer | undefined;
const header = wrapColumnHeaderRenderer(originalHeader) ?? originalHeader;
const header = wrapColumnHeaderRenderer(originalHeader);
const cell = (col as { cell?: unknown }).cell
? ({ row }: { row: TableInstanceRow<T> }) => {
const cellFn = (col as { cell: (args: unknown) => VNode | string | number }).cell;
Expand Down
4 changes: 4 additions & 0 deletions web/src/components/Docker/SingleDockerLogViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ function appendLogLines(newLines: Array<{ timestamp: string; message: string }>)

state.lines = [...state.lines, ...added];
if (state.lines.length > MAX_LOG_LINES) {
const removed = state.lines.slice(0, state.lines.length - MAX_LOG_LINES);
for (const line of removed) {
state.lineKeys.delete(`${line.timestamp}|${line.message}`);
}
state.lines = state.lines.slice(state.lines.length - MAX_LOG_LINES);
}
}
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/Logs/SingleLogViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ const refreshLogContent = async () => {
startLogSubscription();
};

watch(() => props.logFilePath, refreshLogContent);
watch(() => props.logFilePath, refreshLogContent, { immediate: true });
defineExpose({ refreshLogContent });
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,16 @@ const dismissNotification = async (notification: NotificationFragmentFragment) =
const { onResult: onNotificationAdded } = useSubscription(notificationAddedSubscription);

onNotificationAdded(({ data }) => {
if (!data) {
if (!data?.notificationAdded) {
return;
}
const notification = useFragment(NOTIFICATION_FRAGMENT, data.notificationAdded);

// Access raw subscription data directly - don't call useFragment in async callback
const rawNotification = data.notificationAdded as unknown as NotificationFragmentFragment;
if (
!notification ||
(notification.importance !== NotificationImportance.ALERT &&
notification.importance !== NotificationImportance.WARNING)
!rawNotification ||
(rawNotification.importance !== NotificationImportance.ALERT &&
rawNotification.importance !== NotificationImportance.WARNING)
) {
return;
}
Expand All @@ -160,7 +162,7 @@ onNotificationAdded(({ data }) => {
return;
}

if (notification.timestamp) {
if (rawNotification.timestamp) {
// Trigger the global toast in tandem with the subscription update.
const funcMapping: Record<
NotificationImportance,
Expand All @@ -170,16 +172,16 @@ onNotificationAdded(({ data }) => {
[NotificationImportance.WARNING]: globalThis.toast.warning,
[NotificationImportance.INFO]: globalThis.toast.info,
};
const toast = funcMapping[notification.importance];
const toast = funcMapping[rawNotification.importance];
const createOpener = () => ({
label: 'Open',
onClick: () => notification.link && window.open(notification.link, '_blank', 'noopener'),
onClick: () => rawNotification.link && window.open(rawNotification.link, '_blank', 'noopener'),
});

requestAnimationFrame(() =>
toast(notification.title, {
description: notification.subject,
action: notification.link ? createOpener() : undefined,
toast(rawNotification.title, {
description: rawNotification.subject,
action: rawNotification.link ? createOpener() : undefined,
})
);
}
Expand Down
3 changes: 3 additions & 0 deletions web/src/components/Wrapper/mount-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ function ensurePortalRoot(): string | undefined {
}

ensureUnapiScope(portalRoot);
if (isDarkModeActive()) {
portalRoot.classList.add('dark');
}

return `#${PORTAL_ROOT_ID}`;
}
Expand Down
24 changes: 12 additions & 12 deletions web/src/composables/useContainerActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ export function useContainerActions<T = unknown>(options: ContainerActionOptions
const confirmStartStopOpen = ref(false);
const confirmToStart = ref<{ name: string }[]>([]);
const confirmToStop = ref<{ name: string }[]>([]);
let pendingStartStopIds: string[] = [];
const pendingStartStopIds = ref<string[]>([]);

const confirmPauseResumeOpen = ref(false);
const confirmToPause = ref<{ name: string }[]>([]);
const confirmToResume = ref<{ name: string }[]>([]);
let pendingPauseResumeIds: string[] = [];
const pendingPauseResumeIds = ref<string[]>([]);

function classifyStartStop(ids: string[]) {
const toStart: { id: string; containerId: string; name: string }[] = [];
Expand Down Expand Up @@ -201,7 +201,7 @@ export function useContainerActions<T = unknown>(options: ContainerActionOptions
const { toStart, toStop } = classifyStartStop(ids);
const isMixed = toStart.length > 0 && toStop.length > 0;
if (isMixed) {
pendingStartStopIds = ids;
pendingStartStopIds.value = ids;
confirmToStart.value = toStart.map((i) => ({ name: i.name }));
confirmToStop.value = toStop.map((i) => ({ name: i.name }));
confirmStartStopOpen.value = true;
Expand All @@ -216,15 +216,15 @@ export function useContainerActions<T = unknown>(options: ContainerActionOptions
}

async function confirmStartStop(close: () => void) {
const { toStart, toStop } = classifyStartStop(pendingStartStopIds);
setRowsBusy(pendingStartStopIds, true);
const { toStart, toStop } = classifyStartStop(pendingStartStopIds.value);
setRowsBusy(pendingStartStopIds.value, true);
try {
await runStartStopBatch(toStart, toStop);
onSuccess?.('Action completed');
} finally {
setRowsBusy(pendingStartStopIds, false);
setRowsBusy(pendingStartStopIds.value, false);
confirmStartStopOpen.value = false;
pendingStartStopIds = [];
pendingStartStopIds.value = [];
close();
}
}
Expand All @@ -234,7 +234,7 @@ export function useContainerActions<T = unknown>(options: ContainerActionOptions
const { toPause, toResume } = classifyPauseResume(ids);
const isMixed = toPause.length > 0 && toResume.length > 0;
if (isMixed) {
pendingPauseResumeIds = ids;
pendingPauseResumeIds.value = ids;
confirmToPause.value = toPause.map((i) => ({ name: i.name }));
confirmToResume.value = toResume.map((i) => ({ name: i.name }));
confirmPauseResumeOpen.value = true;
Expand All @@ -249,15 +249,15 @@ export function useContainerActions<T = unknown>(options: ContainerActionOptions
}

async function confirmPauseResume(close: () => void) {
const { toPause, toResume } = classifyPauseResume(pendingPauseResumeIds);
setRowsBusy(pendingPauseResumeIds, true);
const { toPause, toResume } = classifyPauseResume(pendingPauseResumeIds.value);
setRowsBusy(pendingPauseResumeIds.value, true);
try {
await runPauseResumeBatch(toPause, toResume);
onSuccess?.('Action completed');
} finally {
setRowsBusy(pendingPauseResumeIds, false);
setRowsBusy(pendingPauseResumeIds.value, false);
confirmPauseResumeOpen.value = false;
pendingPauseResumeIds = [];
pendingPauseResumeIds.value = [];
close();
}
}
Expand Down
Loading