mirror of
				https://github.com/louislam/uptime-kuma.git
				synced 2025-11-04 05:36:13 +08:00 
			
		
		
		
	Merge pull request #2489 from mathiash98/mathiash98/clone-monitor
Feature: Clone existing monitor
This commit is contained in:
		@@ -18,9 +18,15 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
/**
 | 
			
		||||
* @typedef {import('./TagsManager.vue').Tag} Tag
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    props: {
 | 
			
		||||
        /** Object representing tag */
 | 
			
		||||
        /** Object representing tag
 | 
			
		||||
         * @type {Tag}
 | 
			
		||||
         */
 | 
			
		||||
        item: {
 | 
			
		||||
            type: Object,
 | 
			
		||||
            required: true,
 | 
			
		||||
@@ -32,7 +38,7 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * Size of tag
 | 
			
		||||
         * @values normal, small
 | 
			
		||||
         * @type {"normal" | "small"}
 | 
			
		||||
         */
 | 
			
		||||
        size: {
 | 
			
		||||
            type: String,
 | 
			
		||||
 
 | 
			
		||||
@@ -134,13 +134,27 @@ import { colorOptions } from "../util-frontend";
 | 
			
		||||
import Tag from "../components/Tag.vue";
 | 
			
		||||
const toast = useToast();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef Tag
 | 
			
		||||
 * @type {object}
 | 
			
		||||
 * @property {number | undefined} id
 | 
			
		||||
 * @property {number | undefined} monitor_id
 | 
			
		||||
 * @property {number | undefined} tag_id
 | 
			
		||||
 * @property {string} value
 | 
			
		||||
 * @property {string} name
 | 
			
		||||
 * @property {string} color
 | 
			
		||||
 * @property {boolean | undefined} new
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    components: {
 | 
			
		||||
        Tag,
 | 
			
		||||
        VueMultiselect,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
        /** Array of tags to be pre-selected */
 | 
			
		||||
        /** Array of tags to be pre-selected
 | 
			
		||||
         * @type {Tag[]}
 | 
			
		||||
         */
 | 
			
		||||
        preSelectedTags: {
 | 
			
		||||
            type: Array,
 | 
			
		||||
            default: () => [],
 | 
			
		||||
@@ -148,10 +162,14 @@ export default {
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            /** @type {Modal | null} */
 | 
			
		||||
            modal: null,
 | 
			
		||||
            /** @type {Tag[]} */
 | 
			
		||||
            existingTags: [],
 | 
			
		||||
            processing: false,
 | 
			
		||||
            /** @type {Tag[]} */
 | 
			
		||||
            newTags: [],
 | 
			
		||||
            /** @type {Tag[]} */
 | 
			
		||||
            deleteTags: [],
 | 
			
		||||
            newDraftTag: {
 | 
			
		||||
                name: null,
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,9 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
 | 
			
		||||
 | 
			
		||||
// Add Free Font Awesome Icons
 | 
			
		||||
// https://fontawesome.com/v5.15/icons?d=gallery&p=2&s=solid&m=free
 | 
			
		||||
// In order to add an icon, you have to:
 | 
			
		||||
// 1) add the icon name in the import statement below;
 | 
			
		||||
// 2) add the icon name to the library.add() statement below.
 | 
			
		||||
import {
 | 
			
		||||
    faArrowAltCircleUp,
 | 
			
		||||
    faCog,
 | 
			
		||||
@@ -45,6 +48,7 @@ import {
 | 
			
		||||
    faHeartbeat,
 | 
			
		||||
    faFilter,
 | 
			
		||||
    faInfoCircle,
 | 
			
		||||
    faClone,
 | 
			
		||||
} from "@fortawesome/free-solid-svg-icons";
 | 
			
		||||
 | 
			
		||||
library.add(
 | 
			
		||||
@@ -90,6 +94,7 @@ library.add(
 | 
			
		||||
    faHeartbeat,
 | 
			
		||||
    faFilter,
 | 
			
		||||
    faInfoCircle,
 | 
			
		||||
    faClone,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export { FontAwesomeIcon };
 | 
			
		||||
 
 | 
			
		||||
@@ -439,6 +439,9 @@
 | 
			
		||||
    "uninstalling": "Uninstalling",
 | 
			
		||||
    "confirmUninstallPlugin": "Are you sure want to uninstall this plugin?",
 | 
			
		||||
    "notificationRegional": "Regional",
 | 
			
		||||
    "Clone Monitor": "Clone Monitor",
 | 
			
		||||
    "Clone": "Clone",
 | 
			
		||||
    "cloneOf": "Clone of {0}",
 | 
			
		||||
    "smtp": "Email (SMTP)",
 | 
			
		||||
    "secureOptionNone": "None / STARTTLS (25, 587)",
 | 
			
		||||
    "secureOptionTLS": "TLS (465)",
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,9 @@
 | 
			
		||||
                    <router-link :to=" '/edit/' + monitor.id " class="btn btn-normal">
 | 
			
		||||
                        <font-awesome-icon icon="edit" /> {{ $t("Edit") }}
 | 
			
		||||
                    </router-link>
 | 
			
		||||
                    <router-link :to=" '/clone/' + monitor.id " class="btn btn-normal">
 | 
			
		||||
                        <font-awesome-icon icon="clone" /> {{ $t("Clone") }}
 | 
			
		||||
                    </router-link>
 | 
			
		||||
                    <button class="btn btn-danger" @click="deleteDialog">
 | 
			
		||||
                        <font-awesome-icon icon="trash" /> {{ $t("Delete") }}
 | 
			
		||||
                    </button>
 | 
			
		||||
 
 | 
			
		||||
@@ -682,13 +682,23 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        pageName() {
 | 
			
		||||
            return this.$t((this.isAdd) ? "Add New Monitor" : "Edit");
 | 
			
		||||
            let name = "Add New Monitor";
 | 
			
		||||
            if (this.isClone) {
 | 
			
		||||
                name = "Clone Monitor";
 | 
			
		||||
            } else if (this.isEdit) {
 | 
			
		||||
                name = "Edit";
 | 
			
		||||
            }
 | 
			
		||||
            return this.$t(name);
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        isAdd() {
 | 
			
		||||
            return this.$route.path === "/add";
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        isClone() {
 | 
			
		||||
            return this.$route.path.startsWith("/clone");
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        isEdit() {
 | 
			
		||||
            return this.$route.path.startsWith("/edit");
 | 
			
		||||
        },
 | 
			
		||||
@@ -906,11 +916,23 @@ message HealthCheckResponse {
 | 
			
		||||
                        this.monitor.notificationIDList[this.$root.notificationList[i].id] = true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else if (this.isEdit) {
 | 
			
		||||
            } else if (this.isEdit || this.isClone) {
 | 
			
		||||
                this.$root.getSocket().emit("getMonitor", this.$route.params.id, (res) => {
 | 
			
		||||
                    if (res.ok) {
 | 
			
		||||
                        this.monitor = res.monitor;
 | 
			
		||||
 | 
			
		||||
                        if (this.isClone) {
 | 
			
		||||
                            /*
 | 
			
		||||
                         * Cloning a monitor will include properties that can not be posted to backend
 | 
			
		||||
                         * as they are not valid columns in the SQLite table.
 | 
			
		||||
                         */
 | 
			
		||||
                            this.monitor.id = undefined; // Remove id when cloning as we want a new id
 | 
			
		||||
                            this.monitor.includeSensitiveData = undefined;
 | 
			
		||||
                            this.monitor.maintenance = undefined;
 | 
			
		||||
                            this.monitor.name = this.$t("cloneOf", [ this.monitor.name ]);
 | 
			
		||||
                            this.monitor.tags = undefined; // FIXME: Cloning tags does not work yet
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        // Handling for monitors that are created before 1.7.0
 | 
			
		||||
                        if (this.monitor.retryInterval === 0) {
 | 
			
		||||
                            this.monitor.retryInterval = this.monitor.interval;
 | 
			
		||||
@@ -981,7 +1003,7 @@ message HealthCheckResponse {
 | 
			
		||||
                this.monitor.url = this.monitor.url.trim();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (this.isAdd) {
 | 
			
		||||
            if (this.isAdd || this.isClone) {
 | 
			
		||||
                this.$root.add(this.monitor, async (res) => {
 | 
			
		||||
 | 
			
		||||
                    if (res.ok) {
 | 
			
		||||
 
 | 
			
		||||
@@ -67,6 +67,10 @@ const routes = [
 | 
			
		||||
                                    },
 | 
			
		||||
                                ],
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                path: "/clone/:id",
 | 
			
		||||
                                component: EditMonitor,
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                path: "/add",
 | 
			
		||||
                                component: EditMonitor,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user