Replace vue-toast-notification with custom useAppToast across components and enhance Edge Gateway installer state management.
This commit is contained in:
+42949
File diff suppressed because it is too large
Load Diff
@@ -3,15 +3,15 @@ import {computed, onMounted, ref, watch} from 'vue';
|
|||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { authenticatedRequest } from "@/components/session/authenticatedRequest.vue";
|
import { authenticatedRequest } from "@/components/session/authenticatedRequest.vue";
|
||||||
import {BSwitch} from "buefy";
|
import {BSwitch} from "buefy";
|
||||||
import {useToast} from 'vue-toast-notification';
|
|
||||||
import {useI18n} from 'vue-i18n';
|
import {useI18n} from 'vue-i18n';
|
||||||
|
import { useAppToast } from "@/composables/useAppToast.js";
|
||||||
import {
|
import {
|
||||||
getDepartmentSelfServeEnabled,
|
getDepartmentSelfServeEnabled,
|
||||||
setDepartmentSelfServeEnabled,
|
setDepartmentSelfServeEnabled,
|
||||||
} from "@/composables/departmentSelfServeEnabled.js";
|
} from "@/composables/departmentSelfServeEnabled.js";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const toast = useToast();
|
const toast = useAppToast();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const selfServeEnabled = ref(false);
|
const selfServeEnabled = ref(false);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { defineProps, computed, watch } from 'vue';
|
|||||||
import type { NavigationItemProps } from '@/components/models/navigation/NavigationItem.vue';
|
import type { NavigationItemProps } from '@/components/models/navigation/NavigationItem.vue';
|
||||||
import { toggleExpanded } from '../ViewportHeaderSettings.vue';
|
import { toggleExpanded } from '../ViewportHeaderSettings.vue';
|
||||||
import { SessionUser } from '@/components/session/token/SessionUser.vue';
|
import { SessionUser } from '@/components/session/token/SessionUser.vue';
|
||||||
|
import { useAppToast } from "@/composables/useAppToast.js";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
item: {
|
item: {
|
||||||
type: Object as () => NavigationItemProps,
|
type: Object as () => NavigationItemProps,
|
||||||
@@ -20,11 +21,10 @@ const props = defineProps({
|
|||||||
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
import { useToast } from 'vue-toast-notification';
|
|
||||||
import 'vue-toast-notification/dist/theme-sugar.css';
|
import 'vue-toast-notification/dist/theme-sugar.css';
|
||||||
|
|
||||||
// In your setup:
|
// In your setup:
|
||||||
const toast = useToast();
|
const toast = useAppToast();
|
||||||
|
|
||||||
const redirect = async (to: string) => {
|
const redirect = async (to: string) => {
|
||||||
if (!to) {
|
if (!to) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
createEdgeGatewayOperation,
|
createEdgeGatewayOperation,
|
||||||
deleteEdgeGateway,
|
deleteEdgeGateway,
|
||||||
getEdgeGateway,
|
getEdgeGateway,
|
||||||
|
getEdgeGatewayInstallTokenStatus,
|
||||||
listEdgeGatewayDepartments,
|
listEdgeGatewayDepartments,
|
||||||
listEdgeGateways,
|
listEdgeGateways,
|
||||||
peekCachedEdgeGateway,
|
peekCachedEdgeGateway,
|
||||||
@@ -79,6 +80,16 @@ const installerLabel = ref("");
|
|||||||
const installerCommand = ref("");
|
const installerCommand = ref("");
|
||||||
const installerCopyState = ref("idle");
|
const installerCopyState = ref("idle");
|
||||||
const installerClaimPollToken = ref(0);
|
const installerClaimPollToken = ref(0);
|
||||||
|
const createInstallerStatus = () => ({
|
||||||
|
visible: false,
|
||||||
|
claimTokenId: null,
|
||||||
|
state: "Idle",
|
||||||
|
step: "Waiting to start",
|
||||||
|
error: "",
|
||||||
|
diagnostics: [],
|
||||||
|
updatedAt: null,
|
||||||
|
});
|
||||||
|
const installerStatus = ref(createInstallerStatus());
|
||||||
const flashMessage = ref("");
|
const flashMessage = ref("");
|
||||||
const errorState = ref(null);
|
const errorState = ref(null);
|
||||||
const unavailableGatewayId = ref(null);
|
const unavailableGatewayId = ref(null);
|
||||||
@@ -147,6 +158,29 @@ const tone = (status) => ({ ONLINE: "success", DEGRADED: "warning", OFFLINE: "da
|
|||||||
const statusLabel = (status) => ({ ONLINE: "Online", DEGRADED: "Needs attention", OFFLINE: "Offline" }[status] || "Unknown");
|
const statusLabel = (status) => ({ ONLINE: "Online", DEGRADED: "Needs attention", OFFLINE: "Offline" }[status] || "Unknown");
|
||||||
const discoveryLabel = (status) => ({ READY: "Ready", STALE: "Stale", PENDING: "Pending", FAILED: "Failed" }[status] || "Unknown");
|
const discoveryLabel = (status) => ({ READY: "Ready", STALE: "Stale", PENDING: "Pending", FAILED: "Failed" }[status] || "Unknown");
|
||||||
const transportLabel = (mode) => ({ gateway: "Gateway", cloud: "Cloud" }[mode] || mode || "Unknown");
|
const transportLabel = (mode) => ({ gateway: "Gateway", cloud: "Cloud" }[mode] || mode || "Unknown");
|
||||||
|
const installerStateLabel = (status) =>
|
||||||
|
({
|
||||||
|
PENDING: "Pending",
|
||||||
|
RUNNING: "Running",
|
||||||
|
CLAIMED: "Connected",
|
||||||
|
FAILED: "Failed",
|
||||||
|
}[String(status || "").toUpperCase()] || "Unknown");
|
||||||
|
const installerStepLabel = (step) =>
|
||||||
|
({
|
||||||
|
PENDING: "Waiting to start",
|
||||||
|
VERIFY_TOKEN: "Verifying token",
|
||||||
|
INSTALL_PACKAGES: "Installing packages",
|
||||||
|
DOWNLOAD_ARTIFACTS: "Downloading artifacts",
|
||||||
|
WRITE_CONFIG: "Writing config",
|
||||||
|
START_STACK: "Starting stack",
|
||||||
|
WAIT_FOR_CLAIM: "Waiting for gateway claim",
|
||||||
|
CLAIMED: "Gateway claimed",
|
||||||
|
FAILED: "Installer failed",
|
||||||
|
}[String(step || "").toUpperCase()] ||
|
||||||
|
String(step || "Waiting to start")
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/_/g, " ")
|
||||||
|
.replace(/^\w/, (letter) => letter.toUpperCase()));
|
||||||
const deptName = (id) => departments.value.find((item) => Number(item.id) === Number(id))?.name || `Department ${id}`;
|
const deptName = (id) => departments.value.find((item) => Number(item.id) === Number(id))?.name || `Department ${id}`;
|
||||||
const metricText = (value, suffix = "") => (Number.isFinite(Number(value)) ? `${Number(value)}${suffix}` : "No data");
|
const metricText = (value, suffix = "") => (Number.isFinite(Number(value)) ? `${Number(value)}${suffix}` : "No data");
|
||||||
const normalizeFleetUsage = (value) => {
|
const normalizeFleetUsage = (value) => {
|
||||||
@@ -406,6 +440,23 @@ const scheduleInstallerCopyReset = () => {
|
|||||||
}, 1800);
|
}, 1800);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const syncInstallerStatus = (session, overrides = {}) => {
|
||||||
|
installerStatus.value = {
|
||||||
|
...createInstallerStatus(),
|
||||||
|
...installerStatus.value,
|
||||||
|
visible: true,
|
||||||
|
claimTokenId: session?.claim_token_id ?? installerStatus.value.claimTokenId ?? null,
|
||||||
|
state: installerStateLabel(session?.status),
|
||||||
|
step: installerStepLabel(session?.step),
|
||||||
|
error:
|
||||||
|
session?.last_error ||
|
||||||
|
(String(session?.status || "").toUpperCase() === "FAILED" ? session?.message || "Installer failed." : ""),
|
||||||
|
diagnostics: Array.isArray(session?.diagnostics) ? session.diagnostics : [],
|
||||||
|
updatedAt: session?.updated_at || null,
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const copyPlainText = async (value) => {
|
const copyPlainText = async (value) => {
|
||||||
const text = String(value || "");
|
const text = String(value || "");
|
||||||
if (!text.trim()) {
|
if (!text.trim()) {
|
||||||
@@ -747,46 +798,46 @@ const load = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const pollForClaimedGateway = async ({ existingIds, baseline, departmentId, label, pollToken }) => {
|
const pollForClaimedGateway = async ({ claimTokenId, pollToken }) => {
|
||||||
const normalizedDepartmentId = Number(departmentId || 0);
|
|
||||||
const normalizedLabel = normLabel(label);
|
|
||||||
|
|
||||||
for (let attempt = 0; attempt < 60; attempt += 1) {
|
for (let attempt = 0; attempt < 60; attempt += 1) {
|
||||||
if (installerClaimPollToken.value !== pollToken) {
|
if (installerClaimPollToken.value !== pollToken) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await sleep(attempt === 0 ? 1500 : 2000);
|
await sleep(attempt === 0 ? 1500 : 2000);
|
||||||
await refreshFleet();
|
const sessionResponse = await getEdgeGatewayInstallTokenStatus(claimTokenId);
|
||||||
|
const session = unwrap(sessionResponse, null);
|
||||||
const matchingGateways = gateways.value.filter((item) => {
|
if (!session) {
|
||||||
if (Number(item.department_id) !== normalizedDepartmentId) return false;
|
continue;
|
||||||
if (normalizedLabel && normLabel(item.label) !== normalizedLabel) return false;
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
const claimed =
|
|
||||||
matchingGateways.find((item) => !existingIds.has(Number(item.id))) ||
|
|
||||||
(() => {
|
|
||||||
const reusedGateways = sortByMostRecentHeartbeat(
|
|
||||||
matchingGateways.filter((item) => gatewayClaimStateChanged(item, baseline.get(String(item.id))))
|
|
||||||
);
|
|
||||||
if (reusedGateways.length === 1) {
|
|
||||||
return reusedGateways[0];
|
|
||||||
}
|
}
|
||||||
if (normalizedLabel && reusedGateways.length > 1) {
|
|
||||||
return reusedGateways[0];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (claimed) {
|
syncInstallerStatus(session);
|
||||||
flashMessage.value = existingIds.has(Number(claimed.id)) ? "Gateway reconnected." : "Gateway connected.";
|
|
||||||
|
if (String(session.status || "").toUpperCase() === "FAILED") {
|
||||||
|
fail(new Error(session.last_error || session.message || "Installer failed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String(session.status || "").toUpperCase() === "CLAIMED" && session.gateway_id) {
|
||||||
|
flashMessage.value = session.message || "Gateway connected.";
|
||||||
clearError();
|
clearError();
|
||||||
await selectGateway(claimed.id, "overview");
|
await refreshFleet({ forceRefresh: true });
|
||||||
|
await selectGateway(session.gateway_id, "overview");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncInstallerStatus(
|
||||||
|
{
|
||||||
|
claim_token_id: claimTokenId,
|
||||||
|
status: "FAILED",
|
||||||
|
step: "WAIT_FOR_CLAIM",
|
||||||
|
last_error: "The gateway did not claim the installer token in time.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
error: "The gateway did not claim the installer token in time.",
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateInstaller = async () => {
|
const generateInstaller = async () => {
|
||||||
@@ -798,18 +849,44 @@ const generateInstaller = async () => {
|
|||||||
|
|
||||||
loading.value.installer = true;
|
loading.value.installer = true;
|
||||||
installerCopyState.value = "idle";
|
installerCopyState.value = "idle";
|
||||||
|
syncInstallerStatus(
|
||||||
|
{
|
||||||
|
claim_token_id: null,
|
||||||
|
status: "RUNNING",
|
||||||
|
step: "PENDING",
|
||||||
|
last_error: null,
|
||||||
|
diagnostics: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step: "Waiting to start",
|
||||||
|
error: "",
|
||||||
|
diagnostics: [],
|
||||||
|
}
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
const label = installerLabel.value.trim();
|
const label = installerLabel.value.trim();
|
||||||
const pollToken = installerClaimPollToken.value + 1;
|
const pollToken = installerClaimPollToken.value + 1;
|
||||||
const existingIds = new Set(gateways.value.map((item) => Number(item.id)));
|
|
||||||
const baseline = buildGatewayClaimBaseline(gateways.value);
|
|
||||||
const response = await createEdgeGatewayInstallToken({ department_id: departmentId, label: label || undefined });
|
const response = await createEdgeGatewayInstallToken({ department_id: departmentId, label: label || undefined });
|
||||||
|
const installSession = unwrap(response, null) || {};
|
||||||
installerClaimPollToken.value = pollToken;
|
installerClaimPollToken.value = pollToken;
|
||||||
installerCommand.value = unwrap(response, null)?.install_command || "";
|
installerCommand.value = installSession.install_command || "";
|
||||||
|
syncInstallerStatus(
|
||||||
|
{
|
||||||
|
claim_token_id: installSession.claim_token_id || null,
|
||||||
|
status: "RUNNING",
|
||||||
|
step: "PENDING",
|
||||||
|
last_error: null,
|
||||||
|
diagnostics: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
claimTokenId: installSession.claim_token_id || null,
|
||||||
|
}
|
||||||
|
);
|
||||||
flashMessage.value = "Installer token generated.";
|
flashMessage.value = "Installer token generated.";
|
||||||
clearError();
|
clearError();
|
||||||
pollForClaimedGateway({ existingIds, baseline, departmentId, label, pollToken }).catch(() => {});
|
pollForClaimedGateway({ claimTokenId: installSession.claim_token_id, pollToken }).catch((error) => fail(error));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
installerStatus.value = createInstallerStatus();
|
||||||
fail(error);
|
fail(error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value.installer = false;
|
loading.value.installer = false;
|
||||||
@@ -1218,6 +1295,30 @@ onUnmounted(() => {
|
|||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="!filteredGatewayViews.length" class="edge-state-card" data-testid="gateway-empty-state">
|
||||||
|
No gateways are currently available for this fleet view.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<article v-if="installerStatus.visible" class="edge-stat-card" data-testid="gateway-installer-status">
|
||||||
|
<p class="edge-card-label">Installer status</p>
|
||||||
|
<strong data-testid="gateway-installer-status-state">{{ installerStatus.state }}</strong>
|
||||||
|
<p data-testid="gateway-installer-status-step">{{ installerStatus.step }}</p>
|
||||||
|
<p v-if="installerStatus.error" data-testid="gateway-installer-status-error">{{ installerStatus.error }}</p>
|
||||||
|
<details
|
||||||
|
v-if="installerStatus.diagnostics.length"
|
||||||
|
class="edge-installer-diagnostics"
|
||||||
|
data-testid="gateway-installer-status-diagnostics"
|
||||||
|
>
|
||||||
|
<summary>Diagnostics</summary>
|
||||||
|
<ul class="edge-operation-list">
|
||||||
|
<li v-for="diagnostic in installerStatus.diagnostics" :key="`${diagnostic.name}-${diagnostic.output}`">
|
||||||
|
<strong>{{ diagnostic.name }}</strong>
|
||||||
|
<pre class="edge-json-block">{{ diagnostic.output }}</pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</article>
|
||||||
|
|
||||||
<div v-if="allowDestructive" class="edge-onboarding-card" data-testid="gateway-onboarding">
|
<div v-if="allowDestructive" class="edge-onboarding-card" data-testid="gateway-onboarding">
|
||||||
<div class="edge-panel-head">
|
<div class="edge-panel-head">
|
||||||
<h3 class="title is-6">Install new gateway</h3>
|
<h3 class="title is-6">Install new gateway</h3>
|
||||||
@@ -1272,6 +1373,15 @@ onUnmounted(() => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="edge-action-group">
|
<div class="edge-action-group">
|
||||||
|
<button
|
||||||
|
v-if="props.departmentId && currentView !== 'overview'"
|
||||||
|
type="button"
|
||||||
|
class="button is-light"
|
||||||
|
data-testid="gateway-open-full-page"
|
||||||
|
@click="emit('open-gateway-page', selectedGatewayView.id)"
|
||||||
|
>
|
||||||
|
Open full page
|
||||||
|
</button>
|
||||||
<span class="tag is-light">{{ selectedGatewayView.discoveryStatusLabel }}</span>
|
<span class="tag is-light">{{ selectedGatewayView.discoveryStatusLabel }}</span>
|
||||||
<span class="tag is-light">{{ selectedGatewayView.departmentTransportModeLabel }}</span>
|
<span class="tag is-light">{{ selectedGatewayView.departmentTransportModeLabel }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import NotFoundFallBackPageWrapper from "@/components/page/wrappers/NotFoundFall
|
|||||||
import RequiresPermission from "@/components/displays/permissionbased/RequiresPermission.vue";
|
import RequiresPermission from "@/components/displays/permissionbased/RequiresPermission.vue";
|
||||||
import { Goals } from "@/components/session/token/SessionUser/Objects/Goals.vue";
|
import { Goals } from "@/components/session/token/SessionUser/Objects/Goals.vue";
|
||||||
import { showGoalCreateModal, showGoalEditModal } from "./functions/showGoalFormModal";
|
import { showGoalCreateModal, showGoalEditModal } from "./functions/showGoalFormModal";
|
||||||
import { useToast } from 'vue-toast-notification';
|
import { useAppToast } from "@/composables/useAppToast.js";
|
||||||
import { getDepartmentName } from "@/components/pagination/departmentTabs.vue";
|
import { getDepartmentName } from "@/components/pagination/departmentTabs.vue";
|
||||||
import {BToast, BTooltip} from "buefy";
|
import {BToast, BTooltip} from "buefy";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
@@ -26,7 +26,7 @@ const departmentId = ref(SessionUser.functions.getDepartmentIdFromUrl());
|
|||||||
const goals = ref([]);
|
const goals = ref([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const activeTab = ref('active');
|
const activeTab = ref('active');
|
||||||
const toast = useToast();
|
const toast = useAppToast();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const timeframe = ref('all');
|
const timeframe = ref('all');
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, ref, watch } from "vue";
|
import { computed, onMounted, ref, watch } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { useToast } from "vue-toast-notification";
|
|
||||||
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
|
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
|
||||||
import DepartmentDashboardPageWrapper from "@/views/dashboards/departmentDashboard/DepartmentDashboardPageWrapper.vue";
|
import DepartmentDashboardPageWrapper from "@/views/dashboards/departmentDashboard/DepartmentDashboardPageWrapper.vue";
|
||||||
import NotFoundFallBackPageWrapper from "@/components/page/wrappers/NotFoundFallBackPageWrapper.vue";
|
import NotFoundFallBackPageWrapper from "@/components/page/wrappers/NotFoundFallBackPageWrapper.vue";
|
||||||
@@ -10,10 +9,11 @@ import SelfServeTryModal from "@/components/displays/department/tables/SelfServe
|
|||||||
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
||||||
import { ObjectsGlobal } from "@/components/session/token/SessionUser/Objects/ObjectsGlobal.vue";
|
import { ObjectsGlobal } from "@/components/session/token/SessionUser/Objects/ObjectsGlobal.vue";
|
||||||
import { authenticatedRequest } from "@/components/session/authenticatedRequest.vue";
|
import { authenticatedRequest } from "@/components/session/authenticatedRequest.vue";
|
||||||
|
import { useAppToast } from "@/composables/useAppToast.js";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const toast = useToast();
|
const toast = useAppToast();
|
||||||
|
|
||||||
const parseIntOrZero = (value) => {
|
const parseIntOrZero = (value) => {
|
||||||
const parsed = Number.parseInt(value, 10);
|
const parsed = Number.parseInt(value, 10);
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted, watch, defineProps, defineEmits, defineExpose } from 'vue';
|
import { ref, computed, onMounted, watch, defineProps, defineEmits, defineExpose } from 'vue';
|
||||||
import {useToast} from 'vue-toast-notification';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useAppToast } from "@/composables/useAppToast.js";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
//import 'vue-toast-notification/dist/theme-sugar.css';
|
//import 'vue-toast-notification/dist/theme-sugar.css';
|
||||||
@@ -106,7 +106,7 @@ const toastDuration = ref(0);
|
|||||||
|
|
||||||
let instance = null;
|
let instance = null;
|
||||||
|
|
||||||
const $toast = useToast();
|
const $toast = useAppToast();
|
||||||
const createToast = () => {
|
const createToast = () => {
|
||||||
if (!(props.queued > 0 || props.succeeded > 0 || props.failed > 0 )) {
|
if (!(props.queued > 0 || props.succeeded > 0 || props.failed > 0 )) {
|
||||||
return; // Do not create a toast if maxProgress is not greater than 0
|
return; // Do not create a toast if maxProgress is not greater than 0
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import SuperUserDashboardNavigation from "@/views/dashboards/superUserDashboard/
|
|||||||
import PageTitle from "@/components/global/PageTitle.vue";
|
import PageTitle from "@/components/global/PageTitle.vue";
|
||||||
import ModulesPagination from "@/components/displays/pagination/models/SuperUser/ModulesPagination.vue";
|
import ModulesPagination from "@/components/displays/pagination/models/SuperUser/ModulesPagination.vue";
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useToast } from 'vue-toast-notification';
|
import { useAppToast } from "@/composables/useAppToast.js";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const toast = useToast();
|
const toast = useAppToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const laneId = router.currentRoute.value.params.id;
|
const laneId = router.currentRoute.value.params.id;
|
||||||
const lane = ref(null);
|
const lane = ref(null);
|
||||||
|
|||||||
+28
-4
@@ -1,9 +1,10 @@
|
|||||||
|
import fs from 'node:fs'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
import { pathToFileURL } from 'node:url'
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||||
import { viteSingleFile } from 'vite-plugin-singlefile'
|
import { viteSingleFile } from 'vite-plugin-singlefile'
|
||||||
import { VitePWA } from 'vite-plugin-pwa'
|
|
||||||
import VueJsx from '@vitejs/plugin-vue-jsx'
|
import VueJsx from '@vitejs/plugin-vue-jsx'
|
||||||
import { execSync } from 'node:child_process'
|
import { execSync } from 'node:child_process'
|
||||||
|
|
||||||
@@ -60,10 +61,28 @@ function patchBuefyCssMediaQuery() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineConfig(({ mode }) => {
|
async function loadVitePwaPlugin(workspaceRoot) {
|
||||||
|
const localPluginEntry = path.resolve(workspaceRoot, 'node_modules.external-link', 'vite-plugin-pwa', 'dist', 'index.js')
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(localPluginEntry)) {
|
||||||
|
return await import(pathToFileURL(localPluginEntry).href)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to load vite-plugin-pwa from node_modules.external-link:', error.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn('vite-plugin-pwa is unavailable; continuing without PWA support in this environment.')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineConfig(async ({ mode }) => {
|
||||||
const isProd = mode === 'production'
|
const isProd = mode === 'production'
|
||||||
const isPlaywrightRuntime = process.env.PLAYWRIGHT === '1'
|
const isPlaywrightRuntime = process.env.PLAYWRIGHT === '1'
|
||||||
|
const shouldDisableDepOptimizer = process.platform === 'win32'
|
||||||
const workspaceRoot = process.cwd()
|
const workspaceRoot = process.cwd()
|
||||||
|
const vitePwaModule = await loadVitePwaPlugin(workspaceRoot)
|
||||||
|
const VitePWA = vitePwaModule?.VitePWA
|
||||||
|
|
||||||
// Set COMMIT_HASH env var for use in the app
|
// Set COMMIT_HASH env var for use in the app
|
||||||
const version = process.env.npm_package_version || '0.0.0'
|
const version = process.env.npm_package_version || '0.0.0'
|
||||||
@@ -106,7 +125,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
VueJsx(),
|
VueJsx(),
|
||||||
!isProd && !isPlaywrightRuntime && vueDevTools(),
|
!isProd && !isPlaywrightRuntime && vueDevTools(),
|
||||||
enableSingleFile && viteSingleFile(),
|
enableSingleFile && viteSingleFile(),
|
||||||
VitePWA({
|
VitePWA && VitePWA({
|
||||||
registerType: 'autoUpdate',
|
registerType: 'autoUpdate',
|
||||||
injectRegister: isProd ? 'auto' : false,
|
injectRegister: isProd ? 'auto' : false,
|
||||||
strategies: 'generateSW',
|
strategies: 'generateSW',
|
||||||
@@ -222,7 +241,12 @@ export default defineConfig(({ mode }) => {
|
|||||||
ignored: ['**/output/playwright/**']
|
ignored: ['**/output/playwright/**']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
optimizeDeps: isPlaywrightRuntime
|
optimizeDeps: shouldDisableDepOptimizer
|
||||||
|
? {
|
||||||
|
noDiscovery: true,
|
||||||
|
include: []
|
||||||
|
}
|
||||||
|
: isPlaywrightRuntime
|
||||||
? {
|
? {
|
||||||
entries: ['index.html']
|
entries: ['index.html']
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user