Quick-add Tags To Topic

:information_source: Summary Add tags to a topic with a click of a button
:hammer_and_wrench: Repository GitHub - NateDhaliwal/quick-add-tags
:question: Install Guide How to install a theme or theme component
:open_book: New to Discourse Themes? Beginner’s guide to using Discourse Themes

Install this theme component

This is a component that adds tags to a topic with a button in the topic footer. It also provides the option to auto-close the topic after x days (minimum 0).

Admins can configure what tag(s) to add to the topic with the quick_add_tags setting.

Admins can also configure the button label, text and success message text.

Once the tag is added successfully, an success message is displayed:
image

If the adding of tag fails, there’ll be an error message displayed:
image

If you enable auto_close_topic, the add tag button will be visible only to admins/moderators/TL4s (because they have the permissions to set the topic timer). You can change the auto_close_topic_days to any value. This closes the topic in that many days.

Inspiration came from this when I saw this post. Hope this helps someone!

20 Likes

This PR replaces all previous settings with the new quick_add_tags_buttons setting.

This adds the functionality to add more that 1 button, and also provides the option to limit each button by category.

Furthermore, you can now change the button label and title for each button.

For example, you can have the following setup:

Button 1:

  • Tags to add: Tag A, Tag B, Tag C
  • In categories: ABC, DEF
  • Auto close: Yes
  • Close in how many days: 2
  • Button label: Add A, B, C
  • Button title: Add tags A, B and C

Button 2:

  • Tags to add: Tag A, Tag D
  • In categories: DEF, XYZ
  • Auto close: No
  • Button label: Add A, D
  • Button title: Add tags A and D

Thanks to @tobiaseigen for the inspiration for this feature!

5 Likes

Hi, I am testing your TC for that use case: A list of topics awaiting answers and solutions? - #6 by patrickemin

  • First question, from what date the auto close is counted ?
  • Second question: it seems specifying categories is compulsory, but in my use case, I do not want to specify categories, is it possible ?

Also the button is oversized, would you know why?

Thanks.

It’s counted from the moment you press the button.

I’ll see if I can make it optional behind a checkbox, or perhaps by leaving it blank.

IIRC that’s due to the amout of text in the button. Less characters are fine. I’m using DButton and have no idea why this occurs. I’ll see if I can apply some CSS on it.

2 Likes

Thanks, leaving it blank would be better I think.

2 Likes

And while you are at it :wink: a checkbox to hide this buttons to non staff users would be good, independently of the topic closing setting.

2 Likes

Yep, I was already thinking of limiting it by groups as well. Thanks.

3 Likes

Seems fixed now :thinking:

This should be done.

Working on a setting to add groups and display the button if the user is in any of the groups. I’m almost done; in the final stages of testing.

1 Like

@patrickemin As per this PR, you can now limit buttons by groups, as per the show_for_groups setting in each button.

1 Like

Thanks, I guess leaving the categories field empty does not apply to all categories by default?

No, I have changed it so that it applies to all categories when left blank.

I have an error git not found when I use this URL to install: https://github.com/NateDhaliwal/quick-add-tags/pull/2

1 Like

@patrickemin I merged that PR into main, so there shouldn’t be a need to install from a PR (if that’s even possible?).

Sorry, installed successfully, working now

1 Like

Found a bug:

When you make a new tag button, but leave fields blank, it breaks my site:

An excerpt of the console loop:

quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}
quick-add-tag-button.gjs:31 user_groups:
quick-add-tag-button.gjs:32 (14) [1, 51, 54, 48, 52, 49, 44, 56, 2, 3, 10, 11, 12, 13]
quick-add-tag-button.gjs:42 {}
quick-add-tag-button.gjs:26 e {#ts: undefined, #mp: undefined, #mh: undefined, #mm: undefined, #eL: undefined, …}

Well, that’s because it’s not supposed to be blank :wink:. Perhaps I should add a placeholder if text is empty.

@nathank I’ve cleaned a few things up. Do you still see that?

2 Likes

Users are dumb, and need some guardrails at times!

Yup, fixed - but now has a very interesting clash with #calendar-and-event:

What it should look like

What I get with a blank quick tag item

quick-add-tag-button.gjs:38 Uncaught (in promise) TypeError: e.show_for_groups is not iterable
    at new k (quick-add-tag-button.gjs:38:41)
    at h.createComponent (index.js:259:12)
    at $.create (index.js:419:28)
    at Object.evaluate (index.js:985:23)
    at Object.evaluate (index.js:103:106)
    at tn.evaluateSyscall (index.js:2873:20)
    at tn.evaluateInner (index.js:2852:64)
    at tn.evaluateOuter (index.js:2849:10)
    at tH.next (index.js:4167:45)
    at tH._execute (index.js:4157:21)
    at tH.execute (index.js:4133:41)
    at tj.handleException (index.js:3450:19)
    at tR.handleException (index.js:3592:52)
    at tF.throw (index.js:3414:16)
    at G.evaluate (index.js:565:42)
    at tF._execute (index.js:3401:34)
    at tF.execute (index.js:3393:17)
    at tU.rerender (index.js:3610:8)
    at tq.render (index-BCp6wOJU.js:4639:55)
    at index-BCp6wOJU.js:4934:16
    at eX (index.js:2414:7)
    at tG._renderRoots (index-BCp6wOJU.js:4914:7)
    at tG._renderRootsTransaction (index-BCp6wOJU.js:4962:12)
    at tG._revalidate (index-BCp6wOJU.js:4995:10)
    at invoke (index.js:262:14)
    at m.flush (index.js:180:11)
    at g.flush (index.js:334:19)
    at q._end (index.js:762:32)
    at q.end (index.js:565:10)
    at q._run (index.js:806:14)
    at q._join (index.js:783:19)
    at q.join (index.js:605:17)
    at Array.<anonymous> (index-BCp6wOJU.js:4728:26)
    at q._trigger (index.js:860:21)
    at q._end (index.js:775:16)
    at index.js:499:12
quick-add-tag-button.gjs:38 Uncaught (in promise) TypeError: e.show_for_groups is not iterable
    at new k (quick-add-tag-button.gjs:38:41)
    at h.createComponent (index.js:259:12)
    at $.create (index.js:419:28)
    at Object.evaluate (index.js:985:23)
    at Object.evaluate (index.js:103:106)
    at tn.evaluateSyscall (index.js:2873:20)
    at tn.evaluateInner (index.js:2852:64)
    at tn.evaluateOuter (index.js:2849:10)
    at tH.next (index.js:4167:45)
    at tH._execute (index.js:4157:21)
    at tH.execute (index.js:4133:41)
    at tj.handleException (index.js:3450:19)
    at tR.handleException (index.js:3592:52)
    at tF.throw (index.js:3414:16)
    at G.evaluate (index.js:565:42)
    at tF._execute (index.js:3401:34)
    at tF.execute (index.js:3393:17)
    at tU.rerender (index.js:3610:8)
    at tq.render (index-BCp6wOJU.js:4639:55)
    at index-BCp6wOJU.js:4934:16
    at eX (index.js:2414:7)
    at tG._renderRoots (index-BCp6wOJU.js:4914:7)
    at tG._renderRootsTransaction (index-BCp6wOJU.js:4962:12)
    at tG._revalidate (index-BCp6wOJU.js:4995:10)
    at invoke (index.js:262:14)
    at m.flush (index.js:180:11)
    at g.flush (index.js:334:19)
    at q._end (index.js:762:32)
    at q.end (index.js:565:10)
    at q._run (index.js:806:14)
    at q._join (index.js:783:19)
    at q.join (index.js:605:17)
    at Array.<anonymous> (index-BCp6wOJU.js:4728:26)
    at q._trigger (index.js:860:21)
    at q._end (index.js:775:16)
    at index.js:499:12
k @ quick-add-tag-button.gjs:38
createComponent @ index.js:259
create @ index.js:419
(anonymous) @ index.js:985
evaluate @ index.js:103
evaluateSyscall @ index.js:2873
evaluateInner @ index.js:2852
evaluateOuter @ index.js:2849
next @ index.js:4167
_execute @ index.js:4157
execute @ index.js:4133
handleException @ index.js:3450
handleException @ index.js:3592
throw @ index.js:3414
evaluate @ index.js:565
_execute @ index.js:3401
execute @ index.js:3393
rerender @ index.js:3610
(anonymous) @ index-BCp6wOJU.js:4639
(anonymous) @ index-BCp6wOJU.js:4934
eX @ index.js:2414
_renderRoots @ index-BCp6wOJU.js:4914
_renderRootsTransaction @ index-BCp6wOJU.js:4962
_revalidate @ index-BCp6wOJU.js:4995
invoke @ index.js:262
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_run @ index.js:806
_join @ index.js:783
join @ index.js:605
(anonymous) @ index-BCp6wOJU.js:4728
_trigger @ index.js:860
_end @ index.js:775
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_ensureInstance @ index.js:919
schedule @ index.js:618
(anonymous) @ rsvp.js:9
_ @ rsvp-ziM3qQyS.js:360
m @ rsvp-ziM3qQyS.js:324
g @ rsvp-ziM3qQyS.js:338
(anonymous) @ rsvp-ziM3qQyS.js:440
(anonymous) @ preload-store.js:32
Promise.then
(anonymous) @ preload-store.js:32
(anonymous) @ rsvp-ziM3qQyS.js:435
e @ rsvp-ziM3qQyS.js:451
getAndRemove @ preload-store.js:26
I @ topic.js:40
refresh @ post-stream.js:365
model @ from-params.js:31
deserialize @ route.js:867
getModel @ router-BViwI_oJ.js:314
(anonymous) @ router-BViwI_oJ.js:149
k @ rsvp-ziM3qQyS.js:412
w @ rsvp-ziM3qQyS.js:398
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_ensureInstance @ index.js:919
ensureInstance @ index.js:731
scheduleRevalidate @ index-BCp6wOJU.js:3609
dirtyTag @ index.js:229
P @ index.js:287
setter @ index.js:447
l @ cache-fCezwMOy.js:1886
l @ index.js:35
dirtyStorageFor @ map.ts:31
set @ map.ts:107
set @ history-store.js:48
navigateToTopic @ item.gjs:89
event @ item.gjs:158
_ @ transformer.js:253
click @ item.gjs:145
quick-add-tag-button.gjs:38 Uncaught (in promise) TypeError: e.show_for_groups is not iterable
    at new k (quick-add-tag-button.gjs:38:41)
    at h.createComponent (index.js:259:12)
    at $.create (index.js:419:28)
    at Object.evaluate (index.js:985:23)
    at Object.evaluate (index.js:103:106)
    at tn.evaluateSyscall (index.js:2873:20)
    at tn.evaluateInner (index.js:2852:64)
    at tn.evaluateOuter (index.js:2849:10)
    at tH.next (index.js:4167:45)
    at tH._execute (index.js:4157:21)
    at tH.execute (index.js:4133:41)
    at tj.handleException (index.js:3450:19)
    at tR.handleException (index.js:3592:52)
    at tF.throw (index.js:3414:16)
    at G.evaluate (index.js:565:42)
    at tF._execute (index.js:3401:34)
    at tF.execute (index.js:3393:17)
    at tU.rerender (index.js:3610:8)
    at tq.render (index-BCp6wOJU.js:4639:55)
    at index-BCp6wOJU.js:4934:16
    at eX (index.js:2414:7)
    at tG._renderRoots (index-BCp6wOJU.js:4914:7)
    at tG._renderRootsTransaction (index-BCp6wOJU.js:4962:12)
    at tG._revalidate (index-BCp6wOJU.js:4995:10)
    at invoke (index.js:262:14)
    at m.flush (index.js:180:11)
    at g.flush (index.js:334:19)
    at q._end (index.js:762:32)
    at q.end (index.js:565:10)
    at q._run (index.js:806:14)
    at q._join (index.js:783:19)
    at q.join (index.js:605:17)
    at Array.<anonymous> (index-BCp6wOJU.js:4728:26)
    at q._trigger (index.js:860:21)
    at q._end (index.js:775:16)
    at index.js:499:12
k @ quick-add-tag-button.gjs:38
createComponent @ index.js:259
create @ index.js:419
(anonymous) @ index.js:985
evaluate @ index.js:103
evaluateSyscall @ index.js:2873
evaluateInner @ index.js:2852
evaluateOuter @ index.js:2849
next @ index.js:4167
_execute @ index.js:4157
execute @ index.js:4133
handleException @ index.js:3450
handleException @ index.js:3592
throw @ index.js:3414
evaluate @ index.js:565
_execute @ index.js:3401
execute @ index.js:3393
rerender @ index.js:3610
(anonymous) @ index-BCp6wOJU.js:4639
(anonymous) @ index-BCp6wOJU.js:4934
eX @ index.js:2414
_renderRoots @ index-BCp6wOJU.js:4914
_renderRootsTransaction @ index-BCp6wOJU.js:4962
_revalidate @ index-BCp6wOJU.js:4995
invoke @ index.js:262
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_run @ index.js:806
_join @ index.js:783
join @ index.js:605
(anonymous) @ index-BCp6wOJU.js:4728
_trigger @ index.js:860
_end @ index.js:775
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_ensureInstance @ index.js:919
schedule @ index.js:618
(anonymous) @ rsvp.js:9
_ @ rsvp-ziM3qQyS.js:360
m @ rsvp-ziM3qQyS.js:324
g @ rsvp-ziM3qQyS.js:338
(anonymous) @ rsvp-ziM3qQyS.js:440
(anonymous) @ preload-store.js:32
Promise.then
(anonymous) @ preload-store.js:32
(anonymous) @ rsvp-ziM3qQyS.js:435
e @ rsvp-ziM3qQyS.js:451
getAndRemove @ preload-store.js:26
I @ topic.js:40
refresh @ post-stream.js:365
model @ from-params.js:31
deserialize @ route.js:867
getModel @ router-BViwI_oJ.js:314
(anonymous) @ router-BViwI_oJ.js:149
k @ rsvp-ziM3qQyS.js:412
w @ rsvp-ziM3qQyS.js:398
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_ensureInstance @ index.js:919
ensureInstance @ index.js:731
scheduleRevalidate @ index-BCp6wOJU.js:3609
dirtyTag @ index.js:229
P @ index.js:287
setter @ index.js:447
l @ cache-fCezwMOy.js:1886
l @ index.js:35
dirtyStorageFor @ map.ts:31
set @ map.ts:107
set @ history-store.js:48
navigateToTopic @ item.gjs:89
event @ item.gjs:158
_ @ transformer.js:253
click @ item.gjs:145
1 Like

Fixed it. It’s not a clash with the said plugin, but instead is a result of the show_for_groups setting being left blank. I have fixed it in this PR:

3 Likes