Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Last Updated / Actions" column to EntityTable #811

Merged
merged 11 commits into from
May 29, 2023
Merged
32 changes: 12 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,15 @@ becomes more complicated.
}
}
}



////////////////////////////////////////////////////////////////////////////////
// useRowChanged()

[data-use-row-changed="false"] { transition: background-color 0.6s 6s; }

[data-use-row-changed="true"] {
background-color: #faf1cd;
transition: none;
}
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,
matthew-white marked this conversation as resolved.
Show resolved Hide resolved
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
69 changes: 59 additions & 10 deletions src/components/entity/metadata-row.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,38 @@ including this file, may be copied, modified, propagated, or distributed
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>
<tr ref="el" class="entity-metadata-row">
<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,35 @@ export default {
};
</script>
<script setup>
import { inject } from 'vue';
import { computed, inject, ref } from 'vue';

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

import useRoutes from '../../composables/routes';
import { useRowChanged } from '../../composables/row-changed';

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 el = ref(null);
useRowChanged(el);

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 +100,23 @@ const { entityPath } = useRoutes();
@include text-overflow-ellipsis;
max-width: 250px;
}

.col-content { 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;
}
}
</style>
Loading