Skip to content

Commit

Permalink
Add "Last Updated / Actions" column to EntityTable (#811)
Browse files Browse the repository at this point in the history
Also adding:

- A generic component for a table with frozen columns
- A function to highlight a row that has changed
  • Loading branch information
matthew-white authored May 29, 2023
1 parent da77ddf commit 39409ab
Show file tree
Hide file tree
Showing 24 changed files with 918 additions and 505 deletions.
28 changes: 8 additions & 20 deletions src/assets/scss/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -574,26 +574,6 @@ select {
}
}

.table-frozen {
float: left;
width: auto;
}

.table-container {
// Placing the margin here rather than on the table so that the horizontal
// scrollbar appears immediately below the table, above the margin.
margin-bottom: $margin-bottom-table;
overflow-x: auto;

.table {
margin-bottom: 0;
}
}

.table-actions {
margin-bottom: 20px;
}

.empty-table-message {
color: #555;
font-size: 15px;
Expand Down Expand Up @@ -825,3 +805,11 @@ becomes more complicated.
}
}
}



////////////////////////////////////////////////////////////////////////////////
// markRowsChanged()

[data-mark-rows-changed="false"] { transition: background-color 0.6s 6s; }
[data-mark-rows-changed="true"] { background-color: #faf1cd; }
4 changes: 2 additions & 2 deletions src/components/entity/data-row.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ including this file, may be copied, modified, propagated, or distributed
except according to the terms contained in the LICENSE file.
-->
<template>
<tr>
<td v-for="property of properties" :key="property.id">
<tr class="entity-data-row">
<td v-for="property of properties" :key="property.name">
<span v-tooltip.text>{{ entity[property.odataName] }}</span>
</td>
<td><span v-tooltip.text>{{ entity.label }}</span></td>
Expand Down
62 changes: 58 additions & 4 deletions src/components/entity/list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,24 @@ except according to the terms contained in the LICENSE file.
</a>
</div>
<entity-table v-show="odataEntities.dataExists && odataEntities.value.length !== 0"
:properties="dataset.properties"/>
ref="table" :properties="dataset.properties" @update="showUpdate"/>
<p v-show="odataEntities.dataExists && odataEntities.value.length === 0"
class="empty-table-message">
{{ $t('noEntities') }}
</p>
<loading :state="odataEntities.initiallyLoading"/>

<entity-update v-bind="update" @hide="hideUpdate" @success="afterUpdate"/>
</div>
</template>

<script>

import Loading from '../loading.vue';
import Spinner from '../spinner.vue';
import EntityTable from './table.vue';
import EntityUpdate from './update.vue';

import modal from '../../mixins/modal';
import useEntities from '../../request-data/entities';
import { useRequestData } from '../../request-data';
import { apiPaths } from '../../util/request';
Expand All @@ -48,8 +51,11 @@ export default {
components: {
Loading,
Spinner,
EntityTable
EntityTable,
EntityUpdate
},
mixins: [modal()],
inject: ['alert'],
provide() {
return { projectId: this.projectId, datasetName: this.datasetName };
},
Expand All @@ -72,7 +78,14 @@ export default {
},
data() {
return {
refreshing: false
refreshing: false,
// The index of the entity being updated
updateIndex: null,
// Data to pass to the update modal
update: {
state: false,
entity: null
}
};
},
computed: {
Expand Down Expand Up @@ -101,6 +114,47 @@ export default {
})
.finally(() => { this.refreshing = false; })
.catch(noop);
},
showUpdate(index) {
if (this.refreshing) return;
this.updateIndex = index;
const odataEntity = this.odataEntities.value[index];
const data = Object.create(null);
for (const { name, odataName } of this.dataset.properties)
data[name] = odataEntity[odataName];
this.update.entity = {
uuid: odataEntity.__id,
currentVersion: { label: odataEntity.label, data }
};
this.showModal('update');
},
hideUpdate() {
this.hideModal('update');
this.update.entity = null;
this.updateIndex = null;
},
afterUpdate(updatedEntity) {
const index = this.updateIndex;
this.hideUpdate();
this.alert.success(this.$t('alert.updateEntity'));

// Update the OData using the REST response.
const oldOData = this.odataEntities.value[index];
const newOData = Object.assign(Object.create(null), {
__id: oldOData.__id,
label: updatedEntity.currentVersion.label,
__system: {
...oldOData.__system,
updates: oldOData.__system.updates + 1,
updatedAt: updatedEntity.updatedAt
}
});
const { data: updatedData } = updatedEntity.currentVersion;
for (const { name, odataName } of this.dataset.properties)
newOData[odataName] = updatedData[name];
this.odataEntities.value[index] = newOData;

this.$refs.table.afterUpdate(index);
}
}
};
Expand Down
67 changes: 58 additions & 9 deletions src/components/entity/metadata-row.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,37 @@ except according to the terms contained in the LICENSE file.
-->
<template>
<tr class="entity-metadata-row">
<td class="row-number">
<router-link v-slot="{ href }"
:to="entityPath(projectId, datasetName, entity.__id)" custom>
<a :href="href" target="_blank">{{ $n(rowNumber, 'noGrouping') }}</a>
</router-link>
</td>
<td class="row-number">{{ $n(rowNumber, 'noGrouping') }}</td>
<td class="creator-name">
<span v-tooltip.text>{{ entity.__system.creatorName }}</span>
</td>
<td><date-time :iso="entity.__system.createdAt"/></td>
<td>
<div class="col-content">
<date-time :iso="entity.__system.updatedAt" class="updated-at"/>
<span class="updates">
<template v-if="entity.__system.updates !== 0">
<span class="icon-pencil"></span>
<span>{{ $n(entity.__system.updates, 'default') }}</span>
</template>
</span>
<span class="icon-angle-right"></span>
</div>
<div class="btn-group">
<button v-if="canUpdate" type="button"
class="update-button btn btn-default" :aria-label="updateLabel"
v-tooltip.aria-label>
<span class="icon-pencil"></span>
</button>
<router-link v-slot="{ href }"
:to="entityPath(projectId, datasetName, entity.__id)" custom>
<a class="more-button btn btn-default" :href="href" target="_blank">
<span>{{ $t('action.more') }}</span>
<span class="icon-angle-right"></span>
</a>
</router-link>
</div>
</td>
</tr>
</template>

Expand All @@ -30,25 +51,31 @@ export default {
};
</script>
<script setup>
import { inject } from 'vue';
import { computed, inject } from 'vue';

import DateTime from '../date-time.vue';

import useRoutes from '../../composables/routes';

defineProps({
const props = defineProps({
entity: {
type: Object,
required: true
},
rowNumber: {
type: Number,
required: true
}
},
canUpdate: Boolean
});
const projectId = inject('projectId');
const datasetName = inject('datasetName');

const { i18n } = inject('container');
const updateLabel = computed(() => i18n.t('submission.action.edit', {
count: i18n.n(props.entity.__system.updates, 'default')
}));

const { entityPath } = useRoutes();
</script>

Expand All @@ -69,5 +96,27 @@ const { entityPath } = useRoutes();
@include text-overflow-ellipsis;
max-width: 250px;
}

.col-content {
align-items: flex-start;
display: flex;
}
.updated-at {
margin-right: 21px;

&:empty { width: 75px; }
}
.updates {
color: #777;
margin-left: auto;
width: 41px;

.icon-pencil { margin-right: 5px; }
}
.col-content .icon-angle-right {
color: $color-accent-primary;
font-size: 20px;
margin-top: -1px;
}
}
</style>
Loading

0 comments on commit 39409ab

Please sign in to comment.