123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314 |
- {% extends "repo_master.html" %}
- {% from "_formhelper.html"
- import render_bootstrap_field,
- show_comment, show_initial_comment, show_attachments %}
- {% block title %}Issue #{{ issueid }}: {{issue.title | noJS(ignore="img") | safe }} - {{ repo.name }}{% endblock %}
- {% set tag = "home"%}
- {% block header %}
- <link rel="stylesheet" nonce="{{ g.nonce }}" href="{{
- url_for('static', filename='vendor/emojione/emojione.sprites.css') }}?version={{ g.version}}"/>
- <link rel="stylesheet" nonce="{{ g.nonce }}" href="{{
- url_for('static', filename='vendor/selectize/selectize.bootstrap3.css') }}?version={{ g.version}}"/>
- <link rel="stylesheet" nonce="{{ g.nonce }}" href="{{
- url_for('static', filename='vendor/jquery.atwho/jquery.atwho.css') }}?version={{ g.version}}"/>
- {% endblock %}
- {% block repo %}
- <div class="d-flex align-items-start">
- <h4 class="ml-1">
- {% if g.authenticated and (g.repo_user or open_access or g.fas_user.username == issue.user.user) %}
- <form action="{{ url_for('ui_ns.update_issue', username=username,
- namespace=repo.namespace, repo=repo.name, issueid=issueid)
- }}" method="post" class="hidden" id="changestatusform">
- {{form.csrf_token}}
- <input type="hidden" id="statusform_status" name="status" value=""/>
- <input type="hidden" id="statusform_close_status" name="close_status" value=""/>
- {% endif %}
- {% if g.authenticated and (g.repo_user or open_access) %}
- <input type="hidden" id="statusform_tag" name="tag" value=""/>
- <input type="hidden" id="statusform_depending" name="depending" value=""/>
- <input type="hidden" id="statusform_blocking" name="blocking" value=""/>
- <input type="hidden" id="statusform_assignee" name="assignee" value=""/>
- <input type="hidden" id="statusform_milestone" name="milestone" value=""/>
- <input type="hidden" id="statusform_priority" name="priority" value=""/>
- {{form.private}}
- {% if repo.issue_keys %}
- {% for field in repo.issue_keys %}
- <input type="hidden" id="statusform_{{ field.name | replace(' ', '_') }}" name="{{ field.name }}" value=""/>
- {% endfor %}
- {% endif %}
- {% endif %}
- {% if g.authenticated and (g.repo_user or open_access or g.fas_user.username == issue.user.user) %}
- </form>
- {% endif %}
- <div>
- {% if issue.private %}
- <span title="Private ticket" class="text-danger fa fa-fw fa-lock"></span>
- {% endif %}
- {% if issue.status == 'Open' %}
- <span class="fa fa-fw text-success fa-exclamation-circle pt-1"></span>
- <span class="text-success font-weight-bold">#{{issue.id}}</span>
- {% elif issue.status == 'Closed' %}
- <span class="fa fa-fw text-danger fa-exclamation-circle pt-1"></span>
- <span class="text-danger font-weight-bold">#{{issue.id}}</span>
- {% endif %}
- <span class="font-weight-bold">
- {{ issue.title | noJS(ignore="img") | safe}}
- </span>
- {% if g.repo_committer or (
- g.fas_user and g.fas_user.username == issue.user.username) %}
- <a class="btn btn-outline-secondary btn-sm border-0" href="{{
- url_for('ui_ns.edit_issue',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- issueid=issueid)
- }}" title="Edit this issue">
- <i class="fa fa-pencil"></i></a>
- {% endif %}
- </div>
- <div>
- <small>
- {% if issue.status == 'Open' %}
- <span data-toggle="tooltip" title="{{issue.date_created | format_datetime}}">
- <span class="text-success font-weight-bold">Opened</span> {{ issue.date_created |humanize }}
- </span>
- <span title="{{ issue.user.html_title }}"> by {{ issue.user.user }}.</span>
- <span class="text-muted" data-toggle="tooltip" title="{{issue.last_updated | format_datetime}}">
- Modified {{ issue.last_updated |humanize }}
- </span>
- {% elif issue.status == 'Closed' %}
- <span data-toggle="tooltip" title="{{issue.closed_at | format_datetime}}">
- <span class="text-danger font-weight-bold">
- {% if issue.close_status %}
- Closed: {{issue.close_status}}
- {% else %}
- Closed
- {% endif %}
- </span> {{ issue.closed_at |humanize }}
- </span>
- {% if issue.closed_by %}
- by
- <span title="{{ issue.closed_by.html_title }}">{{ issue.closed_by.user }}.</span>
- {% endif %}
- <span class="text-muted" data-toggle="tooltip" title="{{issue.date_created | format_datetime}}">
- <span class="font-weight-bold">Opened</span> {{ issue.date_created |humanize }}
- </span>
- <span class="text-muted" title="{{ issue.user.html_title }}">by {{ issue.user.user }}.</span>
- {% endif %}
- </small>
- </div>
- </h4>
- <div class="ml-auto">
- <div class="btn-group">
- <div class="dropdown">
- {% if g.authenticated and (g.repo_user or open_access or g.fas_user.username == issue.user.user) %}
- <a class="font-weight-bold btn btn-sm {{'btn-success' if issue.status=='Open' else 'btn-danger'}} dropdown-toggle pointer"
- id="dropdownMenuButton" data-toggle='dropdown' aria-haspopup="true" aria-expanded="false">
- {% else %}
- <a class="font-weight-bold opacity-100 disabled btn btn-sm {{'btn-success' if issue.status=='Open' else 'btn-danger'}} pointer">
- {% endif %}
- {% if issue.status == 'Open' %}
- Open
- {% else %}
- {% if issue.close_status %}
- Closed: {{issue.close_status}}
- {% else %}
- Closed
- {% endif %}
- {% endif %}
- </a>
- <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
- {% if issue.status == 'Open' %}
- {% if repo.close_status %}
- <h6 class="dropdown-header">Close issue as:</h6>
- {% for close_status in repo.close_status %}
- <a class="dropdown-item close_status_dropdown_action pointer" data-value="{{close_status}}">{{close_status}}</a>
- {% endfor %}
- {% else %}
- <a class="dropdown-item close_status_dropdown_action pointer" data-value="">Close Issue</a>
- {% endif %}
- {% else %}
- <a class="dropdown-item close_status_dropdown_action pointer">Reopen Issue</a>
- {% endif %}
- {% if g.repo_committer %}
- <div class="dropdown-divider"></div>
- <a class="dropdown-item text-danger pointer" id="closeticket"
- title="Delete this ticket">
- <i class="fa fa-fw fa-trash"></i> Delete Issue
- </a>
- {% endif %}
- </div>
- </div>
- </div>
- </div>
- </div>
- <form action="{{ url_for('ui_ns.update_issue', username=username,
- namespace=repo.namespace, repo=repo.name, issueid=issueid)
- }}" method="post" class="mainform">
- {{ form.csrf_token }}
- <div class="row mt-4">
- <div class="col-md-8 mt-2">
- {{ show_initial_comment(issue, username, repo,issueid, form) }}
- <hr class="mb-1"/>
- <section id="comments" class="pt-1">
- {% if issue.comments %}
- {% for comment in issue.comments %}
- {% if comment.notification %}
- <div class="d-flex align-items-center px-3 py-2 mb-3">
- <div class="">
- {{ comment.user.default_email | avatar(16) | safe }}
- </div>
- <span class="font-size-09 autogenerated-comment pl-4">{{ comment.comment | markdown | noJS | safe }}</span>
- <div class="text-muted ml-auto">
- <span title="{{ comment.date_created | format_datetime }}">{{
- comment.date_created | humanize }}</span>
- </div>
- </div>
- {% else %}
- {{ show_comment(comment, comment.id, repo, username, issueid, form) }}
- {% endif %}
- {% endfor %}
- {% endif %}
- </section>
- {% if g.authenticated and form and not repo.settings.get('issue_tracker_read_only', False) %}
- <div class="card mt-5">
- <div class="card-header pb-0 pt-1 bg-light">
- <div class="row">
- <div class="col align-self-center">
- <span><strong>Add new comment</strong></span>
- </div>
- <div class="col">
- <ul class="nav nav-tabs float-right border-bottom-0">
- <li class="nav-item">
- <a class="nav-link pointer" id="previewinmarkdown">Preview</a>
- </li>
- <li class="nav-item">
- <a class="nav-link active pointer" id="editinmarkdown" >Edit</a>
- </li>
- </ul>
- {% if repo.quick_replies %}
- {% include "quick_reply.html" %}
- {% endif %}
- </div>
- </div>
- </div>
- <div class="card-body">
- <textarea class="form-control" rows=8 id="comment" name="comment"
- placeholder="Enter your comment here" tabindex=1></textarea>
- <div id="preview" class="p-1">
- </div>
- <div class="mt-2">
- <label class="custom-file font-size-09">
- <input type="file" id="file-picker" class="custom-file-input" name="file" accept="image/*" multiple tabindex=3>
- <label class="custom-file-label" for="file-picker">
- Browse to attach images or drag them into the comment field
- </label>
- </label>
- <div id="progress" class="progress hidden height-22p">
- <div id="progress-bar" class="progress-bar height-22p">0%</div>
- </div>
- </div>
- </div>
- <div class="card-footer bg-light">
- <div class="d-flex align-items-center">
- <small>Comments use <a href="https://docs.pagure.org/pagure/usage/markdown.html"
- target="_blank" rel="noopener noreferrer" class="notblue">Markdown Syntax</a></small>
- <div class="ml-auto">
- <div class="btn-group">
- {% if g.authenticated and (g.repo_user or open_access or g.fas_user.username == issue.user.user) %}
- {% if issue.status == 'Open' %}
- {% if repo.close_status %}
- <div class="btn-group">
- <a class="btn btn-outline-primary dropdown-toggle pointer"
- id="dropdownMenuButton" data-toggle='dropdown' aria-haspopup="true" aria-expanded="false" tabindex=3>
- Comment & Close
- </a>
- <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
- <h6 class="dropdown-header">Close issue as:</h6>
- {% for close_status in repo.close_status %}
- <a class="dropdown-item comment_and_close_action pointer" data-value="{{close_status}}">{{close_status}}</a>
- {% endfor %}
- </div>
- </div>
- {% else %}
- <a class="btn btn-outline-primary comment_and_close_action pointer" data-value="">
- Comment & Close
- </a>
- {% endif %}
- {% else %}
- <a class="btn btn-outline-primary comment_and_close_action pointer" data-value="">
- Comment & Reopen
- </a>
- {% endif %}
- {% endif %}
- <input type="submit" class="btn btn-primary"
- value="Comment" tabindex=2 />
- </div>
- </div>
- </div>
- </div>
- </div>
- {% elif g.authenticated and form and repo.settings.get('issue_tracker_read_only', False) %}
- <p>
- This issue tracker is read-only.
- </p>
- {% else %}
- <p>
- <a href="{{ url_for('auth_login', next=request.url) }}">Login</a>
- to comment on this ticket.
- </p>
- {% endif %}
- </div>
- <div class="col-md-4">
- <div>
- <div class="mb-4">
- <h5 class="d-flex align-items-center font-weight-bold border-bottom">
- <div class="py-2 text-uppercase font-size-09">Metadata</div>
- {% if g.authenticated and (g.repo_user or g.fas_user.username == issue.user.user or open_access)
- and not repo.settings.get('issue_tracker_read_only', False) %}
- <div class="ml-auto">
- <a class="btn btn-outline-primary border-0 btn-sm issue-metadata-display editmetadatatoggle pointer inline-block"><i class="fa fa-fw fa-pencil"></i></a>
- <a class="btn btn-outline-secondary border-0 btn-sm issue-metadata-form hidden editmetadatatoggle pointer hidden"><i class="fa fa-fw fa-times"></i></a>
- </div>
- {% endif %}
- </h5>
- {% if g.authenticated and (g.repo_user or g.fas_user.username == issue.user.user) %}
- <div class="hidden">
- {{form.status}}
- {{form.close_status}}
- </div>
- {% endif%}
- <fieldset class="form-group issue-metadata-display mt-4">
- <label class="mb-1 pl-1"> <i class="fa fa-fw fa-user-plus"></i> <strong>Assignee</strong></label>
- <div id="assignee_plain">
- <div class="ml-2" title="{{ issue.assignee.html_title if issue.assignee else '' }}">
- {% if issue.assignee %}
- <div class="mt-1">{{issue.assignee.username| avatar(size=24) | safe}}
- <a href="{{ url_for(
- 'ui_ns.view_issues',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- assignee=issue.assignee.username)
- }}" title="{{ issue.assignee.html_title }}">
- {{ issue.assignee.username }}
- </a>
- {% if g.authenticated and (issue.assignee.username == g.fas_user.username) %}
- — <a class="pointer" id="drop-btn"
- title="drop the assignment of this issue">
- Drop
- </a>
- {% endif %}
- </div>
- {% else %}
- <div class="text-muted">
- None
- {% if g.authenticated and (g.repo_user or g.fas_user.username == issue.user.user or open_access) and issue.status|lower == 'open'
- and (not issue.assignee or issue.assignee.username != g.fas_user.username)
- and not repo.settings.get('issue_tracker_read_only', False) %}
- — <a class="pointer" id="take-btn"
- title="assign this issue to you">
- Take
- </a>
- {% endif %}
- </div>
- {% endif %}
- </div>
- </div>
- </fieldset>
- {% if g.authenticated and (g.repo_user or open_access) %}
- <fieldset class="form-group issue-metadata-form hidden">
- <label for="assignee"><strong>Assignee</strong></label>
- <input class="form-control" name="assignee" id="assignee"
- placeholder="username"
- value="{{ issue.assignee.username or '' }}" />
- </fieldset>
- {% endif%}
- <fieldset class="form-group issue-metadata-display mt-4">
- <label class="mb-1"><i class="fa fa-fw fa-tag"></i> <strong>Tags</strong></label>
- {% if issue.tags %}
- <h4 class="ml-2" id="taglist">
- {% for tag in issue.tags %}
- <a id="tag-{{ tag.tag }}" title="{{ tag.tag_description }}"
- data-bg-color="{{ tag.tag_color }}"
- class="badge badge-secondary text-left my-1 p-2 badge-tag"
- href="{{ url_for('ui_ns.view_issues',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- tags=tag.tag) }}">
- {{ tag.tag }}
- </a>
- {% endfor %}
- </h4>
- {% else %}
- <div class="text-muted">None</div>
- {% endif%}
- </fieldset>
- {% if g.authenticated and (g.repo_user or open_access) %}
- <fieldset class="form-group issue-metadata-form hidden">
- <label for="tag"><strong>Tags</strong></label>
- <input id="tag" type="text" placeholder="tag1, tag2" name="tag"
- title="comma separated list of tags"
- value="{{ issue.tags_text | join(',') }}" />
- </fieldset>
- {% endif%}
- {%macro blocks_item(ticket, itemtype="block") %}
- {% if ticket.status|lower == 'open' %}
- {% set status_color = "success" %}
- {% elif ticket.status|lower == 'merged' %}
- {% set status_color = "info" %}
- {% else %}
- {% set status_color = "danger" %}
- {% endif %}
- <div class="d-flex align-items-center">
- <div class="nowrap">
- <span class="fa fa-fw text-{{status_color}} fa-exclamation-circle pt-1"></span>
- <span class="text-{{status_color}} font-weight-bold">#{{ticket.id}}</span>
- </div>
- <div class="ellipsis pl-2 font-size-09">
- <a id="{{itemtype}}-{{ ticket.id }}"
- href="{{ url_for('ui_ns.view_issue',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- issueid=ticket.id)
- }}" class="notblue">{{ticket.title}}</a>
- </div>
- </div>
- {% endmacro %}
- <fieldset class="form-group issue-metadata-display mt-4">
- <label class="mb-1 pl-1"> <i class="fa fa-fw fa-ban"></i> <strong>Blocking</strong></label>
- <div class="ml-2" id="blocklist">
- {% if issue.children %}
- {% for ticket in issue.children %}
- {{blocks_item(ticket, itemtype="block")}}
- {% endfor %}
- {% else %}
- <div class="text-muted">None</div>
- {% endif%}
- </div>
- </fieldset>
- {% if g.authenticated and (g.repo_user or open_access) %}
- <fieldset class="form-group issue-metadata-form hidden">
- <label for="blocking"><strong>Blocking</strong></label>
- <input class="form-control" id="blocking" type="text"
- placeholder="issue blocking" name="blocking"
- value="{{ issue.blocking_text | join(',') }}" />
- </fieldset>
- {% endif%}
- <fieldset class="form-group issue-metadata-display mt-4">
- <label class="mb-1 pl-1"> <i class="fa fa-fw fa-check-circle-o"></i> <strong>Depending on</strong></label>
- <div class="ml-2" id="dependlist">
- {% if issue.parents %}
- {% for ticket in issue.parents %}
- {{blocks_item(ticket, itemtype="depend")}}
- {% endfor %}
- {% else %}
- <div class="text-muted">None</div>
- {% endif %}
- </div>
- </fieldset>
- {% if g.authenticated and (g.repo_user or open_access) %}
- <fieldset class="form-group issue-metadata-form hidden">
- <label for="depending"><strong>Depending on</strong></label>
- <input class="form-control" id="depending" type="text"
- placeholder="issue depending" name="depending"
- value="{{ issue.depending_text | join(',') }}" />
- </fieldset>
- {% endif%}
- {% if repo.priorities %}
- <fieldset class="form-group issue-metadata-display mt-4">
- <label class="mb-1 pl-1"> <i class="fa fa-bolt"></i> <strong>Priority</strong></label>
- <div class="ml-2" id="priority_plain">
- {% if issue.priority is not none %}
- <span >{{ repo.priorities[issue.priority | string] }}</span>
- {% else %}
- <div class="text-muted">None</div>
- {% endif %}
- </div>
- </fieldset>
- {% if g.authenticated and (g.repo_user or open_access) %}
- {{ render_bootstrap_field(form.priority,
- formclass="issue-metadata-form hidden") }}
- {% endif%}
- {% endif %}
- {% if repo.milestones %}
- <fieldset class="form-group issue-metadata-display mt-4">
- <label class="mb-1 pl-1"> <i class="fa fa-fw fa-map-signs"></i> <strong>Milestone</strong></label>
- <div class="ml-2" id="milestone_plain">
- {% if issue.milestone %}
- <span>
- <a href="{{ url_for(
- 'ui_ns.view_milestone',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- milestone=issue.milestone) }}">
- {{ issue.milestone }}
- </a>
- </span>
- {% else %}
- <span class="text-muted">None</span>
- {% endif %}
- </div>
- </fieldset>
- {% if g.authenticated and (g.repo_user or open_access) %}
- {{ render_bootstrap_field(form.milestone,
- formclass="issue-metadata-form hidden") }}
- {% endif%}
- {% endif %}
- {% if g.authenticated and (g.repo_user or open_access) %}
- {{ render_bootstrap_field(form.private,
- formclass="issue-metadata-form hidden") }}
- {% endif%}
- {% if repo.issue_keys %}
- {% for field in repo.issue_keys %}
- <fieldset class="form-group issue-metadata-display mt-4">
- <label class="mb-0"> <i class="fa fa-fw fa-circle-o"></i> <strong>{{ field.name }}</strong></label>
- <div class="pl-2" id="{{ field.name | replace(' ', '_') }}_plain">
- {% if field.name in knowns_keys %}
- {% if field.key_type == 'link' %}
- {% for link in knowns_keys[field.name].value.split(',') %}
- <a target="_blank" rel="noopener noreferrer" href="{{ link }}">{{ link }}</a>
- <br>
- {% endfor %}
- {% else %}
- {{ knowns_keys[field.name].value }}
- {% endif %}
- {% else %}
- <div class="text-muted">None</div>
- {% endif %}
- </div>
- </fieldset>
- {% if g.authenticated and (g.repo_user or open_access) %}
- <fieldset class="form-group issue-metadata-form hidden">
- <label for="field"><strong> <i class="fa fa-fw fa-circle-o"></i>{{ field.name }}</strong></label>
- {% if field.key_type == 'list' %}
- <select class="form-control"
- name="{{ field.name }}"
- id="{{ field.name | replace(' ', '_') }}">
- <option value="None">None</option>
- {% for item in field.data or [] %}
- <option value="{{item}}" {% if field.name in knowns_keys and item == knowns_keys[field.name].value %} selected {% endif %}>
- {{ item }}
- </option>
- {% endfor %}
- </select>
- {% else %}
- <input
- {%- if field.key_type == 'boolean' %} type="checkbox" {% endif %}
- {%- if field.key_type == 'date'%} type="date" {% endif %}
- class="form-control" name="{{ field.name }}" id="{{ field.name }}"
- {%- if field.name in knowns_keys %}
- {% if field.key_type == 'boolean'%}
- {% if knowns_keys[field.name].value in ['true', 'on', '1'] %}checked{% endif %}
- {% else %} value="{{ knowns_keys[field.name].value }}"
- {% endif %}
- {%- endif -%} />
- {% endif %}
- </fieldset>
- {% endif %}
- {% endfor %}
- {% endif %}
- <input type="submit" class="btn btn-primary issue-metadata-form hidden" value="Update">
- </div>
- </div>
- {% if attachments %}
- <div class="mt-3">
- <h5 class="d-flex align-items-center font-weight-bold border-bottom">
- <div class="py-2 text-uppercase font-size-09">
- Attachments
- <span class="badge badge-secondary badge-pill font-size-09 ml-1" id="attachments-count">{{attachments|count}}</span>
- </div>
- {#<div class="ml-auto">
- <a href="#" class="btn btn-sm btn-link" id="subcribe-btn"
- {% if g.fas_user.username in subscribers -%}
- title="Unsubscribe from this issue">Unsubscribe
- {%- else -%}
- title="Subscribe to this issue">Subscribe
- {%- endif -%}
- </a>
- </div>#}
- </h5>
- {{ show_attachments(attachments) }}
- </div>
- {% endif %}
- {% if g.authenticated %}
- <div class="mt-3">
- <h5 class="d-flex align-items-center font-weight-bold border-bottom">
- <div class="py-2 text-uppercase font-size-09">
- Subscribers
- <span class="badge badge-secondary badge-pill font-size-09 ml-1" id="subscribers-count">{{subscribers|count}}</span>
- </div>
- <div class="ml-auto">
- <a href="#" class="btn btn-sm btn-link" id="subcribe-btn"
- {% if g.fas_user.username in subscribers -%}
- title="Unsubscribe from this issue">Unsubscribe
- {%- else -%}
- title="Subscribe to this issue">Subscribe
- {%- endif -%}
- </a>
- </div>
- </h5>
- {% if subscribers %}
- <div id="subscribers_list" class="p-2">
- {% for subscriber in subscribers %}
- <a href="{{ url_for('ui_ns.view_user', username=subscriber)
- }}" title="{{ subscriber }}" id="sub-avatar-{{subscriber}}">{{
- subscriber |avatar(size=30, css_class="pb-1") | safe
- }}</a>
- {% endfor %}
- </div>
- {% else %}
- <div class="text-center text-muted pt-2">No Subscribers</div>
- {% endif %}
- </div>
- {% endif %}
- {% if issue.related_prs %}
- <div class="mt-3">
- <h5 class="d-flex align-items-center font-weight-bold border-bottom">
- <div class="py-2 text-uppercase font-size-09">
- Related Pull Requests
- </div>
- </h5>
- <div id="pr_list">
- <ul class="list-unstyled">
- {% for pr in issue.related_prs %}
- <li>
- <a class="badge badge-secondary" href="{{ url_for(
- 'ui_ns.request_pull',
- repo=pr.project.name,
- username=pr.project.user.user if pr.project.is_fork else none,
- namespace=pr.project.namespace,
- requestid=pr.id) }}">#{{pr.id}}</a>
- {{ pr.status if pr.status != 'Open' else 'Last updated'
- }} {{ pr.last_updated | humanize }}
- </li>
- {% endfor %}
- </ul>
- </div>
- </div>
- {% endif %}
- </div>
- </div>
- </form>
- {% endblock %}
- {% block jscripts %}
- {{ super() }}
- <script type="text/javascript" nonce="{{ g.nonce }}">
- var UPLOAD_URL = "{{ url_for('ui_ns.upload_issue', repo=repo.name, username=username, namespace=repo.namespace, issueid=issue.id) }}";
- </script>
- <script type="text/javascript" nonce="{{ g.nonce }}"src="{{
- url_for('static', filename='vendor/jquery.textcomplete/jquery.textcomplete.min.js') }}?version={{ g.version}}"></script>
- <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
- url_for('static', filename='vendor/emojione/emojione.min.js') }}?version={{ g.version}}"></script>
- <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
- url_for('static', filename='emoji/emojicomplete.js') }}?version={{ g.version}}"></script>
- <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
- url_for('static', filename='upload.js') }}?version={{ g.version}}"></script>
- <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
- url_for('static', filename='vendor/selectize/selectize.min.js') }}?version={{ g.version}}"></script>
- <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
- url_for('static', filename='vendor/jquery.caret/jquery.caret.min.js') }}?version={{ g.version}}"></script>
- <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
- url_for('static', filename='vendor/jquery.atwho/jquery.atwho.min.js') }}?version={{ g.version}}"></script>
- <script type="text/javascript" nonce="{{ g.nonce }}">
- {% if g.authenticated and form %}
- $(document).ready(function() {
- // Set up the drag/drop zone.
- initDropbox("{{ form.csrf_token.current_token }}", "#comment");
- // Set up the handler for the file input box.
- $("#file-picker").on("change", function() {
- doUpload("{{ form.csrf_token.current_token }}", this.files);
- });
- $('.delete_comment_btn').click(function() {
- return confirm('Do you really want to remove this comment?');
- });
- $('.mainform').submit(function() {
- return try_async_comment($(this));
- });
- $('.mainform #assignee').selectize({
- valueField: 'user',
- labelField: 'user',
- searchField: 'user',
- maxItems: 1,
- create: false,
- load: function(query, callback) {
- if (!query.length) return callback();
- $.getJSON(
- "{{ url_for('api_ns.api_users') }}", {
- pattern: "*"+query+"*"
- },
- function( data ) {
- callback( data.users.map(function(x) { return { user: x }; }) );
- }
- );
- }
- });
- $.get("{{ url_for('api_ns.api_users') }}", {
- pattern: '*'
- }).done(function(resp) {
- var userConfig = {
- at: '@',
- data: resp['mention'],
- insertTpl: '@${username}',
- displayTpl: "<li><img src=\"${image}\"> ${username} <small>${name}</small></li>",
- searchKey: "username"
- }
- $("#comment").atwho(userConfig);
- });
- $.when($.get("{{ url_for('api_ns.api_view_issues',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- status='all') }}"),
- $.get("{{ url_for('api_ns.api_pull_request_views',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- status='all') }}")
- ).done(function(issuesResp, prResp) {
- // 0 is the api response
- var issuesAndPrs = issuesResp[0]['issues'].concat(prResp[0]['requests']);
- var data = $.map(issuesAndPrs, function(ticket, idx) {
- return {
- name: ticket.id.toString(),
- title: $('<div>').text(ticket.title).html()
- }
- });
- var issueAndPrConfig = {
- at: '#',
- data: data,
- insertTpl: '#${name}',
- displayTpl: "<li>#${name}<small> ${title}</small></li>",
- }
- $("#comment").atwho(issueAndPrConfig);
- })
- });
- {% endif %}
- function setup_edit_btns() {
- $(".edit_btn").unbind();
- $(".edit_btn").click(function() {
- var commentid = $( this ).attr('data-comment');
- var _url = '{{ request.base_url }}' + '/comment/' + commentid + '/edit';
- $.ajax({
- url: _url + '?js=1',
- type: 'GET',
- dataType: 'html',
- success: function(res) {
- var el = $('#comment-' + commentid);
- var sec = el.parent().find('.issue_comment');
- $(sec).hide();
- el.parent().find('.issue_actions').hide();
- $(sec).after(res);
- cancel_edit_btn();
- },
- error: function() {
- alert('Could not make edit work');
- }
- });
- return false;
- });
- };
- function cancel_edit_btn() {
- $("#comment_update_cancel").unbind();
- $("#comment_update_cancel").click(
- function() {
- $(this).closest('#comments').find('.issue_comment').show();
- $(this).closest('#comments').find('.issue_actions').show();
- $(this).closest('.edit_comment').remove();
- return false;
- });
- };
- function setup_reply_btns() {
- $(".reply").unbind();
- $( ".reply" ).click(
- function() {
- var _section = $(this).closest('.card');
- if (!_section.length) {
- var _section = $(this).closest('#original_comment_box');
- }
- var _comment = _section.find('.comment_body');
- var _text = _comment.text().split("\n");
- var _output = new Array();
- for (cnt = 0; cnt < _text.length ; cnt ++) {
- _output[cnt] = '> ' + $.trim(_text[cnt]);
- }
- var _prev = $.trim($( "#comment" ).val());
- if (_prev.length > 0){
- _prev += "\n\n";
- }
- $( "#comment" ).val(_prev + _output.join("\n"));
- }
- ).click(function(){
- $('html, body').animate({
- scrollTop: $("#comment").offset().top
- }, 2000);
- });
- };
- function color_tags() {
- $(".badge-tag").each(function(ind, obj) {
- $(obj).css('background-color', $(obj).attr('data-bg-color'));
- });
- }
- $(document).ready(function() {
- var cur_hash = null;
- highlight_comment = function() {
- var _hash = window.location.hash;
- if (_hash != cur_hash) {
- $( cur_hash ).css(
- "background", "linear-gradient(to bottom, #ededed 0%, #fff 100%)"
- );
- };
- cur_hash = _hash;
- if ( _hash ) {
- $( _hash ).css(
- "background", "linear-gradient(to bottom, #eded98 0%, #fff 100%)"
- );
- };
- return false;
- };
- {% if g.repo_user %}
- $('#closeticket').click(function(event){
- event.preventDefault();
- var closeForm = $('<form>', {
- 'method': 'POST',
- 'action': '{{
- url_for('ui_ns.delete_issue',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- issueid=issueid) }}',
- }).append($('<input>', {
- 'name': 'csrf_token',
- 'value': '{{ form.csrf_token.current_token }}',
- 'type': 'hidden'
- })).appendTo('body');
- if (confirm('Are you sure to delete this ticket? \nThis is final and cannot be un-done.')){
- closeForm.submit();
- }
- return false;
- });
- {% endif %}
- $(window.onload=highlight_comment());
- $(window).on('hashchange', highlight_comment);
- cancel_edit_btn();
- setup_edit_btns();
- setup_reply_btns();
- color_tags();
- });
- </script>
- {% if config['EVENTSOURCE_SOURCE'] and not issue.private %}
- <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
- url_for('static', filename='issue_ev.js') }}?version={{ g.version}}"></script>
- {% endif %}
- <script type="text/javascript" nonce="{{ g.nonce }}">
- var source = null;
- var sse = true;
- {% if config['EVENTSOURCE_SOURCE'] and not issue.private %}
- if (!!window.EventSource) {
- source = new EventSource('{{ config["EVENTSOURCE_SOURCE"]
- + request.script_root + request.path }}');
- source.addEventListener('error', function(e) {
- sse = false;
- }, false);
- }
- window.onbeforeunload = function() {
- source.close()
- };
- source.addEventListener('message', function(e) {
- console.log(e.data);
- var data = $.parseJSON(e.data);
- var _issues_url ='{{
- url_for('ui_ns.view_issues',
- repo=repo.name,
- username=username,
- namespace=repo.namespace)}}';
- var _api_issues_url ='{{
- url_for('api_ns.api_view_issue',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- issueid='-123456789')}}';
- var _issue_url ='{{
- url_for('ui_ns.view_issue',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- issueid='-123456789')}}';
- var _roadmap_url ='{{
- url_for('ui_ns.view_roadmap',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- milestone='-123456789')}}';
- process_event(data, "{{ issue.uid }}", _issue_url,
- _issues_url, _api_issues_url, _roadmap_url,
- "{{ g.fas_user.username if g.authenticated or '' }}");
- setup_edit_btns();
- setup_reply_btns();
- }, false);
- {% else %}
- sse = false;
- {% endif %}
- {% if g.authenticated and form %}
- function set_ui_for_comment(setting){
- if (setting == false) {
- $(document.body).find('input[type="submit"]').removeAttr("disabled");
- document.body.style.cursor = 'default';
- } else {
- $(document.body).find('input[type="submit"]').attr("disabled", "disabled");
- document.body.style.cursor = 'wait';
- }
- }
- function try_async_comment(form) {
- console.log('Submitting form:');
- console.log(form);
- set_ui_for_comment(true);
- var _data = $(form).serialize();
- var btn = $(document.activeElement);
- if (btn[0].name == 'drop_comment'){
- _data += '&drop_comment=' + btn[0].value;
- set_ui_for_comment(false);
- return true;
- }
- if (!sse || source.readyState != 1) {
- $(form).off('submit');
- form.submit();
- return false;
- }
- var _url = form.attr("action") + "?js=1";
- $.post( _url, _data )
- .done(function(data) {
- if(data == 'ok') {
- {# The event-source server will automatically refresh the UI #}
- $('#comment').val('');
- $('#preview').html('');
- $('#previewinmarkdown').addClass('inactive');
- $('#previewinmarkdown').removeClass('active');
- $('#preview').hide();
- $('#comment').show();
- $('#comments').find('.comment_body').show();
- $('#comments').find('.edit_comment').remove();
- $( ".issue-metadata-form" ).hide();
- $( ".issue-metadata-display" ).show();
- set_ui_for_comment(false);
- } else {
- // Make the browser submit the form sync
- $(form).off('submit');
- form.submit();
- }
- })
- .fail(function() {
- // Make the browser submit the form sync
- $(form).off('submit');
- form.submit();
- })
- return false;
- };
- {% endif %}
- </script>
- <script type="text/javascript" nonce="{{ g.nonce }}">
- {% if g.authenticated and (g.repo_user or issue.user.user == g.fas_user.username or open_access) %}
- function take_issue(){
- var _url = "{{ url_for('api_ns.api_assign_issue',
- repo=repo.name, namespace=repo.namespace, username=username,
- issueid=issueid) }}";
- var _data = {assignee: "{{ g.fas_user.username }}"};
- $.post (_url, _data ).done(
- function(data) {
- var _user_url = '\n<div class="ml-2"><div class="mt-1">{{g.fas_user.username| avatar(size=24) | safe}} '
- + '<a href="{{ url_for("ui_ns.view_issues", repo=repo.name, username=username, namespace=repo.namespace) }}'
- + '?assignee={{ g.fas_user.username }}">'
- + '{{ g.fas_user.username }}</a>'
- + ' — <a id="drop-btn" title="drop the assignment of this issue" '
- + 'class="pointer">Drop</a></div></div>';
- $('#assignee_plain').html(_user_url);
- $('#assignee').val("{{ g.fas_user.username }}");
- setup_btn_take_drop();
- }
- ).fail(function() {
- alert( "An error occured, could not assign this ticket to you." );
- })
- return false;
- }
- {% endif %}
- {% if g.authenticated and (
- g.repo_user
- or issue.user.user == g.fas_user.username
- or issue.assignee.user == g.fas_user.username) %}
- function drop_issue(){
- var _url = "{{ url_for('api_ns.api_assign_issue',
- repo=repo.name, namespace=repo.namespace, username=username,
- issueid=issueid) }}";
- var _data = {assignee: ""};
- $.post( _url, _data ).done(
- function(data) {
- var _user_url = '<div class="ml-2">\n<span class="text-muted">None</span>'
- + ' — <a id="take-btn" title="assign this issue to you" '
- + 'class="pointer">Take</a></div>';
- $('#assignee_plain').html(_user_url);
- $('#assignee').val("");
- setup_btn_take_drop();
- }
- ).fail(function() {
- alert( "An error occured, could not drop the current assignee." );
- })
- return false;
- }
- {% endif %}
- function setup_btn_take_drop(){
- {% if g.authenticated and (g.repo_user or open_access) %}
- $("#take-btn").click(take_issue)
- {% endif %}
- {% if g.authenticated and (
- g.repo_user
- or issue.user.user == g.fas_user.username
- or issue.assignee.user == g.fas_user.username) %}
- $("#drop-btn").click(drop_issue);
- {% endif %}
- }
- $( document ).ready(function() {
- $(".close_status_dropdown_action").click(function(event){
- var status = "{{issue.status}}";
- if (status == "Open") {
- $("#changestatusform #statusform_status").val("Closed");
- $("#changestatusform #statusform_close_status").val($(this).attr("data-value"));
- } else {
- $("#changestatusform #statusform_status").val("Open");
- }
- $("#changestatusform #statusform_assignee").val($("#assignee").val());
- $("#changestatusform #statusform_tag").val($("#tag").val());
- $("#changestatusform #statusform_priority").val($("#priority").val());
- $("#changestatusform #statusform_milestone").val($("#milestone").val());
- $("#changestatusform #statusform_blocking").val($("#blocking").val());
- $("#changestatusform #statusform_depending").val($("#depending").val());
- {% if repo.issue_keys %}
- {% for field in repo.issue_keys %}
- $("#changestatusform #statusform_{{ field.name | replace(' ', '_') }}").val($("#{{ field.name | replace(' ', '_') }}").val());
- {% endfor %}
- {% endif %}
- $("#changestatusform").submit();
- });
- $(".comment_and_close_action").click(function(event){
- var status = "{{issue.status}}";
- if (status == "Open") {
- $(".mainform #status").val("Closed");
- $(".mainform #close_status").val($(this).attr("data-value"));
- } else {
- $(".mainform #status").val("Open");
- }
- $(".mainform").submit();
- });
- var emojiStrategy;
- $.getJSON(
- '{{ url_for("static", filename="vendor/emojione/emoji_strategy.json") }}',
- function( data ) {
- emojiStrategy = data;
- }
- );
- var folder = '{{url_for("static", filename="emoji/png/") }}?version={{ g.version}}';
- var json_url = '{{ url_for("static", filename="vendor/emojione/emoji_strategy.json") }}?version={{ g.version}}';
- emoji_complete(json_url, folder);
- $(".comment_body").each(function(ind, obj) {
- var source = $(obj).html();
- var preview = emojione.toImage(source);
- $(obj).html(preview);
- });
- $( ".editmetadatatoggle" ).click(
- function() {
- $( ".issue-metadata-form" ).toggle();
- $( ".issue-metadata-display" ).toggle();
- }
- );
- function _get_issues(url, callback){
- $.getJSON(
- url,
- function( data ) {
- issues = data.issues.filter(function(el) {
- return el.id !== {{issue.id}};
- });
- callback(issues);
- if (data.pagination.next){
- _get_issues(data.pagination.next, callback)
- }
- }
- );
- }
- $('.mainform #blocking').selectize({
- plugins: ['remove_button'],
- valueField: 'id',
- labelField: 'id',
- searchField: ['id', 'title'],
- preload: 'focus',
- render: {
- option: function(item, escape) {
- return '<div><span>'+escape(item.id)+'</span> <span>'+escape(item.title)+'</span></div>';
- },
- item: function(item, escape) {
- return '<div><span>#'+escape(item.id)+'</span></div>';
- },
- },
- create: false,
- load: function(query, callback) {
- if (!query){
- callback();
- return;
- };
- var _url = "{{ url_for('api_ns.api_view_issues',
- repo=repo.name,
- username=username,
- namespace=repo.namespace) }}" + "?query_id=" + query;
- _get_issues(_url, callback);
- }
- });
- $('.mainform #depending').selectize({
- plugins: ['remove_button'],
- valueField: 'id',
- labelField: 'id',
- searchField: ['id', 'title'],
- preload: 'focus',
- render: {
- option: function(item, escape) {
- return '<div><span>'+escape(item.id)+'</span> <span>'+escape(item.title)+'</span></div>';
- },
- item: function(item, escape) {
- return '<div><span>#'+escape(item.id)+'</span></div>';
- },
- },
- create: false,
- load: function(query, callback) {
- if (!query){
- callback();
- return;
- };
- var _url = "{{ url_for('api_ns.api_view_issues',
- repo=repo.name,
- username=username,
- namespace=repo.namespace) }}" + "?query_id=" + query;
- _get_issues(_url, callback);
- }
- });
- var available_tags = [];
- {%for tog in tag_list %}
- available_tags.push("{{tog.tag}}");
- {%endfor%}
- var items = available_tags.map(function(x) { return { item: x }; });
- $('.mainform #tag').selectize({
- delimiter: ',',
- options: items,
- persist: false,
- create: false,
- labelField: "item",
- valueField: "item",
- searchField: ["item"],
- });
- $( "#preview" ).hide();
- $( "#previewinmarkdown" ).click(
- function(event, ui) {
- var _text = $( "#comment" ).val();
- var _url = "{{ url_for('ui_ns.markdown_preview',
- repo=repo.name,
- user=repo.user.user if repo.is_fork,
- namespace=repo.namespace) | safe}}";
- $.ajax({
- url: _url ,
- type: 'POST',
- data: {
- content: _text,
- csrf_token: "{{ g.confirmationform.csrf_token.current_token }}",
- },
- dataType: 'html',
- success: function(res) {
- var preview = emojione.toImage(res);
- $( "#preview" ).html(preview);
- $( "#previewinmarkdown" ).addClass("active");
- $( "#editinmarkdown" ).removeClass("active");
- $( "#comment" ).hide();
- $( "#preview" ).show();
- },
- error: function() {
- alert('Unable to generate preview!'+error);
- }
- });
- return false;
- }
- );
- $( "#editinmarkdown" ).click(
- function(event, ui) {
- $( "#editinmarkdown" ).addClass("active");
- $( "#previewinmarkdown" ).removeClass("active");
- $( "#comment" ).show();
- $( "#preview" ).hide();
- }
- );
- function submitFormOnCtrlKey(event) {
- if (event.ctrlKey && event.keyCode == 13) {
- var form = event.target.form;
- form.submit();
- event.preventDefault();
- }
- }
- $('#comment').keydown(function(e) {
- submitFormOnCtrlKey(e);
- });
- {% if g.authenticated and (
- g.repo_user
- or open_access
- or issue.user.user == g.fas_user.username
- or issue.assignee.user == g.fas_user.username) %}
- setup_btn_take_drop();
- {% endif %}
- {% if g.authenticated %}
- function set_up_subcribed() {
- $("#subcribe-btn").click(function(){
- var _url = "{{ url_for(
- 'api_ns.api_subscribe_issue',
- repo=repo.name,
- username=username,
- namespace=repo.namespace,
- issueid=issueid
- ) }}";
- var _btn = $("#subcribe-btn");
- var _data = {};
- if (_btn.text() == 'Unsubscribe'){
- _data.status = false;
- } else {
- _data.status = true;
- }
- $.post( _url, _data ).done(
- function(data) {
- var _btn = $("#subcribe-btn");
- var _countlabel = $("#subscribers-count")
- var _count = parseInt(_countlabel.text())
- if (_btn.text() == 'Subscribe'){
- _btn.text('Unsubscribe');
- _countlabel.text(_count+1)
- var _html = '<a href="/user/' + data.user + '"'
- + 'title="'+data.user+'" id="sub-avatar-'+data.user+'">'
- + '<img src="'+data.avatar_url+'" class="pb-1"></a>';
- $('#subscribers_list').prepend(_html);
- } else {
- _btn.text('Subscribe');
- _countlabel.text(_count-1);
- $('#sub-avatar-'+data.user).remove();
- }
- return false;
- }
- )
- return false;
- });
- };
- set_up_subcribed();
- {% endif %}
- });
- </script>
- {% if repo.quick_replies %}
- <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
- url_for('static', filename='quick_reply.js') }}?version={{ g.version}}"></script>
- {% endif %}
- <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
- url_for('static', filename='reactions.js') }}?version={{ g.version}}"></script>
- {% endblock %}
|