Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 14 additions & 17 deletions apps/central/src/components/entity/metadata-row.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ except according to the terms contained in the LICENSE file.
-->
<template>
<tr class="entity-metadata-row" :class="{ 'entity-row-selected': entity.__system.selected }">
<td class="col-actions">
<entity-actions v-if="!deleted" :entity="entity" :awaiting-response="awaitingResponse"/>
<div v-if="deleted && verbs.has('entity.restore')" class="btn-group">
<button type="button"
class="restore-button btn btn-default"
:aria-disabled="awaitingResponse"
:aria-label="$t('action.restore')" v-tooltip.aria-label>
<span class="icon-recycle"></span><spinner :state="awaitingResponse"/>
</button>
</div>
</td>
<td class="row-number">{{ $n(rowNumber, 'noGrouping') }}</td>
<td v-if="!deleted && verbs.has('entity.delete')">
<input type="checkbox" :aria-label="$t('action.selectRow')" :checked="entity.__system.selected" @change="$emit('selectionChanged', $event.target.checked)">
Expand All @@ -19,7 +30,7 @@ except according to the terms contained in the LICENSE file.
<span v-tooltip.text>{{ entity.__system.creatorName }}</span>
</td>
<td><date-time :iso="entity.__system.createdAt"/></td>
<td v-if="!deleted" class="action-cell">
<td v-if="!deleted" class="last-updated-cell">
<div class="col-content">
<date-time :iso="entity.__system.updatedAt" class="updated-at"/>
<span class="updates">
Expand All @@ -33,22 +44,12 @@ except according to the terms contained in the LICENSE file.
<span>{{ $n(entity.__system.updates, 'default') }}</span>
</template>
</span>
<span class="icon-angle-right"></span>
</div>
<entity-actions :entity="entity" :awaiting-response="awaitingResponse"/>
</td>
<td v-else class="action-cell">
<td v-else class="last-updated-cell">
<div class="col-content col-deleted-at">
<date-time :iso="entity.__system.deletedAt"/>
</div>
<div v-if="verbs.has('entity.restore')" class="btn-group">
<button type="button"
class="restore-button btn btn-default"
:aria-disabled="awaitingResponse"
:aria-label="$t('action.restore')" v-tooltip.aria-label>
<span class="icon-recycle"></span><spinner :state="awaitingResponse"/>
</button>
</div>
</td>
</tr>
</template>
Expand Down Expand Up @@ -98,13 +99,9 @@ defineEmits(['selectionChanged']);
max-width: 250px;
}

.action-cell {
.last-updated-cell {
padding-top: 4px;
padding-bottom: 4px;

// Ensure that the column is wide enough that EntityActions does not wrap.
min-width: 170px;
&:lang(id) { min-width: 215px; }
}

.col-content {
Expand Down
15 changes: 10 additions & 5 deletions apps/central/src/components/entity/table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ except according to the terms contained in the LICENSE file.
:data="odataEntities.value" key-prop="__id"
:frozen-only="properties == null" divider @action="afterAction">
<template #head-frozen>
<th class="col-actions"></th>
<th><span class="sr-only">{{ $t('common.rowNumber') }}</span></th>
<th v-if="!deleted && project.verbs.has('entity.delete')">
<input type="checkbox" :aria-label="$t('action.selectRow')" :checked="allSelected" @change="changeAllSelection($event.target.checked)">
</th>
<th>{{ $t('header.createdBy') }}</th>
<th>{{ $t('header.createdAt') }}</th>
<th v-if="!deleted">{{ $t('header.updatedAtAndActions') }}</th>
<th v-if="!deleted">{{ $t('header.updatedAt') }}</th>
<th v-else class="col-deleted-at">{{ $t('header.deletedAt') }}</th>
</template>
<template #head-scrolling>
Expand Down Expand Up @@ -141,7 +142,12 @@ defineExpose({ afterUpdate, afterDelete });
margin-top: 0;
}

th.col-deleted-at { color: $color-danger; }
th.col-deleted-at { color: $color-danger; }

.col-actions {
width: 0;
padding: 0;
}
}
</style>

