Skip to content

Commit

Permalink
feat: cleans up page redirects
Browse files Browse the repository at this point in the history
  • Loading branch information
amir20 committed Jan 13, 2025
1 parent aa1854a commit 08147bd
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 120 deletions.
69 changes: 13 additions & 56 deletions assets/components/LogViewer/ContainerEventLogItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,79 +3,36 @@
<div class="whitespace-pre-wrap" :data-event="logEntry.event" v-html="logEntry.message"></div>
</LogItem>

<div
class="alert alert-info my-4 w-auto flex-none font-sans text-[1rem] md:mx-auto md:w-1/2"
v-if="followEligible && showCard"
>
<carbon:information class="size-6 shrink-0 stroke-current" />
<!--
<div>
<h3 class="text-lg font-bold">{{ $t("alert.similar-container-found.title") }}</h3>
{{ $t("alert.similar-container-found.message", { containerId: nextContainer.id }) }}
</div>
<div>
<TimedButton
v-if="automaticRedirect"
class="btn-primary btn-sm"
@finished="redirectNow()"
@click="showCard = false"
>
{{ $t("button.cancel") }}
</TimedButton>
<router-link
:to="{ name: '/container/[id]', params: { id: nextContainer.id } }"
class="btn btn-primary btn-sm"
v-else
>
{{ $t("button.redirect") }}
</router-link>
</div>
</div>
-->
</template>
<script lang="ts" setup>
import { ContainerEventLogEntry } from "@/models/LogEntry";
const router = useRouter();
const { showToast } = useToast();
const { t } = useI18n();
const { logEntry } = defineProps<{
logEntry: ContainerEventLogEntry;
showContainerName?: boolean;
}>();
const showCard = ref(true);
const { containers } = useLoggingContext();
const store = useContainerStore();
const { containers: allContainers } = storeToRefs(store);
const nextContainer = computed(
() =>
[
...allContainers.value.filter(
(c) => c.created > containers.value[0].created && c.name === containers.value[0].name,
),
].sort((a, b) => +a.created - +b.created)[0],
);
const followEligible = computed(
() =>
router.currentRoute.value.name === "/container/[id]" && // we are on a container page
logEntry.event === "container-stopped" && // container was stopped
containers.value.length === 1 && // only one container
Date.now() - +logEntry.date < 5 * 60 * 1000 && // was stopped in the last 5 minutes
nextContainer.value !== undefined, // there is a next container
);
function redirectNow() {
showToast(
{
title: t("alert.redirected.title"),
message: t("alert.redirected.message", { containerId: nextContainer.value?.id }),
type: "info",
},
{ expire: 5000 },
);
router.push({ name: "/container/[id]", params: { id: nextContainer.value?.id } });
}
// function redirectNow() {
// showToast(
// {
// title: t("alert.redirected.title"),
// message: t("alert.redirected.message", { containerId: nextContainer.value?.id }),
// type: "info",
// },
// { expire: 5000 },
// );
// router.push({ name: "/container/[id]", params: { id: nextContainer.value?.id } });
// }
</script>

<style scoped>
Expand Down
18 changes: 16 additions & 2 deletions assets/components/common/ToastModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="toast toast-end whitespace-normal max-md:m-0 max-md:w-full">
<div
class="alert max-w-xl max-md:rounded-none"
v-for="toast in toasts"
v-for="{ toast, options: { timed } } in toasts"
:key="toast.id"
:class="{
'alert-error': toast.type === 'error',
Expand All @@ -18,7 +18,21 @@
<div v-html="toast.message" class="[&>a]:underline"></div>
</div>
<div>
<button class="btn btn-circle btn-xs" @click="removeToast(toast.id)"><mdi:close /></button>
<TimedButton
v-if="timed"
class="btn-primary btn-sm"
:duration="timed"
@finished="
removeToast(toast.id);
toast.action?.handler();
"
@cancelled="removeToast(toast.id)"
>
{{ toast.action?.label }}
</TimedButton>
<button class="btn btn-circle btn-xs" @click="removeToast(toast.id)" v-else>
<mdi:close />
</button>
</div>
</div>
</div>
Expand Down
33 changes: 26 additions & 7 deletions assets/composable/toast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,55 @@ type Toast = {
title?: string;
message: string;
type: "success" | "error" | "warning" | "info";
action?: {
label: string;
handler: () => void;
};
};

