diff --git a/package.json b/package.json
index e5aeb5d..a1e5b5c 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"dependencies": {
"@headlessui/react": "^2.1.2",
"@patternfly/react-log-viewer": "^5.2.0",
+ "@sweetalert2/theme-dark": "^5.0.18",
"@tauri-apps/api": "^1",
"chart.js": "^4.4.4",
"react": "^18.2.0",
@@ -21,7 +22,6 @@
"react-router-dom": "^6.25.1",
"react-syntax-highlighter": "^15.5.0",
"react-table": "^7.8.0",
- "react-toastify": "^10.0.5",
"sweetalert2": "^11.14.0",
"tauri-plugin-store-api": "https://github.com/tauri-apps/tauri-plugin-store#v1"
},
diff --git a/src/App.jsx b/src/App.jsx
index b678e74..5ffafa6 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -2,8 +2,6 @@ import React, {useEffect, useRef} from 'react';
import {BrowserRouter as Router, Route, Routes, useNavigate, useLocation} from 'react-router-dom';
import Sidebar from './components/Sidebar';
import ContainersScreen from './components/Screens/ContainersScreen';
-import {ToastContainer} from 'react-toastify';
-import 'react-toastify/dist/ReactToastify.css';
import ImagesScreen from './components/Screens/ImagesScreen';
import VolumesScreen from './components/Screens/VolumesScreen';
import NetworkScreen from './components/Screens/NetworkScreen';
@@ -55,11 +53,6 @@ function App() {
-
}/>
diff --git a/src/components/Containers/ContainerDetails.jsx b/src/components/Containers/ContainerDetails.jsx
index c82a3c4..5749e3f 100644
--- a/src/components/Containers/ContainerDetails.jsx
+++ b/src/components/Containers/ContainerDetails.jsx
@@ -5,12 +5,13 @@ import {listen} from '@tauri-apps/api/event';
import LogsViewer from '../LogsViewer';
import {IconBxTerminal, IconBxTrashAlt, IconCircleStop, IconPlayCircle, IconRestart, IconWeb} from '../../Icons';
-import {toast} from 'react-toastify';
import {useContainers} from '../../state/ContainerContext';
import LogoScreen from '../LogoScreen';
import ContainerStats from './ContainerStats';
import JSONSyntaxHighlighter from "../JSONSyntaxHighlighter.jsx";
import ContainerNameWidget from "./ContainerNameWidget.jsx";
+import Swal from "sweetalert2";
+import toast from "../../utils/toast.js";
function ContainerDetails() {
@@ -93,6 +94,30 @@ function ContainerDetails() {
function containerOperation(actionType) {
+
+ let unsafeActions = ["delete"]
+
+ if (unsafeActions.includes(actionType)) {
+ Swal.fire({
+ title: 'Are you sure?',
+ showDenyButton: true,
+ showCancelButton: true,
+ confirmButtonText: 'Yes',
+ denyButtonText: 'No',
+ icon: 'warning'
+ }).then((result) => {
+ if (result.isConfirmed) {
+ Swal.fire('Saved!', '', 'success')
+ } else if (result.isDenied) {
+ Swal.fire('Changes are not saved', '', 'info')
+ }
+ })
+ toast.success('Operation completed successfully!');
+
+ return
+ }
+
+
setLoadingButton(actionType)
invoke('container_operation', {
containerName: selectedContainer.Names[0].replace("/", ""),
@@ -161,13 +186,13 @@ function ContainerDetails() {
:
}
@@ -178,7 +203,7 @@ function ContainerDetails() {
disabled={!isContainerRunning}
onClick={() => containerOperation("restart")}
>
- {loadingButton == 'restart' ? :
+ {loadingButton === 'restart' ? :
}
@@ -187,7 +212,7 @@ function ContainerDetails() {
diff --git a/src/components/Containers/ContainerNameWidget.jsx b/src/components/Containers/ContainerNameWidget.jsx
index 7f59846..be8c47b 100644
--- a/src/components/Containers/ContainerNameWidget.jsx
+++ b/src/components/Containers/ContainerNameWidget.jsx
@@ -2,7 +2,7 @@ import {IconCancel, IconEdit, IconTick} from "../../Icons/index.jsx";
import React, {useState} from "react";
import {invoke} from "@tauri-apps/api";
import {useContainers} from "../../state/ContainerContext.jsx";
-import {toast} from "react-toastify";
+import toast from "../../utils/toast.js";
export default function ContainerNameWidget() {
const {selectedContainer, refreshSelectedContainer} = useContainers();
diff --git a/src/components/Images/ImageDetails.jsx b/src/components/Images/ImageDetails.jsx
index 55dacb4..6e7680e 100644
--- a/src/components/Images/ImageDetails.jsx
+++ b/src/components/Images/ImageDetails.jsx
@@ -1,6 +1,6 @@
import {invoke} from '@tauri-apps/api';
import React, {useEffect, useState} from 'react';
-import {toast} from 'react-toastify';
+import toast from '../../utils/toast.js';
import {useImages} from "../../state/ImagesContext";
import {IconBxExport, IconBxTrashAlt, IconCopy} from '../../Icons';
import ImageHistory from './ImageHistory';
@@ -54,7 +54,7 @@ function ImageDetails() {
force: forceDelete,
noPrune: noPrune
}).then((res) => {
- toast.success(res);
+ toast.success('Image successfully deleted!');
setSelectedImage(null);
loadImages();
}).catch((err) => {
diff --git a/src/components/Images/ImageHistory.jsx b/src/components/Images/ImageHistory.jsx
index 8f0d0a0..442c497 100644
--- a/src/components/Images/ImageHistory.jsx
+++ b/src/components/Images/ImageHistory.jsx
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { useImages } from '../../state/ImagesContext'
import { formatSize, formatDate } from '../../utils';
import { invoke } from '@tauri-apps/api';
-import { toast } from 'react-toastify';
+import toast from '../../utils/toast.js';
diff --git a/src/components/Screens/SettingsScreen.jsx b/src/components/Screens/SettingsScreen.jsx
index e330e59..f8d909a 100644
--- a/src/components/Screens/SettingsScreen.jsx
+++ b/src/components/Screens/SettingsScreen.jsx
@@ -1,14 +1,15 @@
-import React, { useState, useEffect, useCallback } from 'react';
-import { capitalizeFirstLetter } from '../../utils';
-import { ALL_THEMES, DEFAULT_THEME, DOCKER_TERMINAL } from '../../constants';
-import { useSettings } from '../../state/SettingsContext';
-import { getVersion } from "@tauri-apps/api/app";
-import { checkUpdate, installUpdate } from "@tauri-apps/api/updater";
-import { relaunch } from "@tauri-apps/api/process";
-import { IconGithub } from "../../Icons/index.jsx";
+import React, {useCallback, useEffect, useState} from 'react';
+import {capitalizeFirstLetter} from '../../utils';
+import {ALL_THEMES, DEFAULT_THEME, DOCKER_TERMINAL} from '../../constants';
+import {useSettings} from '../../state/SettingsContext';
+import {getVersion} from "@tauri-apps/api/app";
+import {checkUpdate, installUpdate} from "@tauri-apps/api/updater";
+import {relaunch} from "@tauri-apps/api/process";
+import {IconGithub} from "../../Icons/index.jsx";
import Swal from "sweetalert2";
-import { invoke } from '@tauri-apps/api';
-import { reteriveValue, storeValue } from "../../utils/storage.js";
+import {invoke} from '@tauri-apps/api';
+import {reteriveValue, storeValue} from "../../utils/storage.js";
+import toast from "../../utils/toast.js";
const SettingsScreen = () => {
const [theme, setTheme] = useState(DEFAULT_THEME);
@@ -42,14 +43,7 @@ const SettingsScreen = () => {
try {
const { shouldUpdate, manifest } = await checkUpdate();
if (!shouldUpdate) {
- Swal.fire({
- position: "bottom-right",
- icon: "success",
- title: "Your app is up to date.",
- showConfirmButton: false,
- timer: 1500,
- toast: true
- });
+ toast.success("Your app is up to date.")
return;
}
console.log(`Installing update ${manifest?.version}, ${manifest?.date}, ${manifest?.body}`);
@@ -60,7 +54,7 @@ const SettingsScreen = () => {
Swal.fire({
icon: "error",
title: "Oops...",
- text: error.message,
+ text: error.message ? error.message : "Failed to check for updates.",
footer: 'Visit Latest Release Page'
});
} finally {
diff --git a/src/utils/clipboard.js b/src/utils/clipboard.js
index 8341d81..df1a76c 100644
--- a/src/utils/clipboard.js
+++ b/src/utils/clipboard.js
@@ -1,4 +1,4 @@
-import { toast } from "react-toastify";
+import toast from "./toast.js";
export const copyToClipboard = (text) => {
diff --git a/src/utils/toast.js b/src/utils/toast.js
new file mode 100644
index 0000000..4b196e1
--- /dev/null
+++ b/src/utils/toast.js
@@ -0,0 +1,53 @@
+import Swal from 'sweetalert2';
+import 'sweetalert2/dist/sweetalert2.min.css';
+import '@sweetalert2/theme-dark/dark.css';
+
+const toast = (() => {
+ let currentLibrary = 'sweetalert2';
+
+
+ const showToast = (message, type = 'info', duration = 3000) => {
+ const timerProgressColors = {
+ success: "bg-success",
+ info: "bg-info",
+ warning: "bg-warning",
+ error: "bg-error"
+ };
+ if (currentLibrary === 'sweetalert2') {
+ Swal.fire({
+ toast: true,
+ position: 'bottom-right',
+ showConfirmButton: false,
+ timer: duration,
+ timerProgressBar: true,
+ icon: type,
+ title: message,
+ background: 'oklch(var(--b2))',
+ customClass: {
+ popup: 'text-base-content',
+ timerProgressBar: timerProgressColors[type]
+ },
+ });
+ } else if (currentLibrary === 'react-toast') {
+ console.log(`React-toast: ${type} - ${message}`);
+ }
+ };
+
+ const setLibrary = (library) => {
+ if (['sweetalert2', 'react-toast'].includes(library)) {
+ currentLibrary = library;
+ } else {
+ console.error('Unsupported library');
+ }
+ };
+
+ return {
+ success: (message, duration) => showToast(message, 'success', duration),
+ error: (message, duration) => showToast(message, 'error', duration),
+ warning: (message, duration) => showToast(message, 'warning', duration),
+ info: (message, duration) => showToast(message, 'info', duration),
+ setLibrary
+ };
+})();
+
+export default toast;
diff --git a/yarn.lock b/yarn.lock
index 8adec59..69af384 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -609,6 +609,11 @@
dependencies:
tslib "^2.4.0"
+"@sweetalert2/theme-dark@^5.0.18":
+ version "5.0.18"
+ resolved "https://registry.yarnpkg.com/@sweetalert2/theme-dark/-/theme-dark-5.0.18.tgz#e070da21b74eec8ba3420c26cf5bd64ed480dd05"
+ integrity sha512-Fdt8OQHQcbJy6i+rvA49h3OAzQevMwDgfsHPdR2kNwT5M7AtG5rAaBBo0StlvNbcTx/AQ5xhEdMyJdnM05CNoQ==
+
"@tanstack/react-virtual@^3.8.1":
version "3.10.8"
resolved "https://registry.yarnpkg.com/@tanstack/react-virtual/-/react-virtual-3.10.8.tgz#bf4b06f157ed298644a96ab7efc1a2b01ab36e3c"
@@ -907,7 +912,7 @@ chokidar@^3.5.3:
optionalDependencies:
fsevents "~2.3.2"
-clsx@^2.0.0, clsx@^2.1.0:
+clsx@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
@@ -1628,13 +1633,6 @@ react-table@^7.8.0:
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.8.0.tgz#07858c01c1718c09f7f1aed7034fcfd7bda907d2"
integrity sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==
-react-toastify@^10.0.5:
- version "10.0.5"
- resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-10.0.5.tgz#6b8f8386060c5c856239f3036d1e76874ce3bd1e"
- integrity sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==
- dependencies:
- clsx "^2.1.0"
-
react@^18.2.0:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"