mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-10-21 23:11:39 +02:00
fix: make dashboard UI consistent and compact on mobile
This commit is contained in:
1 parent
adc9dbd439
commit
282efdc16e
52 files changed
+2177
-712
No files matched your search
+103
-79
@@ -1,64 +1,59 @@
|
||||
<div class="container page dashboard-page paper-page">
|
||||
<div class="row">
|
||||
<div class="w-100">
|
||||
<div class="paper-crumbs">My work / <span class="here">Dashboard</span></div>
|
||||
<div class="d-flex align-items-end justify-content-between flex-wrap" style="gap: 12px;">
|
||||
<div class="dashboard-heading">
|
||||
<div>
|
||||
<h1 class="paper-page-title">Your <em>anonymizations</em></h1>
|
||||
<p class="paper-page-lede">Every repository, pull request, and gist you’ve mirrored, with live status and stats.</p>
|
||||
<h1 class="paper-page-title">Projects</h1>
|
||||
<p class="paper-page-lede">Manage your anonymous links.</p>
|
||||
<details class="dashboard-quota" :open="quotaExpanded" @toggle="quotaExpanded = $event.target.open" @keydown.esc.prevent.stop="closeQuota()">
|
||||
<summary aria-controls="dashboard-usage" :aria-expanded="quotaExpanded">
|
||||
<svg class="quota-summary-ring" viewBox="0 0 24 24" aria-hidden="true" :class="quota ? 'quota-' + quota.repository.level : ''">
|
||||
<circle class="quota-ring-track" cx="12" cy="12" r="9"></circle>
|
||||
<circle class="quota-ring-fill" cx="12" cy="12" r="9" pathLength="100" v-if="quota && !quota.repository.unlimited" :stroke-dasharray="quota.repository.percent + ' 100'"></circle>
|
||||
<path v-if="quota?.repository.unlimited" d="M7 12c0-4 4-4 5 0s5 4 5 0-4-4-5 0-5 4-5 0" class="quota-ring-unlimited"></path>
|
||||
</svg>
|
||||
<span class="quota-summary-label">Usage</span>
|
||||
<span class="quota-summary-value" v-if="quota">{{ fmt.number(quota.repository.used) }}<span v-if="!quota.repository.unlimited"> / {{ fmt.number(quota.repository.total) }}</span> repos</span>
|
||||
<svg class="project-type-svg quota-summary-chevron" aria-hidden="true"><use href="#project-icon-chevron"></use></svg>
|
||||
</summary>
|
||||
<div class="quota-panel" id="dashboard-usage">
|
||||
<div class="quota-panel-heading"><h2>Account usage</h2><button type="button" class="project-close" aria-label="Close usage" @click="closeQuota()"><svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-close"></use></svg></button></div>
|
||||
<quota-usage :quota="quota" :fmt="fmt" v-if="quota"></quota-usage>
|
||||
<p class="quota-loading" role="status" v-else>Loading usage…</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="dashboard-heading-actions">
|
||||
<a href="/anonymize" class="btn btn-ink">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> New anonymization
|
||||
<a href="/anonymize" class="btn btn-ink" aria-label="New anonymization">
|
||||
<svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-plus"></use></svg><span class="dashboard-new-label">New link</span><span class="dashboard-new-mobile" aria-hidden="true">New</span>
|
||||
</a>
|
||||
<a href="/connections" class="dashboard-connections-link">
|
||||
<i class="fab fa-github" aria-hidden="true"></i> GitHub connections <span aria-hidden="true">→</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quota -->
|
||||
<div class="quota-row" v-if="quota">
|
||||
<div class="quota-item" v-for="(q, index) in [
|
||||
{key: 'repository', label: 'Repositories', kind: 'count'},
|
||||
{key: 'storage', label: 'Storage', kind: 'bytes'},
|
||||
{key: 'file', label: 'Files', kind: 'count'}
|
||||
]">
|
||||
<div class="quota-header">
|
||||
<span class="quota-label">{{ q?.label }}</span>
|
||||
<span class="quota-value" v-if="q?.kind === 'count'">
|
||||
{{ fmt?.number(quota[q?.key].used) }}<span v-if="!quota[q?.key].unlimited"> / {{ fmt?.number(quota[q?.key].total) }}</span>
|
||||
<span class="quota-unlimited-tag" v-if="quota[q?.key].unlimited">Unlimited</span>
|
||||
</span>
|
||||
<span class="quota-value" v-if="q?.kind === 'bytes'">
|
||||
{{ fmt?.humanFileSize(quota[q?.key].used) }}<span v-if="!quota[q?.key].unlimited"> / {{ fmt?.humanFileSize(quota[q?.key].total) }}</span>
|
||||
<span class="quota-unlimited-tag" v-if="quota[q?.key].unlimited">Unlimited</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="quota-track" role="progressbar" aria-valuemin="0" :class="'quota-' + quota[q?.key].level" :aria-label="(q?.label) + " quota"" :aria-valuenow="(quota[q?.key].used)" :aria-valuemax="(quota[q?.key].unlimited ? quota[q?.key].used : quota[q?.key].total)" :aria-valuetext="(quota[q?.key].unlimited ? 'unlimited' : fmt.number(quota[q?.key].percent, 0) + '% used')">
|
||||
<div class="quota-fill" v-if="!quota[q?.key].unlimited" :style="{width: quota[q?.key].percent + '%'}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search + filters -->
|
||||
<form class="w-100 dashboard-filter-row" aria-label="Filter anonymizations" accept-charset="UTF-8" v-form="viewState" @submit.prevent="submitForm($event, () => { $event.preventDefault() })">
|
||||
<div class="search-wrap">
|
||||
<input type="search" id="search" class="form-control" aria-label="Search anonymizations" placeholder="Search by name, source, or conference…" autocomplete="off" v-field="{ state: viewState, set: value => { search = value }, value: search, form: null, options: {} }">
|
||||
<input type="search" id="search" class="form-control" aria-label="Search anonymizations" placeholder="Search projects, IDs, or conferences…" autocomplete="off" v-field="{ state: viewState, set: value => { search = value }, value: search, form: null, options: {} }">
|
||||
</div>
|
||||
<div class="dashboard-filter-controls">
|
||||
<button class="btn dashboard-filters-toggle" type="button" :aria-expanded="filtersExpanded" aria-controls="dashboard-filter-controls" @click="filtersExpanded = !filtersExpanded">Filters<svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-filter"></use></svg></button>
|
||||
<div id="dashboard-filter-controls" class="dashboard-filter-controls" :class="{'expanded': filtersExpanded}">
|
||||
<div class="btn-group" role="group" aria-label="Type">
|
||||
<button type="button" class="btn" :class="{'btn-primary': typeFilter === 'all'}" @click="typeFilter = 'all'" :aria-pressed="(typeFilter === 'all')">All</button>
|
||||
<button type="button" class="btn" :class="{'btn-primary': typeFilter === 'repo'}" @click="typeFilter = 'repo'" :aria-pressed="(typeFilter === 'repo')">Repos</button>
|
||||
<button type="button" class="btn" :class="{'btn-primary': typeFilter === 'pr'}" @click="typeFilter = 'pr'" :aria-pressed="(typeFilter === 'pr')">PRs</button>
|
||||
<button type="button" class="btn" :class="{'btn-primary': typeFilter === 'gist'}" @click="typeFilter = 'gist'" :aria-pressed="(typeFilter === 'gist')">Gists</button>
|
||||
<button type="button" class="btn dashboard-type-filter" title="Repositories" :class="{'btn-primary': typeFilter === 'repo'}" @click="typeFilter = 'repo'" :aria-pressed="(typeFilter === 'repo')"><svg class="project-type-svg" aria-hidden="true"><use href="#project-type-repo"></use></svg><span class="type-filter-label">Repos</span></button>
|
||||
<button type="button" class="btn dashboard-type-filter" title="Pull requests" :class="{'btn-primary': typeFilter === 'pr'}" @click="typeFilter = 'pr'" :aria-pressed="(typeFilter === 'pr')"><svg class="project-type-svg" aria-hidden="true"><use href="#project-type-pr"></use></svg><span class="type-filter-label">PRs</span></button>
|
||||
<button type="button" class="btn dashboard-type-filter" title="Gists" :class="{'btn-primary': typeFilter === 'gist'}" @click="typeFilter = 'gist'" :aria-pressed="(typeFilter === 'gist')"><svg class="project-type-svg" aria-hidden="true"><use href="#project-type-gist"></use></svg><span class="type-filter-label">Gists</span></button>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dashboard-extra-filters" class="dashboard-extra-filters" :class="{'expanded': filtersExpanded}">
|
||||
<div class="dropdown">
|
||||
<button class="btn dropdown-toggle" type="button" id="dropdownSort" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="filter-btn-label">Sort</span>
|
||||
<span class="filter-btn-value">{{ sortLabel() }}</span>
|
||||
<i class="fas" aria-hidden="true" :class="sortDesc() ? 'fa-arrow-down' : 'fa-arrow-up'"></i>
|
||||
<svg class="project-type-svg sort-direction" aria-hidden="true" :class="{'ascending': !sortDesc()}"><use href="#project-icon-arrow"></use></svg>
|
||||
<span class="sr-only">{{ sortDesc() ? 'descending' : 'ascending' }}</span>
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownSort">
|
||||
@@ -69,7 +64,6 @@
|
||||
</div>
|
||||
<div class="dropdown-divider"></div>
|
||||
<button type="button" class="dropdown-item" @click="toggleSortDirection()">
|
||||
<i class="fas fa-exchange-alt fa-rotate-90" aria-hidden="true"></i>
|
||||
{{ sortDesc() ? 'Switch to ascending' : 'Switch to descending' }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -90,43 +84,48 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Result count + active filter chips -->
|
||||
<div class="dashboard-meta" v-if="!loading">
|
||||
<div class="dashboard-view-tabs" role="group" aria-label="Project view">
|
||||
<button type="button" :aria-pressed="projectView === 'all'" @click="setProjectView('all')" aria-label="All projects"><span class="dashboard-view-long">All projects</span><span class="dashboard-view-short" aria-hidden="true">All</span></button>
|
||||
<button type="button" :aria-pressed="projectView === 'attention'" @click="setProjectView('attention')" :aria-label="'Needs attention ' + attentionCount()"><span class="dashboard-attention-prefix">Needs </span><span>attention</span> <span class="attention-count" :class="{'has-attention': attentionCount() > 0}">{{ attentionCount() }}</span></button>
|
||||
</div>
|
||||
<span class="dashboard-count">
|
||||
<span v-if="filteredItems?.length === items?.length">{{ fmt?.number(items?.length) }} anonymization<span v-if="items?.length !== 1">s</span></span>
|
||||
<span v-if="filteredItems?.length === items?.length">{{ fmt?.number(items?.length) }} project<span v-if="items?.length !== 1">s</span></span>
|
||||
<span v-if="filteredItems?.length !== items?.length">{{ fmt?.number(filteredItems?.length) }} of {{ fmt?.number(items?.length) }} shown</span>
|
||||
</span>
|
||||
<template v-for="(v, f, index) in filters?.status"><span class="filter-chip" v-if="v === false">
|
||||
Hiding {{ statusKeyLabels[f] }}
|
||||
<button type="button" class="filter-chip-close" @click="filters.status[f] = true;" :aria-label=""Show " + (statusKeyLabels[f]) + " again"">×</button>
|
||||
</span></template>
|
||||
<button type="button" class="btn-link-inline" v-if="hasActiveFilters()" @click="clearFilters()">Clear filters</button>
|
||||
<div class="dashboard-active-filters">
|
||||
<template v-for="(v, f, index) in filters?.status"><button type="button" class="filter-chip" v-if="v === false" @click="filters.status[f] = true" :aria-label="'Show ' + statusKeyLabels[f] + ' again'" :title="'Show ' + statusKeyLabels[f] + ' again'">{{ statusKeyLabels[f] }} hidden<svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-close"></use></svg></button></template>
|
||||
<button type="button" class="filter-chip" v-if="typeFilter !== 'all'" @click="typeFilter = 'all'" aria-label="Show all project types">{{ typeFilter === 'repo' ? 'Repositories' : typeFilter === 'pr' ? 'Pull requests' : 'Gists' }}<svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-close"></use></svg></button>
|
||||
<button type="button" class="btn-link-inline" v-if="showClearFilters()" @click="clearFilters()">Clear filters</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Table -->
|
||||
<div class="paper-table paper-table-dashboard w-100" role="table" aria-label="Anonymizations" :aria-busy="(loading)">
|
||||
<div class="paper-table paper-table-dashboard" role="table" aria-label="Anonymizations" :aria-busy="(loading)">
|
||||
<div class="paper-table-head" role="row">
|
||||
<div role="columnheader" :aria-sort="(isSortedBy('_name') ? (sortDesc() ? 'descending' : 'ascending') : 'none')">
|
||||
<button type="button" class="sortable" :class="{active: isSortedBy('_name')}" @click="setSort('_name')">
|
||||
Anonymization <i class="fas" aria-hidden="true" v-if="isSortedBy('_name')" :class="sortDesc() ? 'fa-arrow-down' : 'fa-arrow-up'"></i>
|
||||
<div role="columnheader" :aria-sort="(isSortedBy('_label') ? (sortDesc() ? 'descending' : 'ascending') : 'none')">
|
||||
<button type="button" class="sortable" :class="{active: isSortedBy('_label')}" @click="setSort('_label')">
|
||||
Project <svg class="project-type-svg sort-direction" aria-hidden="true" v-if="isSortedBy('_label')" :class="{'ascending': !sortDesc()}"><use href="#project-icon-arrow"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div role="columnheader" :aria-sort="(isSortedBy('status') ? (sortDesc() ? 'descending' : 'ascending') : 'none')">
|
||||
<button type="button" class="sortable" :class="{active: isSortedBy('status')}" @click="setSort('status')">
|
||||
Status <i class="fas" aria-hidden="true" v-if="isSortedBy('status')" :class="sortDesc() ? 'fa-arrow-down' : 'fa-arrow-up'"></i>
|
||||
Status <svg class="project-type-svg sort-direction" aria-hidden="true" v-if="isSortedBy('status')" :class="{'ascending': !sortDesc()}"><use href="#project-icon-arrow"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div role="columnheader" class="num" :aria-sort="(isSortedBy('pageView') ? (sortDesc() ? 'descending' : 'ascending') : 'none')">
|
||||
<button type="button" class="sortable" :class="{active: isSortedBy('pageView')}" @click="setSort('pageView')">
|
||||
Views <i class="fas" aria-hidden="true" v-if="isSortedBy('pageView')" :class="sortDesc() ? 'fa-arrow-down' : 'fa-arrow-up'"></i>
|
||||
Views <svg class="project-type-svg sort-direction" aria-hidden="true" v-if="isSortedBy('pageView')" :class="{'ascending': !sortDesc()}"><use href="#project-icon-arrow"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div role="columnheader" :aria-sort="(isSortedBy('options.expirationDate') ? (sortDesc() ? 'descending' : 'ascending') : 'none')">
|
||||
<button type="button" class="sortable" :class="{active: isSortedBy('options.expirationDate')}" @click="setSort('options.expirationDate')">
|
||||
Expires <i class="fas" aria-hidden="true" v-if="isSortedBy('options.expirationDate')" :class="sortDesc() ? 'fa-arrow-down' : 'fa-arrow-up'"></i>
|
||||
Expires <svg class="project-type-svg sort-direction" aria-hidden="true" v-if="isSortedBy('options.expirationDate')" :class="{'ascending': !sortDesc()}"><use href="#project-icon-arrow"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div role="columnheader"><span class="sr-only">Actions</span></div>
|
||||
@@ -143,27 +142,21 @@
|
||||
|
||||
<template v-for="(item, index) in filteredItems" :key="(item?._type + ':' + (item?._id || index))"><div class="paper-table-row" role="row" v-if="!loading" :class="{'repo-inactive': item?._statusKey == 'expired' || item?._statusKey == 'removed', 'repo-error': item?.status == 'error', 'row-clickable': !!item?._viewUrl}" @click="openItem(item, $event)">
|
||||
<div class="cell-anon" role="cell">
|
||||
<span class="type-badge" :class="{'type-repo': item?._type === 'repo', 'type-pr': item?._type === 'pr', 'type-gist': item?._type === 'gist'}">{{ item?._type === 'repo' ? 'Repo' : item?._type === 'pr' ? 'PR' : 'Gist' }}</span>
|
||||
<span class="project-type-icon" role="img" :aria-label="item?._type === 'repo' ? 'Repository' : item?._type === 'pr' ? 'Pull request' : 'Gist'" :title="item?._type === 'repo' ? 'Repository' : item?._type === 'pr' ? 'Pull request' : 'Gist'"><svg class="project-type-svg" aria-hidden="true"><use :href="'#project-type-' + item._type"></use></svg></span>
|
||||
<div class="anon-text">
|
||||
<div class="anon-title">
|
||||
<a class="repo-name" v-if="item?._viewUrl" v-text="item?._name" :href="safeUrl((item?._viewUrl))"></a>
|
||||
<span class="repo-name repo-name-static" v-if="!item?._viewUrl" v-text="item?._name"></span>
|
||||
<a class="repo-name" v-if="item?._viewUrl" :title="item._label" v-text="item?._label" :href="safeUrl((item?._viewUrl))"></a>
|
||||
<span class="repo-name repo-name-static" v-if="!item?._viewUrl" v-text="item?._label"></span>
|
||||
<span class="type-badge type-coauthor" title="You are a co-author on this anonymization" v-if="item?.role === 'coauthor'">Co-author</span>
|
||||
</div>
|
||||
<div class="anon-sub" v-if="!item?._broken || item?.conference">
|
||||
<span class="anon-source" v-if="item?._type === 'repo' && item?.source?.fullName && !item?._broken">
|
||||
<a target="_blank" rel="noopener" v-text="item?.source?.fullName" :href="safeUrl("https://github.com/" + (item?.source?.fullName) + "/")"></a><span v-if="item?.options?.update && item?.source?.branch"> · <a target="_blank" rel="noopener" v-text="item?.source?.branch" :href="safeUrl("https://github.com/" + (item?.source?.fullName) + "/tree/" + (item?.source?.branch))"></a></span><span v-if="item?.source?.commit"> · <a class="commit-hash" target="_blank" rel="noopener" :href="safeUrl("https://github.com/" + (item?.source?.fullName) + "/tree/" + (item?.source?.commit))">@{{ item?.source?.commit?.substring(0, 8) }}</a></span>
|
||||
</span>
|
||||
<span class="anon-source" v-if="item?._type === 'pr' && item?.source?.repositoryFullName && !item?._broken">
|
||||
<a target="_blank" rel="noopener" v-text="item?._source" :href="safeUrl("https://github.com/" + (item?.source?.repositoryFullName) + "/pull/" + (item?.source?.pullRequestId))"></a>
|
||||
</span>
|
||||
<span class="anon-source" v-if="item?._type === 'gist' && item?.source?.gistId && !item?._broken">
|
||||
<a target="_blank" rel="noopener" v-text="item?._source" :href="safeUrl("https://gist.github.com/" + (item?.source?.gistId))"></a>
|
||||
</span>
|
||||
<span class="cell-conf conf-tag" v-if="item?.conference" :title="(item?.conference)"><i class="fas fa-university" aria-hidden="true"></i> <span v-text="item?.conference"></span></span>
|
||||
<div class="anon-sub">
|
||||
<code class="anonymous-id" v-if="item?._id" :title="item._id">{{ item._id }}</code>
|
||||
<span class="commit-hash" v-if="item?._type === 'repo' && item?.source?.commit" :title="item.source.commit">{{ item.source.commit.substring(0, 8) }}</span>
|
||||
<span class="cell-conf conf-tag" v-if="item?.conference" :title="(item?.conference)"><svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-conference"></use></svg> <span v-text="item?.conference"></span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard-row-meta" role="presentation">
|
||||
<div class="cell-status" role="cell">
|
||||
<div class="status-line">
|
||||
<span class="status-dot" aria-hidden="true" :class="'status-' + item?._statusKey"></span>
|
||||
@@ -173,60 +166,91 @@
|
||||
<div class="status-sub status-sub-warn" v-if="item?._stale" :title=""Last activity " + (fmt?.humanTime(item?.anonymizeDate || item?.lastView))">
|
||||
Last activity {{ fmt?.humanTime(item?.anonymizeDate || item?.lastView) }} · may be stuck
|
||||
</div>
|
||||
<div class="status-sub" v-if="item?.status != 'error' && !item?._stale && item?.anonymizeDate">
|
||||
<a class="project-attention-action" v-if="item.status === 'error' && item._editUrl" :href="safeUrl(item._editUrl)">Fix source</a>
|
||||
<button type="button" class="project-attention-action" v-if="item._stale || item._broken" @click.stop="showProjectDetails(item)">{{ item._broken ? 'Review details' : 'Check progress' }}</button>
|
||||
<div class="status-sub status-sub-date" v-if="item?.status != 'error' && !item?._stale && item?.anonymizeDate">
|
||||
anonymized {{ fmt?.humanTime(item?.anonymizeDate) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell-views num" role="cell" v-text="fmt?.number(item?.pageView)"></div>
|
||||
<div class="cell-views num" role="cell" :aria-label="fmt.number(item.pageView) + ' views'"><svg class="project-type-svg mobile-meta-icon" aria-hidden="true"><use href="#project-icon-eye"></use></svg><span>{{ fmt.number(item.pageView) }}</span></div>
|
||||
<div class="cell-expires" role="cell">
|
||||
<svg class="project-type-svg mobile-meta-icon" aria-hidden="true"><use href="#project-icon-clock"></use></svg>
|
||||
<span class="expires-never" v-if="item?._expiry?.kind === 'never'">Never</span>
|
||||
<span v-if="item?._expiry?.kind === 'date'" v-text="fmt?.humanTime(item?._expiry?.date)"></span>
|
||||
<span class="expires-past" v-if="item?._expiry?.kind === 'expired' && item?._expiry?.date">Expired {{ fmt?.humanTime(item?._expiry?.date) }}</span>
|
||||
<span class="expires-past" v-if="item?._expiry?.kind === 'expired' && !item?._expiry?.date">Expired</span>
|
||||
<span class="empty-dash" aria-label="Not applicable" v-if="item?._expiry?.kind === 'none'">—</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell-actions" role="cell">
|
||||
<button type="button" class="copy-link-inline" v-if="item._viewUrl" @click.stop="copyLink(item)" :disabled="!!copyingId" :title="'Copy anonymous link for ' + item._label" :aria-label="'Copy anonymous link for ' + item._label"><svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-copy"></use></svg></button>
|
||||
<button type="button" class="project-details-button" v-if="item._broken" @click.stop="showProjectDetails(item)" :data-project-actions="encodeURIComponent(item._type + ':' + item._id)" :aria-controls="projectDetailsId(item)" :aria-expanded="selectedProject === item">Details</button>
|
||||
<div class="dropdown" v-if="!item?._broken">
|
||||
<button class="btn btn-icon-dots" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" :aria-label=""Actions for " + (item?._name)">
|
||||
<i class="fas fa-ellipsis-h" aria-hidden="true"></i>
|
||||
<button class="btn btn-icon-dots" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" :data-project-actions="encodeURIComponent(item._type + ':' + item._id)" :aria-label=""Actions for " + (item?._name)">
|
||||
<svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-more"></use></svg>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<button type="button" class="dropdown-item" @click="showProjectDetails(item)" :aria-controls="projectDetailsId(item)" :aria-expanded="selectedProject === item">Project details & name</button>
|
||||
<a class="dropdown-item" :href="safeUrl((item?._viewUrl))">
|
||||
<i class="fa fa-eye" aria-hidden="true"></i> View
|
||||
View
|
||||
</a>
|
||||
<a class="dropdown-item" target="_self" v-if="item?._type === 'repo' && item?.options?.page && item?.status == 'ready'" :href="safeUrl("/w/" + (item?.repoId) + "/")">
|
||||
<i class="fas fa-globe" aria-hidden="true"></i> View page
|
||||
View page
|
||||
</a>
|
||||
<button type="button" class="dropdown-item" @click="copyLink(item)" :disabled="!!copyingId" v-if="item?._viewUrl">
|
||||
Copy anonymous link
|
||||
</button>
|
||||
<a class="dropdown-item" :href="safeUrl((item?._editUrl))">
|
||||
<i class="far fa-edit" aria-hidden="true"></i> Edit
|
||||
Edit
|
||||
</a>
|
||||
<button type="button" class="dropdown-item" v-if="item?.status == 'ready' || item?.status == 'error'" @click="refreshItem(item)">
|
||||
<i class="fas fa-sync" aria-hidden="true"></i> Force update
|
||||
Force update
|
||||
</button>
|
||||
<button type="button" class="dropdown-item" v-if="item?.status == 'removed'" @click="refreshItem(item)">
|
||||
<i class="fas fa-check-circle" aria-hidden="true"></i> Enable
|
||||
Enable
|
||||
</button>
|
||||
<button type="button" class="dropdown-item" v-if="item?.status == 'expired'" @click="extendItem(item)">
|
||||
<i class="fas fa-calendar-plus" aria-hidden="true"></i> Extend 6 months
|
||||
Extend 6 months
|
||||
</button>
|
||||
<div v-if="(item?.status == 'ready' || item?.status == 'expired' || item?.status == 'error') && item?.role !== 'coauthor'">
|
||||
<div class="dropdown-divider"></div>
|
||||
<button type="button" class="dropdown-item dropdown-item-danger" @click="removeItem(item)">
|
||||
<i class="fas fa-trash-alt" aria-hidden="true"></i> Remove
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-details-row" role="row" v-if="!loading && selectedProject === item">
|
||||
<div class="project-details" role="cell" aria-colspan="5" :id="projectDetailsId(item)" tabindex="-1" @keydown.esc.stop="closeProjectDetails(item)">
|
||||
<div class="project-details-heading"><h2>Project details</h2><button type="button" class="project-close" @click="closeProjectDetails(item)" aria-label="Close project details"><svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-close"></use></svg></button></div>
|
||||
<dl class="project-details-list">
|
||||
<div><dt>Source</dt><dd>{{ item._source || 'Not available' }}</dd></div>
|
||||
<div><dt>Anonymous ID</dt><dd><code>{{ item._id || 'Missing identifier' }}</code></dd></div>
|
||||
<div v-if="item.source?.commit"><dt>Commit</dt><dd><code>{{ item.source.commit }}</code></dd></div>
|
||||
<div v-if="item.conference"><dt>Conference</dt><dd>{{ item.conference }}</dd></div>
|
||||
<div><dt>Status</dt><dd>{{ fmt.statusLabel(item.status) }}<span v-if="item.statusMessage"> · {{ fmt.statusMsg(item.statusMessage) }}</span></dd></div>
|
||||
<div v-if="item.anonymizeDate"><dt>Last anonymized</dt><dd>{{ fmt.humanTime(item.anonymizeDate) }}</dd></div>
|
||||
</dl>
|
||||
<p class="project-progress-help" v-if="item._stale">This download has not progressed recently. Check the source access and selected branch before retrying.</p>
|
||||
<a class="project-attention-action" v-if="item._editUrl" :href="safeUrl(item._editUrl)">{{ needsAttention(item) ? 'Check source settings' : 'Edit anonymization settings' }}</a>
|
||||
<form class="project-name-form" v-if="item._id" @submit.prevent="saveProjectName(item)">
|
||||
<label :for="'project-name-' + item._type + '-' + item._id">Project name</label>
|
||||
<p :id="'project-name-help-' + item._type + '-' + item._id">Only you see this name. Leave it blank to use the default.</p>
|
||||
<div class="project-name-controls"><input class="form-control" type="text" :id="'project-name-' + item._type + '-' + item._id" :aria-describedby="'project-name-help-' + item._type + '-' + item._id" maxlength="100" v-model="projectName" :disabled="nameSaving"><button class="btn btn-ink" type="submit" :disabled="nameSaving">{{ nameSaving ? 'Saving…' : 'Save name' }}</button></div>
|
||||
<p class="project-name-error" role="alert" v-if="nameError">{{ nameError }}</p><p role="status" v-if="nameMessage">{{ nameMessage }}</p>
|
||||
</form>
|
||||
</div>
|
||||
</div></template>
|
||||
|
||||
<div class="paper-table-empty" v-if="!loading && filteredItems?.length == 0">
|
||||
<i class="fas fa-inbox" aria-hidden="true"></i>
|
||||
<svg class="project-type-svg project-empty-icon" aria-hidden="true"><use href="#project-icon-inbox"></use></svg>
|
||||
<span v-if="items?.length == 0">You have no anonymizations yet.</span>
|
||||
<span v-if="items?.length > 0">Nothing matches the current filters.</span>
|
||||
<div class="paper-table-empty-actions">
|
||||
<button type="button" class="btn btn-outline-ink" v-if="hasActiveFilters()" @click="clearFilters()">Clear filters</button>
|
||||
<a href="/anonymize" class="btn btn-ink" v-if="items?.length == 0"><i class="fa fa-plus-circle mr-1" aria-hidden="true"></i> New anonymization</a>
|
||||
<a href="/anonymize" class="btn btn-ink" v-if="items?.length == 0"><svg class="project-type-svg" aria-hidden="true"><use href="#project-icon-plus"></use></svg> New anonymization</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user