type ToastOptions = {
expire?: number;
once?: boolean;
timed?: number;
};

const toasts = ref<Toast[]>([]);
const toasts = ref<
{
toast: Toast;
options: ToastOptions;
}[]
>([]);

const showToast = (
toast: Omit<Toast, "id" | "createdAt"> & { id?: string },
{ expire = -1, once = false }: ToastOptions = { expire: -1, once: false },
{ expire = -1, once = false, timed }: ToastOptions = { expire: -1, once: false, translate: false },
) => {
if (once && toasts.value.some((t) => t.id === toast.id)) {
if (once && !toast.id) {
throw new Error("Toast id is required when once is true");
}
if (once && toasts.value.some((t) => t.toast.id === toast.id)) {
return;
}
toasts.value.push({

const toastWithId = {
id: Date.now().toString(),
createdAt: new Date(),
...toast,
createdAt: new Date(),
};
toasts.value.push({
toast: toastWithId,
options: { expire, once, timed },
});

if (expire > 0) {
setTimeout(() => {
removeToast(toasts.value[0].id);
removeToast(toastWithId.id);
}, expire);
}
};

const removeToast = (id: Toast["id"]) => {
toasts.value = toasts.value.filter((toast) => toast.id !== id);
toasts.value = toasts.value.filter((instance) => instance.toast.id !== id);
};

export const useToast = () => {
Expand Down
38 changes: 36 additions & 2 deletions assets/pages/container/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@
</template>

<script lang="ts" setup>
import { type Container } from "@/models/Container";
const route = useRoute("/container/[id]");
const id = toRef(() => route.params.id);
const containerStore = useContainerStore();
const currentContainer = containerStore.currentContainer(id);
const { ready } = storeToRefs(containerStore);
const pinnedLogsStore = usePinnedLogsStore();
const { pinnedLogs } = storeToRefs(pinnedLogsStore);
const { containers: allContainers } = storeToRefs(containerStore) as unknown as { containers: Ref<Container[]> };
const { showToast } = useToast();
const { t } = useI18n();
const router = useRouter();
watchEffect(() => {
if (ready.value) {
Expand All @@ -30,6 +33,37 @@ watchEffect(() => {
}
}
});
const redirectTrigger = ref(false);
watch(currentContainer, () => (redirectTrigger.value = false));
watchEffect(() => {
if (redirectTrigger.value) return;
if (!currentContainer.value) return;
if (currentContainer.value.state === "running") return;
if (Date.now() - +currentContainer.value.finishedAt > 5 * 60 * 1000) return;
const nextContainer = allContainers.value
.filter((c) => c.startedAt > currentContainer.value.startedAt && c.name === currentContainer.value.name)
.sort((a, b) => +a.created - +b.created)[0];
if (!nextContainer) return;
redirectTrigger.value = true;
showToast(
{
title: t("alert.similar-container-found.title"),
message: t("alert.similar-container-found.message", { containerId: nextContainer.id }),
type: "info",
action: {
label: t("button.cancel"),
handler: () => router.push({ name: "/container/[id]", params: { id: nextContainer.id } }),
},
},
{ timed: 4000 },
);
});
</script>
<route lang="yaml">
meta:
Expand Down
1 change: 1 addition & 0 deletions internal/agent/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ func (c *Client) StreamEvents(ctx context.Context, events chan<- docker.Containe
ActorID: resp.Event.ActorId,
Name: resp.Event.Name,
Host: resp.Event.Host,
Time: resp.Event.Timestamp.AsTime(),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/agent/pb/rpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion internal/agent/pb/rpc_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 08147bd

Please sign in to comment.