Edgewall Software
Modify

Opened 13 years ago

Closed 12 years ago

Last modified 6 years ago

#4686 closed enhancement (fixed)

Ticket duplication using Trac

Reported by: olivermn@… Owned by: Christian Boos
Priority: normal Milestone: 0.11
Component: ticket system Version:
Severity: normal Keywords: copy ticketclone
Cc: Branch:
Release Notes:
API Changes:

Description (last modified by Christian Boos)

It should be possible to create a new ticket by duplicating an existing ticket.

Use Cases

(from #th1214)

We just migrated to Trac from Bugzilla. The only feature we miss is the ability to clone a ticket into the new ticket fields. It would be great to have the Clone a Trac Ticket functionality.

(original request)

I'm hoping this has been done before and I'm just unable to find it. I have a collection of HW which assigns tasks to multiple teams when it arrives. To help manage this data I want to use Trac tasks. I have a GUI front end which solicits for all the data required in creating a task. It also solicits which teams are impacted. I want to create as many issues as there are teams impacted with the components of each driving the owner.

I then want to be able to use the front end to manage status on each of the opened tasks. So tickets 45, 46, 47 might all have the same data but have different components where Teams A, B, and C all have very different assignments.

I don't wish to reinvent the wheel. Is something similar to this already done?

tracking the status of an issue in different release lines

When there's a regression for a bug, instead of reopening the ticket (which will loose the information that this bug has been effectively fixed for the milestone indicated), one could duplicate it and schedule it for a given milestone on the other release line, see #4298.

creating ticket templates

One could have a wiki page with links to a few "typical" tickets that could be used as a templates for creating new tickets. Such tickets could have among other things prefilled descriptions, see #4044.

Attachments (1)

clone_as_action.png (20.8 KB ) - added by Christian Boos 12 years ago.
Yet another possibility, the "clone" as an action distinct from the ones modifying the ticket itself

Download all attachments as: .zip

Change History (32)

comment:1 by anonymous, 12 years ago

Resolution: wontfix
Status: newclosed

As the author I wish to cancel.

comment:2 by Christian Boos, 12 years ago

(this proposal sounded a bit like the "clone ticket" functionality … not sure there's already a ticket opened for that though)

comment:3 by anonymous, 12 years ago

Resolution: wontfix
Status: closedreopened

This is essentially cloning an existing ticket. Not an easy way to do this from my perspective. Have been trying to either use the macros to facilitate or to use eggs. Neither has been fruitful to date. What is the timeline for having clone feature. I found a clone defect that was a year old.

comment:4 by Christian Boos, 12 years ago

Keywords: copy clone added
Milestone: 1.0
Summary: Front-end display and duplication using TracTicket duplication using Trac

What is the timeline for having clone feature. I found a clone defect that was a year old.

I was looking for a duplicate of this request but didn't find it… care to give the ticket number?

I agree that a Clone Ticket functionality can be useful in some scenarios, like one way to deal with the single issue, multiple releases problem (see #4298), or creating ticket templates (see #4044).

comment:5 by olivermn@…, 12 years ago

I have written by own version and I'll post those changes here shortly. Up to you if you'd like to use this to close the other clone issue.

comment:6 by ThurnerRupert <rupert.thurner@…>, 12 years ago

closed the other one as inferior proposal.

in reply to:  6 comment:7 by schandler@…, 12 years ago

Replying to ThurnerRupert <rupert.thurner@gmail.com>:

closed the other one as inferior proposal.

FYI: There is still another clone request #T1214 out there that is different enough, imho, from this ticket.

Version 0, edited 12 years ago by schandler@… (next)

comment:8 by Christian Boos, 12 years ago

Description: modified (diff)

#Th1214 you meant ;-)

Well, I agree that the original description was not explicitly targeted at ticket duplication, it's only because of comment:2 and comment:3 that this ticket has been focused on the ticket cloning topic. I'll cleanup the description to reflect that, as otherwise I think that #Th1214 should be implemented in the base ticket system, for the reasons mentioned in comment:4.

in reply to:  8 comment:9 by schandler@…, 12 years ago

Replying to cboos:

#Th1214 you meant ;-)

Well, I agree that the original description was not explicitly targeted at ticket duplication, it's only because of comment:2 and comment:3 that this ticket has been focused on the ticket cloning topic. I'll cleanup the description to reflect that, as otherwise I think that #Th1214 should be implemented in the base ticket system, for the reasons mentioned in comment:4.

yep. I goofed up. 1214 is on Trac-hacks. Thanks for the correction! I'll be more careful about that.

comment:10 by anonymous, 12 years ago

I forgot about this work.

I made two changes to allow a version of cloning The first was in the style sheet.

/usr/share/trac/template/ticket.cs
 <div class="buttons">
  <input type="hidden" name="ts" value="<?cs var:ticket.ts ?>" />
  <input type="hidden" name="replyto" value="<?cs var:ticket.replyto ?>" />
  <input type="hidden" name="cnum" value="<?cs var:ticket.cnum ?>" />
  <input type="submit" name="preview" value="Preview" accesskey="r" />&nbsp;
  <input type="submit" value="Submit changes" />
  <p>
  <input type="submit" name="clone" value="Clone" />&nbsp;
 </div>



Only 2 new lines in the above:
335,336d333
<   <p>
<   <input type="submit" name="clone" value="Clone" />&nbsp;

The second change was to
/usr/lib/python2-3/site-packages/trac/ticket/web_ui.py

where I made a copy new ticket in a clone request

    def clone_request(self, req, db):
        req.perm.assert_permission('TICKET_CREATE')

        db = self.env.get_db_cnx()

        if req.method == 'POST' and 'owner' in req.args and \
               not req.perm.has_permission('TICKET_MODIFY'):
            del req.args['owner']

        if not req.args.get('summary'):
            raise TracError('Tickets must contain a summary.')

        ticket = Ticket(self.env, db=db)
        ticket.populate(req.args)
        ticket.values['reporter'] = get_reporter_id(req, 'reporter')
        ticket['status'] = 'new'
        self._validate_ticket(req, ticket)

        ticket.insert(db=db)
        db.commit()

        # Notify
        try:
            tn = TicketNotifyEmail(self.env)
            tn.notify(ticket, newticket=True)
        except Exception, e:
            self.log.exception("Failure sending notification on creation of "
                               "ticket #%s: %s" % (ticket.id, e))

        # Redirect the user to the newly created ticket
        if req.args.get('attachment'):
            req.redirect(req.href.attachment('ticket', ticket.id, action='new'))
        else:
            req.redirect(req.href.ticket(ticket.id))

        ticket = Ticket(self.env, db=db)
        ticket.populate(req.args)
        ticket.values['reporter'] = get_reporter_id(req, 'reporter')

        if ticket.values.has_key('description'):
            description = wiki_to_html(ticket['description'], self.env, req, db)
            req.hdf['newticket.description_preview'] = description

        req.hdf['title'] = 'New Ticket'
        req.hdf['newticket'] = ticket.values

        field_names = [field['name'] for field in ticket.fields
                       if not field.get('custom')]
        if 'owner' in field_names:
            curr_idx = field_names.index('owner')
            if 'cc' in field_names:
                insert_idx = field_names.index('cc')
            else:
                insert_idx = len(field_names)
            if curr_idx < insert_idx:
                ticket.fields.insert(insert_idx, ticket.fields[curr_idx])
                del ticket.fields[curr_idx]

        for field in ticket.fields:
            name = field['name']
            del field['name']
            if name in ('summary', 'reporter', 'description', 'type', 'status',
                        'resolution'):
                field['skip'] = True
            elif name == 'owner':
                field['label'] = 'Assign to'
                if not req.perm.has_permission('TICKET_MODIFY'):
                    field['skip'] = True
            elif name == 'milestone':
                # Don't make completed milestones available for selection
                options = field['options'][:]
                for option in field['options']:
                    milestone = Milestone(self.env, option, db=db)
                    if milestone.is_completed:
                        options.remove(option)
                field['options'] = options
            req.hdf['newticket.fields.' + name] = field

        if req.perm.has_permission('TICKET_APPEND'):
            req.hdf['newticket.can_attach'] = True
            req.hdf['newticket.attachment'] = req.args.get('attachment')

        add_stylesheet(req, 'common/css/ticket.css')
        return 'newticket.cs', None





then later in the file defined the call to the above method as

            elif req.args.has_key('clone'):
                self.clone_request(req, db)

                # Use user supplied values
                ticket.populate(req.args)
                req.hdf['ticket.action'] = action
                req.hdf['ticket.ts'] = req.args.get('ts')
                req.hdf['ticket.reassign_owner'] = req.args.get('reassign_owner') \
                                                   or req.authname
                req.hdf['ticket.resolve_resolution'] = req.args.get('resolve_resolution')
                comment = req.args.get('comment')
                if comment:
                    req.hdf['ticket.comment'] = comment
                    # Wiki format a preview of comment
                    req.hdf['ticket.comment_preview'] = wiki_to_html(
                        comment, self.env, req, db)
                self._do_save(req, db, ticket)


I'm sure there are better ways to take advantage of Plugins but this was the fastest way for me to get this done.

comment:11 by Christian Boos, 12 years ago

Owner: changed from Jonas Borgström to Christian Boos
Status: reopenednew

I'm sure there are better ways to take advantage of Plugins but this was the fastest way for me to get this done.

You should preferably produce a patch for this change, that way others can easily take benefit from your work (do a svn checkout of the SubversionRepository, make you changes there, then at the top-level of the checkout, do svn diff > ticket_cloning_for_trac-0.10.patch).

For 0.11, I think we can come up with a simpler solution, I'll try to post one for comments a bit later on.

comment:12 by Noah Kantrowitz, 12 years ago

Just thought it was worth mentioning that the Datamover plugin can copy tickets both between envs and within the same env.

comment:13 by Christian Boos, 12 years ago

Milestone: 1.00.11
Resolution: fixed
Status: newclosed

Implemented in r5457.

comment:14 by ThurnerRupert, 12 years ago

Resolution: fixed
Status: closedreopened

could you pls make this available to any user, not only admin? for trying to use this as "ticket template" (see #4044) it is essential.

allow reopen pls …

comment:15 by Christian Boos, 12 years ago

Ah, you're right. Then perhaps we could make use of a new permission here, or a configuration setting.

comment:16 by Christian Boos, 12 years ago

A TICKET_CLONE permission seems the most appropriate thing, then depending on the expected usage, the trac admin can grant that permission to anonymous, authenticated, or any other combination.

There's also some discussion going on about the placement of this "Clone" button. Some options are:

  • leave it like it is, in the ticket box
  • move it alongside with the other "actions" (which IMO should better be kept focused on the workflow related changes)
  • move it at the bottom of the page, next to the "Preview" and "Submit" ones, at the right side of the screen

I'd be interested to get feedback from future users of this feature.

by Christian Boos, 12 years ago

Attachment: clone_as_action.png added

Yet another possibility, the "clone" as an action distinct from the ones modifying the ticket itself

comment:17 by Christian Boos, 12 years ago

coderanger prototyped the attachment:clone_as_action.png alternative, which also has implications in the ITicketActionController API that would essentially allow to integrate those clone and delete operations in the upcoming bulk editor (#525).

comment:18 by ThurnerRupert, 12 years ago

ad ticket_clone permission: please not

i'm wondering what the gain would be. either you are allowed to create a new ticket or not, no matter where you get it from. and you are allowed to view a ticket or not. if you have both you are able to clone. but its very well possible i'm overlooking something. i'd prefer if trac could stay as slim as possible = asap :)

position of clone

i like the position where it currently is, beside the reply, as it is on top and saves us from scrolling down. even the delete should go, a very good idea of coderanger. but i would not mind it on the bottom additionally if somebody insists all the actions should stay there.

what we really miss on the bottom is the "next - previous" link, as we often have queries, edit one ticket, go to next, edit, go to next, edit … and so on. currently this is a scrolling exercise.

or, what i personally find even more attractive, turn the order upside down, as it is with roundup, see http://www.selenic.com/mercurial/bts/issue552. this would leave all the links, buttons, editable fields in front of your nose, just the "old" things down.

but what i find counter-intuitive on the png (clone as action) is the two clicks you are forcing, as only one is necessary. you do not change and clone or change and delete at the same time, and then applying it. so i guess its against good ui design principles.

usage, positioning of link —> avoid scrolling and clicking

we plan to create some open tickets with contents (e.g. headlines, prio, type, etc filled out), mark it somehow (maybe keyword) to present it in a query/list. how we get this list behind the "new" i'm not sure yet - but maybe having a page with the link would be sufficient. or how we could get a clone icon in every line of the list …

in reply to:  17 comment:19 by Emmanuel Blot, 12 years ago

Replying to cboos:

coderanger prototyped the attachment:clone_as_action.png alternative, which also has implications in the ITicketActionController API that would essentially allow to integrate those clone and delete operations in the upcoming bulk editor (#525).

I'm really not a big fan of seeing Trac UI becoming a little bit more like too many other bug tracking tools that exhibit far too many fields and buttons. I initially chose Trac because of its clean and lean UI, and I hope it will stay simple.
Why not keeping the current style (as with the th:wiki:TicketDeletePlugin), that would be "Reply Delete" in the yellow box?

Having a ticket UI that involves scrolling to reach the numerous fields does not sound like user friendly… Keep in mind something essential: the more buttons and fields are shown, the less the people who want to fill in a bug.

Features that are rarely used (such as deleting a ticket) should not clutter the whole UI, even for the admin accounts.

in reply to:  16 ; comment:20 by Eli Carter, 12 years ago

Replying to cboos:

A TICKET_CLONE permission seems the most appropriate thing, then depending on the expected usage, the trac admin can grant that permission to anonymous, authenticated, or any other combination.

Agreed. In my case, we have people who want the clone functionality who aren't ticket admins.

in reply to:  20 ; comment:21 by ThurnerRupert, 12 years ago

Replying to ecarter:

Replying to cboos:

A TICKET_CLONE permission seems the most appropriate thing, then depending on the expected usage, the trac admin can grant that permission to anonymous, authenticated, or any other combination.

Agreed. In my case, we have people who want the clone functionality who aren't ticket admins.

would it not be sufficient to be allowed to have ticket create? i.e. no additional right necessary? for displaying the ticket itself, ticket read of course is necessary.

in reply to:  21 ; comment:22 by Eli Carter, 12 years ago

Replying to ThurnerRupert:

would it not be sufficient to be allowed to have ticket create? i.e. no additional right necessary? for displaying the ticket itself, ticket read of course is necessary.

Well, yes… and no. On the one hand, ticket cloning is just creating a ticket. On the otherhand, it's a fast way to create a ticket. For internal systems, that's not a problem, but for public-facing sites, that could become a nuisance. But, adding TICKET_CLONE does increase the complexity of the system. Hmm… and you can already pre-fill fields via the url when you just have ticket create… so… maybe TICKET_CREATE should be all we check. I'm undecided.

in reply to:  22 comment:23 by Christian Boos, 12 years ago

Replying to ecarter:

Replying to ThurnerRupert:

would it not be sufficient to be allowed to have ticket create? i.e. no additional right necessary? for displaying the ticket itself, ticket read of course is necessary.

… I'm undecided.

Yes, I think it's a matter of local policy, and if there must be a "one size fits all", then we'd rather go in the direction pointed out by eblot: "clean and lean UI, … hope it will stay simple."

That's admittedly not an easy goal to fulfill when you're adding features, but we should strive to it ;-)

Introducing a TICKET_CLONE permission is somewhat abusing the permission system in order to be able to adapt the UI to the expected "role" of the user. It's probably not the "best" way to do it, but the more flexible given the tools at hand. Maybe a special naming of the permission would help here, showing that it's more a capability than a permission? (e.g. ticket_clone_control)

comment:24 by Christian Boos, 12 years ago

Milestone: 0.11.10.11
Resolution: fixed
Status: reopenedclosed

Ok, for now we're already checking for TICKET_CREATE, so I think the "ticket duplication" can be considered to be implemented.

This doesn't mean it can't be improved upon in the next releases:

  • for the presentation point of view (though there seems to be more people liking the current way than the alternatives)
  • regarding (ab)using the permission system as a way to configure the UI (e.g. use something like TICKET_clone_operation - can't be all lower case as suggested in comment:23)

comment:25 by Christian Boos, 12 years ago

Resolution: fixed
Status: closedreopened

As discussed on trac-dev, I'll try to make a ITemplateStreamFilter sample plugin out of this.

comment:26 by Christian Boos, 12 years ago

Resolution: fixed
Status: reopenedclosed

With r6153, this feature is now available as a single file plugin. Install by copying source:trunk/sample-plugins/ticket_clone.py in your <env>/plugins folder.

comment:27 by anonymous, 11 years ago

Type: enhancementdefect

comment:28 by anonymous, 11 years ago

Type: defectenhancement

comment:29 by Christian Boos, 7 years ago

Keywords: ticketclone added; clone removed

comment:30 by Christian Boos, 6 years ago

For reference, the ticket clone feature is now an optional component which can be found in source:tags/trac-1.0/tracopt/ticket/clone.py

in reply to:  20 comment:31 by Ryan J Ollos, 6 years ago

Replying to ecarter:

Replying to cboos:

A TICKET_CLONE permission seems the most appropriate thing, then depending on the expected usage, the trac admin can grant that permission to anonymous, authenticated, or any other combination.

Agreed. In my case, we have people who want the clone functionality who aren't ticket admins.

Another ticket has been raised for this issue, #10948.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Christian Boos.
The resolution will be deleted. Next status will be 'reopened'.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.