Expand All @@ -150,9 +156,8 @@ th.col-deleted-at { color: $color-danger; }
"en": {
"header": {
// This is the text of a column header of a table of Entities. The column
// shows when each Entity was last updated, as well as actions that can be
// taken on the Entity.
"updatedAtAndActions": "Last Updated / Actions",
// shows when each Entity was last updated.
"updatedAt": "Last Updated",
// Heading of the column that shows Entity deletion timestamp
"deletedAt": "Deleted at"
}
Expand Down
9 changes: 6 additions & 3 deletions apps/central/src/components/field-key/list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ except according to the terms contained in the LICENSE file.
<table-freeze v-if="dataExists" id="field-key-list-table" :data="fieldKeys.data" key-prop="id"
:frozen-only="actorProperties.length === 0" :divider="actorProperties.length > 0">
<template #head-frozen>
<th class="col-actions"></th>
<th>{{ $t('header.displayName') }}</th>
<th>{{ $t('header.configureClient') }}</th>
<th>{{ $t('header.createdAt') }}</th>
<th>{{ $t('header.createdBy') }}</th>
<th>{{ $t('header.lastUsedAndActions', { lastUsed: $t('header.lastUsed'), actions: $t('header.actions') }) }}</th>
<th>{{ $t('header.lastUsed') }}</th>
</template>
<template #head-scrolling>
<th v-for="property of actorProperties" :key="property.name">
Expand Down Expand Up @@ -218,6 +219,10 @@ export default {
&.frozen-only .table-freeze-frozen {
width: 100%;
}
.col-actions {
width: 0;
padding: 0;
}
}
</style>

Expand All @@ -240,8 +245,6 @@ export default {
],
"header": {
"lastUsed": "Last Used",
// Header for the table column that shows the last used date and action buttons.
"lastUsedAndActions": "{lastUsed} / {actions}",
// Header for the table column that shows QR codes to configure data collection clients such as ODK Collect.
"configureClient": "Configure Client"
},
Expand Down
52 changes: 17 additions & 35 deletions apps/central/src/components/field-key/row.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,7 @@ except according to the terms contained in the LICENSE file.
-->
<template>
<tr class="field-key-row" :class="{ success: fieldKey.id === highlighted }">
<td class="display-name">
<span v-tooltip.text>{{ fieldKey.displayName }}</span>
</td>
<td>
<a v-if="fieldKey.token != null" ref="popoverLink" href="#"
class="field-key-row-popover-link" role="button"
@click.prevent="toggleQr">
<span class="icon-qrcode"></span>{{ $t('seeCode') }}
</a>
<template v-else>
{{ $t('accessRevoked') }}
</template>
</td>
<td><date-time :iso="fieldKey.createdAt"/></td>
<td class="created-by">
<span v-tooltip.text>{{ fieldKey.createdBy.displayName }}</span>
</td>
<td class="last-used-and-actions">
<div class="col-content">
<date-time :iso="fieldKey.lastUsed"/>
</div>
<td class="col-actions">
<div class="btn-group">
<button v-if="fieldKey.token != null && showEdit" type="button"
class="edit-button btn btn-default"
Expand All @@ -47,6 +27,22 @@ except according to the terms contained in the LICENSE file.
</button>
</div>
</td>
<td class="display-name"><span v-tooltip.text>{{ fieldKey.displayName }}</span></td>
<td>
<a v-if="fieldKey.token != null" ref="popoverLink" href="#"
class="field-key-row-popover-link" role="button"
@click.prevent="toggleQr">
<span class="icon-qrcode"></span>{{ $t('seeCode') }}
</a>
<template v-else>
{{ $t('accessRevoked') }}
</template>
</td>
<td><date-time :iso="fieldKey.createdAt"/></td>
<td class="created-by">
<span v-tooltip.text>{{ fieldKey.createdBy.displayName }}</span>
</td>
<td><date-time :iso="fieldKey.lastUsed"/></td>
</tr>
</template>

Expand Down Expand Up @@ -78,25 +74,11 @@ export default {
@import '../../assets/scss/variables';

.field-key-row {
.table tbody & td { vertical-align: middle; }

.display-name, .created-by {
@include text-overflow-ellipsis;
max-width: 250px;
}

.last-used-and-actions {
padding-top: 4px;
padding-bottom: 4px;
min-width: 120px;
}

.col-content {
display: flex;
align-items: flex-start;
margin-top: 3px;
}

.btn-group {
@include icon-btn-group;
.icon-ban { color: $color-danger; }
Expand Down
33 changes: 14 additions & 19 deletions apps/central/src/components/submission/metadata-row.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,24 @@ except according to the terms contained in the LICENSE file.
-->
<template>
<tr class="submission-metadata-row">
<td class="col-actions">
<submission-actions v-if="!draft && !deleted" :submission="submission"
:awaiting-response="awaitingResponse"/>
<div v-if="deleted && verbs.has('submission.restore')" class="btn-group">
<button type="button"
class="restore-button btn btn-default"
:aria-disabled="awaitingResponse"
:aria-label="$t('action.restore')" v-tooltip.aria-label>
<span class="icon-recycle"></span><spinner :state="awaitingResponse"/>
</button>
</div>
</td>
<td class="row-number">{{ $n(rowNumber, 'noGrouping') }}</td>
<td v-if="!draft" class="submitter-name">
<span v-tooltip.text>{{ submission.__system.submitterName }}</span>
</td>
<td><date-time :iso="submission.__system.submissionDate"/></td>
<td v-if="!draft && !deleted" class="state-and-actions">
<td v-if="!draft && !deleted">
<div class="col-content">
<span class="state">
<template v-if="missingAttachment">
Expand All @@ -32,23 +44,12 @@ except according to the terms contained in the LICENSE file.
<span>{{ $n(submission.__system.edits, 'default') }}</span>
</template>
</span>
<span class="icon-angle-right"></span>
</div>
<submission-actions :submission="submission"
:awaiting-response="awaitingResponse"/>
</td>
<td v-if="!draft && deleted" class="state-and-actions">
<td v-if="!draft && deleted">
<div class="col-content col-deleted-at">
<date-time :iso="submission.__system.deletedAt"/>
</div>
<div v-if="verbs.has('submission.restore')" class="btn-group">
<button type="button"
class="restore-button btn btn-default"
:aria-disabled="awaitingResponse"
:aria-label="$t('action.restore')" v-tooltip.aria-label>
<span class="icon-recycle"></span><spinner :state="awaitingResponse"/>
</button>
</div>
</td>
</tr>
</template>
Expand Down Expand Up @@ -108,12 +109,6 @@ export default {
@include text-overflow-ellipsis;
max-width: 250px;
}

.state-and-actions {
// Ensure that the column is wide enough that the .btn-group does not wrap.
min-width: 205px;
&:lang(id) { min-width: 221px; }
}
.col-content {
align-items: flex-start;
display: flex;
Expand Down
9 changes: 7 additions & 2 deletions apps/central/src/components/submission/table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ except according to the terms contained in the LICENSE file.
:data="chunkyOData" key-prop="__id" :frozen-only="fields == null" divider
@action="handleActions">
<template #head-frozen>
<th class="col-actions"></th>
<th><span class="sr-only">{{ $t('common.rowNumber') }}</span></th>
<th v-if="!draft">{{ $t('header.submitterName') }}</th>
<th>{{ $t('header.submissionDate') }}</th>
<th v-if="!draft && !deleted">{{ $t('header.stateAndActions') }}</th>
<th v-if="!draft && !deleted">{{ $t('header.state') }}</th>
<th v-if="!draft && deleted" class="col-deleted-at">{{ $t('header.deletedAt') }}</th>
</template>
<template #head-scrolling>
Expand Down Expand Up @@ -117,14 +118,18 @@ defineExpose({ afterReview, afterDelete });
}

th.col-deleted-at { color: $color-danger; }
.col-actions {
padding: 0;
width: 0;
}
}
</style>

<i18n lang="json5">
{
"en": {
"header": {
"stateAndActions": "State and actions",
"state": "State",
// Heading of the column that shows Submission deletion timestamp
"deletedAt": "Deleted at"
}
Expand Down
14 changes: 7 additions & 7 deletions apps/central/src/components/table/freeze.vue
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ defineExpose({ getRowPair });
<style lang="scss">
@import '../../assets/scss/mixins';

.table-freeze { @include clearfix; }
.table-freeze {
@include clearfix;
position: relative;
}

.table-freeze-frozen {
float: left;
Expand All @@ -154,7 +157,6 @@ defineExpose({ getRowPair });

.table-freeze-frozen.divider {
box-shadow: 3px 0 0 rgba(0, 0, 0, 0.04);
position: relative;
// Adding z-index so that the background color of the other table's thead does
// not overlay the box shadow.
z-index: 1;
Expand All @@ -166,22 +168,20 @@ defineExpose({ getRowPair });
// Styles related to actions (buttons and links). If there are actions, they
// should be in a .btn-group.
.table-freeze-frozen {
// If the table has a .btn-group, it will probably be in the last column.
td:last-child { position: relative; }

.btn-group {
// Setting the background color in case an action is transparent.
background-color: $color-page-background;
left: -2000px;
// Relative to .table-freeze so that buttons are shown to the right side of the component.
position: absolute;
top: 4px;
margin-top: 4px;
}

.actions-trigger-hover tr:hover .btn-group,
.actions-trigger-hover .scrolling-hover .btn-group,
.actions-trigger-focus .btn-group:focus-within {
left: auto;
right: $padding-right-table-data;
right: 0px;
}

.btn-group { @include icon-btn-group; }
Expand Down
9 changes: 5 additions & 4 deletions apps/central/test/components/entity/list.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,11 @@ describe('EntityList', () => {

it('updates the EntityMetadataRow', async () => {
const component = await submit();
const td = component.get('.entity-metadata-row:nth-child(2) td:last-child');
should.exist(td.getComponent(DateTime).props().iso);
td.get('.updates').text().should.equal('1');
td.get('.update-button').attributes('aria-label').should.equal('Edit (1)');
const row = component.get('.entity-metadata-row:nth-child(2)');
const lastUpdatedTd = row.get('.last-updated-cell');
should.exist(lastUpdatedTd.getComponent(DateTime).props().iso);
lastUpdatedTd.get('.updates').text().should.equal('1');
row.get('.update-button').attributes('aria-label').should.equal('Edit (1)');
});
});
});
Expand Down
Loading
Loading