Skip to content

Commit 2a6767d

Browse files
authored
Merge pull request #674 from l3montree-dev/fix-delete-assetversion-redirection-bug
2 parents 36522df + 91ba6fc commit 2a6767d

3 files changed

Lines changed: 103 additions & 13 deletions

File tree

src/app/(loading-group)/[organizationSlug]/projects/[projectSlug]/assets/[assetSlug]/refs/page.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { browserApiClient } from "../../../../../../../../services/devGuardApi";
3737
import { AssetVersionDTO } from "../../../../../../../../types/api/api";
3838
import CreateRefDialog from "../../../../../../../../components/CreateBranchDialog";
3939
import { classNames } from "../../../../../../../../utils/common";
40+
import { eventBus } from "@/events";
4041

4142
const RefsPage = () => {
4243
const assetMenu = useAssetMenu();
@@ -72,6 +73,17 @@ const RefsPage = () => {
7273
refs: prev.refs.filter((ref) => ref.slug !== open.slug),
7374
};
7475
});
76+
// If the deleted ref is the last viewed ref, remove it from localStorage
77+
const stored = localStorage.getItem(
78+
"lastViewedAssetVersionSlug" + params.assetSlug,
79+
);
80+
if (stored === open.slug) {
81+
localStorage.removeItem(
82+
"lastViewedAssetVersionSlug" + params.assetSlug,
83+
);
84+
eventBus.dispatch({ type: "assetVersionDeleted", payload: {} });
85+
}
86+
7587
setOpen(null);
7688
} else {
7789
toast.error("Failed to delete ref");

src/components/common/AssetTitle.tsx

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,66 @@
1+
"use client";
2+
13
import { useActiveAsset } from "@/hooks/useActiveAsset";
24
import { useActiveOrg } from "@/hooks/useActiveOrg";
35
import { useActiveProject } from "@/hooks/useActiveProject";
4-
import { useActiveAssetVersion } from "@/hooks/useActiveAssetVersion";
6+
import useDecodedParams from "@/hooks/useDecodedParams";
57
import Link from "next/link";
6-
import React, { useState, useEffect } from "react";
8+
import { useEffect, useState } from "react";
79
import { Badge } from "../ui/badge";
810
import ProjectTitle from "./ProjectTitle";
9-
import useDecodedParams from "@/hooks/useDecodedParams";
11+
import { eventBus } from "@/events";
1012

1113
const AssetTitle = () => {
1214
const activeOrg = useActiveOrg();
1315
const project = useActiveProject()!;
1416
const asset = useActiveAsset();
15-
const assetVersion = useActiveAssetVersion();
1617

1718
const params = useDecodedParams() as { assetVersionSlug?: string };
1819

19-
const [assetVersionSlug, setAssetVersionSlug] = useState<string | undefined>(
20-
undefined,
21-
);
20+
const [assetVersionSlug, setAssetVersionSlug] = useState<string>();
2221

2322
useEffect(() => {
24-
const currentSlug = assetVersion?.slug ?? params?.assetVersionSlug;
23+
const currentSlug = params?.assetVersionSlug;
2524

2625
if (currentSlug) {
27-
localStorage.setItem("lastViewedAssetVersionSlug", currentSlug);
26+
localStorage.setItem(
27+
"lastViewedAssetVersionSlug" + asset?.slug,
28+
currentSlug,
29+
);
2830
setAssetVersionSlug(currentSlug);
2931
} else {
30-
const stored = localStorage.getItem("lastViewedAssetVersionSlug");
31-
setAssetVersionSlug(stored ?? undefined);
32+
const stored = localStorage.getItem(
33+
"lastViewedAssetVersionSlug" + asset?.slug,
34+
);
35+
setAssetVersionSlug(stored && stored !== "undefined" ? stored : "");
3236
}
33-
}, [assetVersion?.slug, params?.assetVersionSlug]);
37+
}, [params?.assetVersionSlug, asset?.slug]);
38+
39+
useEffect(() => {
40+
eventBus.subscribe("assetTitleListener", "assetVersionDeleted", () => {
41+
const stored = localStorage.getItem(
42+
"lastViewedAssetVersionSlug" + asset?.slug,
43+
);
44+
setAssetVersionSlug(stored && stored !== "undefined" ? stored : "");
45+
});
46+
47+
return () => {
48+
eventBus.unsubscribe("assetTitleListener");
49+
};
50+
}, [asset?.slug]);
51+
3452
return (
3553
<span className="flex flex-row gap-2 min-w-0 overflow-hidden">
3654
<ProjectTitle />
3755
<span className="opacity-75 flex-shrink-0">/</span>
3856
<Link
3957
className="flex !text-header-foreground items-center gap-1 hover:no-underline min-w-0"
40-
href={`/${activeOrg?.slug}/projects/${project?.slug}/assets/${asset?.slug}/refs/${assetVersionSlug}`}
58+
href={
59+
`/${activeOrg?.slug}/projects/${project?.slug}/assets/${asset?.slug}` +
60+
(assetVersionSlug && assetVersionSlug !== "undefined"
61+
? `/refs/${assetVersionSlug}`
62+
: "")
63+
}
4164
title={asset?.name}
4265
>
4366
<span className="truncate">{asset?.name}</span>

src/events.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2026 L3montree GmbH and the DevGuard Contributors.
2+
// SPDX-License-Identifier: AGPL-3.0-or-later
3+
4+
interface AssetVersionDeletedEvent {}
5+
6+
type Events = {
7+
assetVersionDeleted: AssetVersionDeletedEvent;
8+
};
9+
10+
type Listener<T extends keyof Events> = {
11+
id: string;
12+
callback: (payload: Events[T]) => void;
13+
};
14+
class EventBus {
15+
private listeners: {
16+
[K in keyof Events]: Listener<K>[];
17+
} = {
18+
assetVersionDeleted: [],
19+
};
20+
public dispatch<E extends keyof Events>(event: {
21+
type: E;
22+
payload: Events[E];
23+
}) {
24+
const listeners = this.listeners[event.type] || [];
25+
26+
for (const listener of listeners) {
27+
listener.callback(event.payload);
28+
}
29+
}
30+
31+
public subscribe<T extends keyof Events>(
32+
id: string,
33+
eventType: T,
34+
callback: (payload: Events[T]) => void,
35+
) {
36+
if (!this.listeners[eventType]) {
37+
this.listeners[eventType] = [];
38+
}
39+
(this.listeners[eventType] as Listener<T>[]) = this.listeners[
40+
eventType
41+
].filter((l) => l.id !== id);
42+
this.listeners[eventType].push({ id, callback });
43+
}
44+
45+
public unsubscribe(id: string) {
46+
for (const eventType in this.listeners) {
47+
this.listeners[eventType as keyof Events] = this.listeners[
48+
eventType as keyof Events
49+
].filter((listener) => listener.id !== id);
50+
}
51+
}
52+
}
53+
54+
// THIS WILL ALWAYS BE A SINGLETON THANKS JAVASCRIPT
55+
export const eventBus = new EventBus();

0 commit comments

Comments
 (0)