Action

/ slash tag migration

Posted by FlohGro, Last update 8 months ago - Unlisted

UPDATES

8 months ago

Migrate tags ending with a slash

created by @FlohGro / more on my Blog

/ slash tag migration

This action is a helper to migrate tags that use a slash / at the start, end or in the middle of a tag.
See the forum entry for details why you need to migrate those tags.

Update Warning: Tags starting and ending with “/” no longer allowed
https://forums.getdrafts.com/t/update-warning-tags-starting-and-ending-with-no-longer-allowed/14516

The Action will search for tags with a slash at the start, end or any tag containing a slash and asks you to rename each of them. You have to do it for all tags that start or end with a slash (personally i used it to categorize tags). Tags containing slashes somewhere in between will be nested tags so it might be intended.

Just run the action and look through the tags - if you don‘t want to do all of your tags at once - you can simply abort the migration.

The tags will still be visible in the tag pane for a bit of time.


If you find this useful and want to support me you can donate or buy me a coffe

Buy Me A Coffee

Steps

  • script

    // slash tag migration
    
    // get all tags that contain a slash
    const slashTags = Tag.query("/")
    // get all tags that start with a slash
    const startingWithSlash = slashTags.filter(tag => tag.startsWith("/"))
    // get all tags that end with a slash
    const endingWithSlash = slashTags.filter(tag => tag.endsWith("/"))
    const mustChangeSlashTags = startingWithSlash.concat(endingWithSlash)
    
    // get all tags that contain a slash but NOT at the beginning
    let containsSlash = slashTags.filter(tag => !tag.startsWith("/"))
    let renamedDraftsCt = 0
    let dbg = []
    function run(){
    
    	alert("welcome to the slash tag migration\n\nthis action will help you to migrate tags that contain a \"/\". In the upcoming updates of Drafts this will result in nested Tags as announced in the forums.\nThe Action handles two different cases:\n1) tags starting and ending with a \"/\" must not be used and will be renamed to your preference\n2) tags that contain a \"/\" might need changes if you don't want them to be nested\n\nplease note, no renaming will be done automatically, you need to confirm each tag on its own")
    
    	// iterate through startingWithSlash tags and ask to rename them
    
    	alert("we start with the tags starting or ending with a \"/\".\n\nYou should at least remove the slash - the action will suggest that by default but you need to confirm it for each tag")
    	for(tag of mustChangeSlashTags){
    	// due to drafts kind of caching the tags and not removing them instantly we have to double check that any draft contains a tag - e.g. it was renamed already in an earlier run of this action,... then we skip that tag
        	if(!doesAnyDraftContainTag(tag)){
            	continue
        	}
    		let p = new Prompt()
    		p.title = "rename tag \"" + tag + "\"!"
    		let startsWithSlash = true
    		if(tag.endsWith("/")){
    		    startsWithSlash = false
    		}
    		p.message = "the tag must not " + startsWithSlash ? "start" : "end" + "with a \"\/\" please type the new name into the text field below"
    		let newTagSuggest = ""
    		if(startsWithSlash){
    		    newTagSuggest = tag.slice(1)
    		} else {
    		    newTagSuggest = tag.slice(tag.length)
    		}
    		p.addTextField("newTag","",newTagSuggest,{wantsFocus: true, autocapitalization: "none", autocorrect: false})
    		p.addButton("abort migration helper")
    		p.addButton("rename tag")
    		p.isCancellable = false
    		
    		let curRenamedDraftsAmountCt = renamedDraftsCt
    		if(p.show()){
    			// button was pressed (not cancelled) check if abort is intended
    			if(p.buttonPressed == "abort migration helper"){
    				return
    			}
    			let newTag = p.fieldValues["newTag"]
    			if(newTag.contains("/")){
    			    containsSlash.push(newTag)
    			}
    			renamedDraftsCt += renameTag(tag, newTag)
    			app.displaySuccessMessage("updated " + (renamedDraftsCt - curRenamedDraftsAmountCt) + " drafts")
    		}
    	}
    
    	alert("no more tags with a \"/\" at the beginning or end.\n\nlets see which tags contain a \"/\".\n not at the beginning.\nagain those will be nested tags - think about if you need it for that specific tag and rename it if you don't want to have a nested tag")
    	for(tag of containsSlash){
        	// due to drafts kind of caching the tags and not removing them instantly we have to double check that any draft contains a tag - e.g. it was renamed already in an earlier run of this action,... then we skip that tag
        	if(!doesAnyDraftContainTag(tag)){
            	continue
        	}
    		let p = new Prompt()
    		p.title = "rename tag \"" + tag + "\"?"
    		p.message = "tags with a \"\/\" will be nested tags - check if you want to have a nested tag for the following tag - otherwise pick a new name"
    		p.addTextField("newTag","",tag,{wantsFocus: true, autocapitalization: "none", autocorrect: false})
    		p.addButton("abort migration helper")
    		p.addButton("rename tag")
    		p.addButton("keep tag as it is")
    		p.isCancellable = false
    		
    		let curRenamedDraftsAmountCt = renamedDraftsCt
    		if(p.show()){
    			// button was pressed (not cancelled) check if abort is intended
    			if(p.buttonPressed == "abort migration helper"){
    				return
    			}
    			if(p.buttonPressed == "rename tag"){
    				let newTag = p.fieldValues["newTag"]
    				if(newTag != tag){
    					renamedDraftsCt += renameTag(tag, newTag)
    					app.displaySuccessMessage("updated " + (renamedDraftsCt - curRenamedDraftsAmountCt) + " drafts")
    				}
    			}
    		}
    	}
    
    }
    
    function doesAnyDraftContainTag(tag){
    let drafts = Draft.query("", "all", [tag])
    	if(!drafts){
        	dbg.push("ignoring tag: " + tag)
        	return false
    	}
    if(drafts.length > 0){
    return true
    } else {
    return false
    }
    }
    
    function renameTag(oldTag, newTag){
    	let drafts = Draft.query("", "all", [oldTag]);
    	if (drafts.length == 0) {
    		return 0
    	}
    	else {
    		let ct = 0;
    		for (let d of drafts) {
    			d.removeTag(oldTag);
    			if (newTag.length > 0) {
    				d.addTag(newTag);
    			}
    			d.update();
    			ct++;
    		}
    		return ct
    	}
    }
    
    run()
    alert("finished tag migration.\nupdated " + renamedDraftsCt + " drafts in total")

Options

  • After Success Nothing
    Notification Info
    Log Level Info
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.