mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-09-12 21:58:57 +02:00
"Report an issue" in the navbar read like a way to report an anonymized
repository, and it opened a blank GitHub issue instead of the template
that asks reporters to confirm the issue is about the service. The user
menu offered "Default settings" and "Logout" with no hint of what lives
behind them, and the Claim page was unreachable from any menu.
The settings page never loaded quotas (the bars stayed in their striped
loading state), mixed serif checkbox labels with sans forms, used
Bootstrap alert colours, and described options in jargon ("Proxy mode",
"Github page", "Line of code").
- Navbar: "Report a bug" links to the issue template with a tooltip that
names the service; the user menu shows who is signed in and lists
Settings, Claim an anonymization, Report a bug, Source code, Sign out,
each with a one-line hint. Icon links get aria-labels.
- Settings: quotas load through a shared quotaService (also used by the
dashboard); sections match the side navigation, which now follows
scrolling via a small paperScrollspy directive; copy explains each
option; account card with Sign out; delete moved into a danger zone;
Save shows Saving/Saved and the error alert uses the paper palette.
- Conferences list and detail: sort and status buttons show their state,
hidden statuses appear as chips with a count line, Remove is a button
behind a divider, dates spell the month, expiry column matches the
dashboard, detail page gets an Edit button and plan/cost meta.
- New conference: validation errors only appear after a field is touched
or the form submitted; pricing copy matches how price is computed.
- Status page: progress label no longer overlaps the details below it;
"Report a bug" points at the template and says whom it is for.
- Claim: single rule, constrained width, explains when to use it.
- Anonymize: shorter placeholder, consistent Auto-update label.
- Mock server gains the endpoints these pages need and an ANON mode.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
478 lines
28 KiB
HTML
478 lines
28 KiB
HTML
<div class="anonymize-page h-100">
|
|
<!-- ===== STATE 1: No URL — centered input ===== -->
|
|
<div class="anonymize-landing" ng-hide="sourceUrl">
|
|
<div class="anonymize-landing-inner">
|
|
<div class="paper-crumbs">My work / <span class="here">New anonymization</span></div>
|
|
<h1 class="paper-page-title">New <em>anonymization</em></h1>
|
|
<p class="paper-page-lede">
|
|
Paste a GitHub repository, pull-request, or gist URL. We’ll fetch
|
|
it, strip every trace of identity, and hand you back a stable link.
|
|
</p>
|
|
<div class="form-group mt-4 mb-2">
|
|
<label class="paper-field-label" for="sourceUrl-landing">Source URL</label>
|
|
<input
|
|
id="sourceUrl-landing"
|
|
type="text"
|
|
class="form-control form-control-lg"
|
|
ng-model="sourceUrl"
|
|
placeholder="https://github.com/owner/repository"
|
|
ng-model-options="{ debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }"
|
|
ng-change="urlSelected()"
|
|
/>
|
|
</div>
|
|
<small class="form-text" style="color: var(--ink-muted);">
|
|
Repository, pull request (…/pull/42) and gist (gist.github.com/…) URLs are all accepted.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ===== STATE 2: URL provided — form (left) + preview (right) ===== -->
|
|
<div class="anonymize-workspace" ng-show="sourceUrl">
|
|
<header class="anonymize-topbar">
|
|
<div class="anonymize-topbar-inner">
|
|
<div class="paper-crumbs">
|
|
<a href="/dashboard">My work</a> /
|
|
<span class="here">{{ isUpdate ? 'Edit anonymization' : 'New anonymization' }}</span>
|
|
</div>
|
|
<div class="anonymize-topbar-head">
|
|
<h1 class="paper-page-title anonymize-topbar-title">
|
|
<span ng-if="!isUpdate">New <em>anonymization</em></span>
|
|
<span ng-if="isUpdate">Edit <em>anonymization</em></span>
|
|
</h1>
|
|
<span class="type-badge" ng-show="detectedType" ng-class="{'type-repo': detectedType === 'repo', 'type-pr': detectedType === 'pr', 'type-gist': detectedType === 'gist'}">
|
|
{{detectedType === 'repo' ? 'Repo' : detectedType === 'pr' ? 'PR' : 'Gist'}}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="anonymize-split">
|
|
<!-- Form column (left) -->
|
|
<div class="anonymize-form-col overflow-auto">
|
|
<form class="form needs-validation paper-settings-main" name="anonymize" novalidate>
|
|
|
|
<section class="paper-settings-section">
|
|
<div class="paper-section-eyebrow">Source</div>
|
|
|
|
<div class="form-group">
|
|
<label class="paper-field-label" for="sourceUrl">GitHub URL</label>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
name="sourceUrl"
|
|
id="sourceUrl"
|
|
ng-class="{'is-invalid': anonymize.sourceUrl.$invalid}"
|
|
ng-model="sourceUrl"
|
|
placeholder="Paste a GitHub repo or pull request URL"
|
|
ng-model-options="{ debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }"
|
|
ng-change="urlSelected()"
|
|
/>
|
|
<div class="invalid-feedback" ng-show="anonymize.sourceUrl.$error.github">
|
|
Please provide a valid GitHub URL.
|
|
</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.sourceUrl.$error.access">
|
|
Not accessible. The organization may restrict access.
|
|
</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.sourceUrl.$error.missing">
|
|
Does not exist or is not accessible.
|
|
</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.sourceUrl.$error.used">
|
|
Already anonymized.
|
|
</div>
|
|
</div>
|
|
|
|
<div ng-show="detectedType === 'repo'" class="form-grid-2">
|
|
<div class="form-group">
|
|
<label class="paper-field-label" for="branch">Branch</label>
|
|
<div class="input-group">
|
|
<select class="form-control" id="branch" name="branch" ng-model="source.branch">
|
|
<option ng-repeat="b in branches" ng-bind="b.name" value="{{b.name}}"></option>
|
|
</select>
|
|
<div class="input-group-append">
|
|
<button class="btn" type="button" ng-click="getBranches(true)" title="Refresh" data-toggle="tooltip" data-placement="bottom">
|
|
<i class="fas fa-sync" aria-hidden="true"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="paper-field-label" for="commit">Commit</label>
|
|
<input class="form-control" id="commit" name="commit" pattern="[a-fA-Z0-9]{6,}" ng-model="source.commit" required ng-class="{'is-invalid': anonymize.commit.$invalid}" />
|
|
<div class="invalid-feedback" ng-show="anonymize.commit.$error.pattern || anonymize.commit.$error.required">
|
|
The commit SHA is not valid.
|
|
</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.commit.$error.exists">
|
|
This commit no longer exists in the repository. Click refresh to get the latest.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-check" ng-show="detectedType">
|
|
<input class="form-check-input" type="checkbox" id="update" name="update" ng-model="options.update" />
|
|
<label class="form-check-label" for="update">Auto-update from GitHub</label>
|
|
<small class="form-text text-muted">Follow the branch and pull the latest commit automatically, at most once an hour.</small>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="paper-settings-section" ng-show="detectedType">
|
|
<div class="paper-section-eyebrow">Identity</div>
|
|
|
|
<div class="form-group" ng-show="detectedType === 'repo'">
|
|
<label class="paper-field-label" for="repoId">Anonymized repository ID</label>
|
|
<input type="text" class="form-control" name="repoId" id="repoId" ng-class="{'is-invalid': anonymize.repoId.$invalid}" ng-model="repoId" ng-model-options="{ debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }" />
|
|
<small class="form-text text-muted">Your share link will be <code>anonymous.4open.science/r/{{repoId}}</code>.</small>
|
|
<div class="invalid-feedback" ng-show="anonymize.repoId.$error.format">ID can only contain letters and numbers.</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.repoId.$error.used">{{repoId}} is already used.</div>
|
|
</div>
|
|
|
|
<div class="form-group" ng-show="detectedType === 'pr'">
|
|
<label class="paper-field-label" for="pullRequestId">Anonymized pull request ID</label>
|
|
<input type="text" class="form-control" name="pullRequestId" id="pullRequestId" ng-class="{'is-invalid': anonymize.pullRequestId.$invalid}" ng-model="pullRequestId" ng-model-options="{ debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }" />
|
|
<small class="form-text text-muted">Your share link will be <code>anonymous.4open.science/pr/{{pullRequestId}}</code>.</small>
|
|
<div class="invalid-feedback" ng-show="anonymize.pullRequestId.$error.format">ID can only contain letters and numbers.</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.pullRequestId.$error.used">{{pullRequestId}} is already used.</div>
|
|
</div>
|
|
|
|
<div class="form-group" ng-show="detectedType === 'gist'">
|
|
<label class="paper-field-label" for="gistId">Anonymized gist ID</label>
|
|
<input type="text" class="form-control" name="gistId" id="gistId" ng-class="{'is-invalid': anonymize.gistId.$invalid}" ng-model="gistId" ng-model-options="{ debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }" />
|
|
<small class="form-text text-muted">Your share link will be <code>anonymous.4open.science/gist/{{gistId}}</code>.</small>
|
|
<div class="invalid-feedback" ng-show="anonymize.gistId.$error.format">ID can only contain letters and numbers.</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.gistId.$error.used">{{gistId}} is already used.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="paper-field-label" for="conference">Conference <span class="paper-optional">(optional)</span></label>
|
|
<input class="form-control" id="conference" name="conference" ng-model="conference" ng-model-options="{ debounce: { default: 800, blur: 0 }, updateOn: 'default blur' }" ng-class="{'is-invalid': anonymize.conference.$invalid}" />
|
|
<small class="form-text text-muted" ng-show="conference_data">
|
|
<a ng-href="{{conference_data.url}}" target="_blank">{{conference_data.name}}</a> expires {{conference_data.endDate | date}}.
|
|
</small>
|
|
<div class="invalid-feedback" ng-show="anonymize.conference.$error.activated">The conference is not activated.</div>
|
|
<small class="form-text text-muted" ng-show="!conference_data">Link to a conference to apply its shared defaults.</small>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="paper-settings-section" ng-show="detectedType">
|
|
<div class="paper-section-eyebrow">Anonymization</div>
|
|
|
|
<div class="form-group">
|
|
<label class="paper-field-label" for="terms">Terms to redact</label>
|
|
<textarea class="form-control" id="terms" name="terms" rows="4" ng-model="terms" ng-model-options="{ debounce: 250 }" ng-class="{'is-invalid': anonymize.terms.$invalid}"></textarea>
|
|
<small class="form-text text-muted">One term per line (regex allowed). Replaced by <code>{{site_options.ANONYMIZATION_MASK}}-[N]</code>, or use <code>term=>replacement</code> to pick your own (e.g. <code>Anonymous=>ABC</code>).</small>
|
|
<div class="warning-feedback" ng-show="termsRegexWarning">Regex characters detected. Escape them if unintentional.</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.terms.$error.format">Terms are in an invalid format.</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="paper-settings-section" ng-show="detectedType">
|
|
<div class="paper-section-eyebrow">Display</div>
|
|
|
|
<div ng-show="detectedType === 'repo'">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="link" name="link" ng-model="options.link" />
|
|
<label class="form-check-label" for="link">Keep links</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="image" name="image" ng-model="options.image" />
|
|
<label class="form-check-label" for="image">Display images</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="pdf" name="pdf" ng-model="options.pdf" />
|
|
<label class="form-check-label" for="pdf">Display PDFs</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="notebook" name="notebook" ng-model="options.notebook" />
|
|
<label class="form-check-label" for="notebook">Display Notebooks</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="page" name="page" ng-model="options.page" ng-disabled="!details.hasPage || (details.pageSource && details.pageSource.branch !== source.branch)" />
|
|
<label class="form-check-label" for="page">GitHub Pages</label>
|
|
<small class="form-text text-muted d-block" ng-show="!details.hasPage">
|
|
{{ 'WARNINGS.page_not_enabled_on_repo' | translate }}
|
|
</small>
|
|
<small class="form-text text-muted d-block" ng-show="details.hasPage && details.pageSource && details.pageSource.branch !== source.branch">
|
|
{{ 'WARNINGS.page_branch_mismatch' | translate:{ pageBranch: details.pageSource.branch, selectedBranch: source.branch } }}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div ng-show="detectedType === 'gist'">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="title-gist" name="title-gist" ng-model="options.title" />
|
|
<label class="form-check-label" for="title-gist">Gist description</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="content-gist" name="content-gist" ng-model="options.content" />
|
|
<label class="form-check-label" for="content-gist">File contents</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="comments-gist" name="comments-gist" ng-model="options.comments" />
|
|
<label class="form-check-label" for="comments-gist">Comments</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="username-gist" name="username-gist" ng-model="options.username" />
|
|
<label class="form-check-label" for="username-gist">Usernames</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="date-gist" name="date-gist" ng-model="options.date" />
|
|
<label class="form-check-label" for="date-gist">Dates</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="origin-gist" name="origin-gist" ng-model="options.origin" />
|
|
<label class="form-check-label" for="origin-gist">Source gist ID</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div ng-show="detectedType === 'pr'">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="title" name="title" ng-model="options.title" />
|
|
<label class="form-check-label" for="title">PR title</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="body" name="body" ng-model="options.body" />
|
|
<label class="form-check-label" for="body">PR body</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="diff" name="diff" ng-model="options.diff" />
|
|
<label class="form-check-label" for="diff">Diff</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="comments" name="comments" ng-model="options.comments" />
|
|
<label class="form-check-label" for="comments">Comments</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="username" name="username" ng-model="options.username" />
|
|
<label class="form-check-label" for="username">Usernames</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="date" name="date" ng-model="options.date" />
|
|
<label class="form-check-label" for="date">Dates</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="origin" name="origin" ng-model="options.origin" />
|
|
<label class="form-check-label" for="origin">Project name</label>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="paper-settings-section" ng-show="detectedType">
|
|
<div class="paper-section-eyebrow">Expiration</div>
|
|
|
|
<div class="form-grid-2">
|
|
<div class="form-group">
|
|
<label class="paper-field-label" for="expiration">Strategy</label>
|
|
<select class="form-control" id="expiration" name="expiration" ng-model="options.expirationMode">
|
|
<option value="redirect">Redirect to GitHub when expired</option>
|
|
<option value="remove" selected>Remove when expired</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="paper-field-label" for="expirationDate">Expiration date</label>
|
|
<input class="form-control" type="date" name="expirationDate" id="expirationDate" ng-model="options.expirationDate" ng-class="{'is-invalid': anonymize.expirationDate.$invalid}" min="{{minExpirationDate}}" max="{{maxExpirationDate}}" required />
|
|
<div class="invalid-feedback" ng-show="anonymize.expirationDate.$error.min">Pick a date in the future.</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.expirationDate.$error.max">Pick a date on or before {{maxExpirationDate | date}}.</div>
|
|
<div class="invalid-feedback" ng-show="anonymize.expirationDate.$error.required || anonymize.expirationDate.$error.date">Enter a valid expiration date.</div>
|
|
</div>
|
|
</div>
|
|
<small class="form-text text-muted" ng-show="options.expirationMode=='remove' && options.expirationDate">After {{options.expirationDate | date}}, the content will be removed.</small>
|
|
<small class="form-text text-muted" ng-show="options.expirationMode=='redirect' && options.expirationDate">After {{options.expirationDate | date}}, visitors will be redirected to GitHub.</small>
|
|
</section>
|
|
|
|
<section class="paper-settings-section" ng-show="isUpdate && detectedType === 'repo'">
|
|
<div class="paper-section-eyebrow">Co-authors</div>
|
|
<p class="form-text text-muted" style="margin-bottom: 8px;">
|
|
Co-authors can view and edit these settings. They cannot delete the anonymization or manage co-authors.
|
|
</p>
|
|
|
|
<div class="form-group" ng-show="role === 'owner' || role === 'admin'">
|
|
<label class="paper-field-label" for="coauthorSearch">Add a GitHub user</label>
|
|
<div style="position: relative;">
|
|
<input
|
|
type="text"
|
|
id="coauthorSearch"
|
|
class="form-control"
|
|
placeholder="Search GitHub username…"
|
|
ng-model="coauthorSearch"
|
|
ng-change="searchCoauthors()"
|
|
ng-model-options="{ debounce: 300 }"
|
|
autocomplete="off"
|
|
/>
|
|
<div class="dropdown-menu show" style="display: block; max-height: 220px; overflow-y: auto; width: 100%;" ng-show="coauthorResults.length > 0">
|
|
<a href="#" class="dropdown-item d-flex align-items-center" ng-repeat="u in coauthorResults" ng-click="addCoauthor(u, $event)">
|
|
<img ng-src="{{u.photo}}" alt="" style="width: 22px; height: 22px; border-radius: 50%; margin-right: 8px;" />
|
|
<span ng-bind="u.username"></span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<small class="form-text text-muted" ng-show="coauthorError" ng-bind="coauthorError"></small>
|
|
</div>
|
|
|
|
<div class="coauthor-list">
|
|
<div class="coauthor-row d-flex align-items-center" ng-repeat="c in coauthors" style="padding: 6px 0; gap: 8px;">
|
|
<img ng-src="{{c.photo}}" alt="" style="width: 24px; height: 24px; border-radius: 50%;" ng-if="c.photo" />
|
|
<a ng-href="https://github.com/{{c.username}}" target="_blank" ng-bind="c.username"></a>
|
|
<span class="type-badge type-coauthor">Co-author</span>
|
|
<button type="button" class="btn btn-sm" ng-click="removeCoauthor(c)" ng-show="role === 'owner' || role === 'admin'" style="margin-left: auto;" title="Remove co-author">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<div class="form-text text-muted" ng-show="!coauthors || coauthors.length === 0">
|
|
No co-authors yet.
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="alert alert-danger" role="alert" ng-if="error" ng-bind="error"></div>
|
|
|
|
<div class="anonymize-submit-bar" ng-show="detectedType">
|
|
<button type="submit" class="btn btn-ink" ng-click="anonymizeRepo($event)" ng-if="detectedType === 'repo' && !isUpdate">
|
|
<i class="fas fa-user-secret mr-1"></i> Anonymize Repository
|
|
</button>
|
|
<button type="submit" class="btn btn-ink" ng-click="anonymizeRepo($event)" ng-if="detectedType === 'repo' && isUpdate">
|
|
<i class="fas fa-save mr-1"></i> Update Repository
|
|
</button>
|
|
<button type="submit" class="btn btn-ink" ng-click="anonymizePullRequest($event)" ng-if="detectedType === 'pr' && !isUpdate">
|
|
<i class="fas fa-user-secret mr-1"></i> Anonymize Pull Request
|
|
</button>
|
|
<button type="submit" class="btn btn-ink" ng-click="anonymizePullRequest($event)" ng-if="detectedType === 'pr' && isUpdate">
|
|
<i class="fas fa-save mr-1"></i> Update Pull Request
|
|
</button>
|
|
<button type="submit" class="btn btn-ink" ng-click="anonymizeGist($event)" ng-if="detectedType === 'gist' && !isUpdate">
|
|
<i class="fas fa-user-secret mr-1"></i> Anonymize Gist
|
|
</button>
|
|
<button type="submit" class="btn btn-ink" ng-click="anonymizeGist($event)" ng-if="detectedType === 'gist' && isUpdate">
|
|
<i class="fas fa-save mr-1"></i> Update Gist
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Preview column (right) -->
|
|
<div
|
|
class="anonymize-preview-col"
|
|
ng-if="detectedType === 'repo' && html_readme"
|
|
>
|
|
<div class="anonymize-preview-head">
|
|
<span class="paper-eyebrow">Live preview</span>
|
|
<span class="anonymize-preview-sub">README with redactions applied</span>
|
|
</div>
|
|
<div class="anonymize-preview-body markdown-body body" ng-bind-html="html_readme"></div>
|
|
</div>
|
|
|
|
<div class="anonymize-preview-col" ng-if="detectedType === 'gist' && details">
|
|
<div class="anonymize-preview-head">
|
|
<span class="paper-eyebrow">Live preview</span>
|
|
<span class="anonymize-preview-sub">Gist with redactions applied</span>
|
|
</div>
|
|
<div class="anonymize-preview-body">
|
|
<div class="d-flex w-100 justify-content-between align-items-center flex-wrap">
|
|
<h2 class="pr-title mb-1">
|
|
<span ng-if="options.title">{{anonymizeGistContent(details.gist.description) || 'Untitled gist'}}</span>
|
|
<span class="badge" ng-class="{'badge-success': details.gist.isPublic, 'badge-secondary': !details.gist.isPublic}">
|
|
{{details.gist.isPublic ? 'public' : 'secret'}}
|
|
</span>
|
|
</h2>
|
|
<small ng-bind="details.gist.updatedDate | date" ng-if="options.date"></small>
|
|
</div>
|
|
<small ng-if="options.origin">Gist ID: {{details.source.gistId}}</small>
|
|
<small ng-if="options.username && details.gist.ownerLogin">By @{{anonymizeGistContent(details.gist.ownerLogin)}}</small>
|
|
<div ng-if="options.content && previewGistFiles.length">
|
|
<ul class="pr-comments mt-3">
|
|
<li class="pr-comment" ng-repeat="file in previewGistFiles">
|
|
<div class="pr-comment-head">
|
|
<strong ng-bind="file.filename"></strong>
|
|
<span class="pr-comment-date" ng-if="file.language">{{file.language}}</span>
|
|
</div>
|
|
<gist-file file="file" terms="terms" options="options"></gist-file>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div ng-if="options.comments && details.gist.comments && details.gist.comments.length">
|
|
<h3 class="paper-section-eyebrow mt-3">Comments</h3>
|
|
<ul class="pr-comments">
|
|
<li class="pr-comment" ng-repeat="comment in details.gist.comments">
|
|
<div class="pr-comment-head">
|
|
<span class="pr-comment-author" ng-if="options.username">
|
|
<i class="far fa-user"></i> @<span ng-bind="anonymizeGistContent(comment.author)"></span>
|
|
</span>
|
|
<span class="pr-comment-date" ng-if="options.date" ng-bind="comment.updatedDate | date"></span>
|
|
</div>
|
|
<div class="pr-comment-body" ng-if="options.body">
|
|
<markdown content="anonymizeGistContent(comment.body)" options="options" terms="terms"></markdown>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="anonymize-preview-col" ng-if="detectedType === 'pr' && details"
|
|
ng-init="prTabState = { active: options.diff ? 'diff' : 'comments' }">
|
|
<div class="anonymize-preview-head">
|
|
<span class="paper-eyebrow">Live preview</span>
|
|
<span class="anonymize-preview-sub">Pull request with redactions applied</span>
|
|
</div>
|
|
<div class="anonymize-preview-body">
|
|
<div class="d-flex w-100 justify-content-between align-items-center flex-wrap">
|
|
<h2 class="pr-title mb-1">
|
|
<span ng-if="options.title">{{anonymizePrContent(details.pullRequest.title)}}</span>
|
|
<span class="badge" ng-class="{'badge-success':details.pullRequest.merged, 'badge-warning':details.pullRequest.state=='open', 'badge-danger':details.pullRequest.state=='closed' && !details.pullRequest.merged}">
|
|
{{details.pullRequest.merged ? "merged" : details.pullRequest.state | title}}
|
|
</span>
|
|
</h2>
|
|
<small ng-bind="details.pullRequest.updatedDate | date" ng-if="options.date"></small>
|
|
</div>
|
|
<small ng-if="options.origin">Pull Request on {{details.pullRequest.baseRepositoryFullName}}</small>
|
|
<div class="pr-body shadow-sm p-3 mb-4 rounded" style="background: var(--paper-bg-alt)" ng-if="options.body">
|
|
<markdown content="anonymizePrContent(details.pullRequest.body)" options="options" terms="terms"></markdown>
|
|
</div>
|
|
<nav class="paper-tabs" ng-if="options.diff || options.comments" role="tablist">
|
|
<button
|
|
class="paper-tab"
|
|
ng-if="options.diff"
|
|
ng-class="{'active': prTabState.active == 'diff'}"
|
|
ng-click="prTabState.active = 'diff'"
|
|
type="button"
|
|
role="tab"
|
|
>
|
|
<i class="fas fa-code"></i> Diff
|
|
</button>
|
|
<button
|
|
class="paper-tab"
|
|
ng-if="options.comments"
|
|
ng-class="{'active': prTabState.active == 'comments'}"
|
|
ng-click="prTabState.active = 'comments'"
|
|
type="button"
|
|
role="tab"
|
|
>
|
|
<i class="far fa-comment-dots"></i>
|
|
<ng-pluralize count="details.pullRequest.comments.length" when="{'0': 'No comments', 'one': '1 comment', 'other': '{} comments'}"></ng-pluralize>
|
|
</button>
|
|
</nav>
|
|
<div class="paper-tab-content">
|
|
<div ng-if="options.diff && prTabState.active == 'diff'">
|
|
<div class="pr-diff" ng-bind-html="anonymizePrContent(details.pullRequest.diff) | diff"></div>
|
|
</div>
|
|
<div ng-if="options.comments && prTabState.active == 'comments'">
|
|
<ul class="pr-comments">
|
|
<li class="pr-comment" ng-repeat="comment in details.pullRequest.comments">
|
|
<div class="pr-comment-head">
|
|
<span class="pr-comment-author" ng-if="options.username">
|
|
<i class="far fa-user"></i> @<span ng-bind="anonymizePrContent(comment.author)"></span>
|
|
</span>
|
|
<span class="pr-comment-date" ng-if="options.date" ng-bind="comment.updatedDate | date"></span>
|
|
</div>
|
|
<div class="pr-comment-body" ng-if="options.body">
|
|
<markdown content="anonymizePrContent(comment.body)" options="options" terms="terms"></markdown>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|