410 lines
11 KiB
Vue
410 lines
11 KiB
Vue
|
<template>
|
|||
|
<div v-if="!isFetching" class="grid grid-cell u-flex__justify--center">
|
|||
|
<div class="grid-cell grid-cell--col12 u-mt--28">
|
|||
|
<div class="u-flex u-flex__justify--between title-container">
|
|||
|
<h2 class="title is-caption is-txtMainTextColor">
|
|||
|
Data sample
|
|||
|
<transition name="fade">
|
|||
|
<a
|
|||
|
v-if="variables && variables.length > 0"
|
|||
|
@click="scrollToVariables()"
|
|||
|
class="is-small"
|
|||
|
>View {{ numberColumns }} variables list</a
|
|||
|
>
|
|||
|
</transition>
|
|||
|
</h2>
|
|||
|
<div class="is-small text txtMainTextColor">
|
|||
|
<span class="source u-flex u-flex__align--center" style="white-space:pre-wrap;" v-if="source"
|
|||
|
>(*) Sample not available: this preview is for
|
|||
|
<i class="is-semibold is-italic">{{ source }}</i></span
|
|||
|
>
|
|||
|
<span class="grey" v-else-if="numberRows > 0"
|
|||
|
>First {{ numberRows }} rows</span
|
|||
|
>
|
|||
|
<span class="grey" v-else>Not available</span>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="table-wrapper" ref="tableWrapper" v-if="columns.length">
|
|||
|
<div
|
|||
|
class="tooltip is-small"
|
|||
|
:class="{ first: tooltip.isFirst, last: tooltip.isLast }"
|
|||
|
v-if="tooltip.visible"
|
|||
|
:style="{ left: tooltip.left + 'px' }"
|
|||
|
>
|
|||
|
<p class="text is-small">
|
|||
|
<span class="is-semibold">Description:</span>
|
|||
|
{{ tooltip.description }}
|
|||
|
</p>
|
|||
|
<p class="text is-small">
|
|||
|
<span class="is-semibold">Type:</span> {{ tooltip.type }}
|
|||
|
</p>
|
|||
|
</div>
|
|||
|
<div v-if="numberRows > 0" class="scrollable-table u-mt--24">
|
|||
|
<table class="text is-small u-width--100">
|
|||
|
<tr>
|
|||
|
<th></th>
|
|||
|
<th
|
|||
|
@mousemove="showTooltip(value, $event)"
|
|||
|
@mouseleave="hideTooltip"
|
|||
|
v-for="value in columns"
|
|||
|
:key="value"
|
|||
|
>
|
|||
|
{{ value }}
|
|||
|
</th>
|
|||
|
</tr>
|
|||
|
<tr v-for="n in numberRows" :key="n">
|
|||
|
<td class="is-semibold">{{ n - 1 }}</td>
|
|||
|
<td v-for="sample of tableSample" :key="sample.column_name">
|
|||
|
<template v-if="sample.column_name !== 'geom'">
|
|||
|
<span
|
|||
|
v-if="
|
|||
|
sample.values[n - 1] !== null &&
|
|||
|
sample.values[n - 1] !== undefined
|
|||
|
"
|
|||
|
>{{ sample.values[n - 1] }}</span
|
|||
|
>
|
|||
|
<span v-else class="is-txtLightGrey is-italic">null</span>
|
|||
|
</template>
|
|||
|
<template v-else>
|
|||
|
<span>GeoJSON</span>
|
|||
|
</template>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
</table>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<NotAvailable
|
|||
|
v-else
|
|||
|
:title="'Sample is not available'"
|
|||
|
:description="
|
|||
|
'This data sample can’t be shown because the real dataset only contains a few rows.'
|
|||
|
"
|
|||
|
:contactUrl="getFormURL()"
|
|||
|
:mode="'contact'"
|
|||
|
></NotAvailable>
|
|||
|
</div>
|
|||
|
|
|||
|
<transition name="fade">
|
|||
|
<div
|
|||
|
v-if="variables && variables.length > 0"
|
|||
|
class="grid-cell--col12 u-mt--60"
|
|||
|
ref="variablesSection"
|
|||
|
>
|
|||
|
<div class="u-flex u-flex__align--center u-flex__justify--between">
|
|||
|
<h2 class="grid-cell title is-caption is-txtMainTextColor">
|
|||
|
Variables
|
|||
|
</h2>
|
|||
|
<span class="is-txtMidGrey text is-small u-pr--10">{{numberColumns}} variables</span>
|
|||
|
</div>
|
|||
|
|
|||
|
<ul class="u-mt--24 text f12 is-small is-txtMainTextColor">
|
|||
|
<li class="grid title is-txtMidGrey header-row">
|
|||
|
<div class="grid-cell grid-cell--col4">Column Name</div>
|
|||
|
<div
|
|||
|
class="grid-cell grid-cell--col7 grid-cell--col6--tablet grid-cell--col5--mobile"
|
|||
|
>
|
|||
|
Description
|
|||
|
</div>
|
|||
|
<div
|
|||
|
class="grid-cell grid-cell--col1 grid-cell--col2--tablet grid-cell--col3--mobile"
|
|||
|
>
|
|||
|
Type
|
|||
|
</div>
|
|||
|
</li>
|
|||
|
|
|||
|
<li
|
|||
|
class="grid info-row"
|
|||
|
v-for="variable in variables"
|
|||
|
:key="variable.slug"
|
|||
|
>
|
|||
|
<div class="grid-cell grid-cell--col4 is-semibold name-cell">
|
|||
|
{{ variable.column_name }}
|
|||
|
</div>
|
|||
|
<div
|
|||
|
class="grid-cell grid-cell--col7 grid-cell--col6--tablet grid-cell--col5--mobile"
|
|||
|
>
|
|||
|
{{ variable.description }}
|
|||
|
</div>
|
|||
|
<div
|
|||
|
class="grid-cell grid-cell--col1 grid-cell--col2--tablet grid-cell--col3--mobile"
|
|||
|
>
|
|||
|
{{ variable.db_type }}
|
|||
|
</div>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
</div>
|
|||
|
</transition>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
import { mapState } from 'vuex';
|
|||
|
import NotAvailable from 'new-dashboard/components/Catalog/NotAvailable.vue';
|
|||
|
import { formURL } from 'new-dashboard/utils/catalog/form-url';
|
|||
|
import { sendCustomDimensions } from 'new-dashboard/utils/catalog/custom-dimensions-ga';
|
|||
|
|
|||
|
export default {
|
|||
|
name: 'CatalogDatasetData',
|
|||
|
components: {
|
|||
|
NotAvailable
|
|||
|
},
|
|||
|
data () {
|
|||
|
return {
|
|||
|
tooltip: {
|
|||
|
visible: false,
|
|||
|
isFirst: false,
|
|||
|
isLast: false,
|
|||
|
left: 0,
|
|||
|
description: null,
|
|||
|
type: null
|
|||
|
}
|
|||
|
};
|
|||
|
},
|
|||
|
watch: {
|
|||
|
dataset: {
|
|||
|
handler (value) {
|
|||
|
if (value && value.category_name) {
|
|||
|
sendCustomDimensions(
|
|||
|
value.category_name,
|
|||
|
value.country_name,
|
|||
|
value.is_public_data,
|
|||
|
value.provider_name
|
|||
|
);
|
|||
|
}
|
|||
|
},
|
|||
|
immediate: true
|
|||
|
}
|
|||
|
},
|
|||
|
computed: {
|
|||
|
...mapState({
|
|||
|
dataset: state => state.catalog.dataset,
|
|||
|
variables: state => state.catalog.variables,
|
|||
|
isFetching: state => state.catalog.isFetching
|
|||
|
}),
|
|||
|
isPublicWebsite () {
|
|||
|
return !(this.$store.state.user && this.$store.state.user.id);
|
|||
|
},
|
|||
|
tableKey () {
|
|||
|
if (this.dataset && this.dataset.summary_json) {
|
|||
|
if (this.dataset.summary_json.ordered_glimpses) {
|
|||
|
return 'ordered_glimpses';
|
|||
|
} else if (this.dataset.summary_json.default_ordered_glimpses) {
|
|||
|
return 'default_ordered_glimpses';
|
|||
|
}
|
|||
|
}
|
|||
|
return null;
|
|||
|
},
|
|||
|
source () {
|
|||
|
if (this.tableKey === 'default_ordered_glimpses') {
|
|||
|
return this.dataset.summary_json[this.tableKey].source;
|
|||
|
}
|
|||
|
return null;
|
|||
|
},
|
|||
|
tableSample () {
|
|||
|
if (this.tableKey && this.dataset.summary_json) {
|
|||
|
const geom_column = { column_name: 'geom', values: Array(10) };
|
|||
|
return [...this.dataset.summary_json[this.tableKey].tail, geom_column];
|
|||
|
}
|
|||
|
return [];
|
|||
|
},
|
|||
|
columns () {
|
|||
|
return this.tableSample ? this.tableSample.map(t => t.column_name) : [];
|
|||
|
},
|
|||
|
numberRows () {
|
|||
|
// return this.columns.length ? this.tableSample[this.columns[0]].length : 0;
|
|||
|
return this.tableSample && this.tableSample.length > 0 ? this.tableSample[0].values.length : 0;
|
|||
|
},
|
|||
|
numberColumns () {
|
|||
|
return this.variables ? this.variables.length : this.columns.length;
|
|||
|
},
|
|||
|
isGeography () {
|
|||
|
return this.$route.params.type === 'geography';
|
|||
|
}
|
|||
|
},
|
|||
|
methods: {
|
|||
|
fetchVariables () {
|
|||
|
this.$store.dispatch('catalog/fetchVariables', {
|
|||
|
id: this.$route.params.datasetId,
|
|||
|
type: this.$route.params.type
|
|||
|
});
|
|||
|
},
|
|||
|
findVariableInfo (variableName) {
|
|||
|
return this.variables.find(e => e.column_name === variableName);
|
|||
|
},
|
|||
|
showTooltip (variableName, event) {
|
|||
|
let tooltipInfo = this.findVariableInfo(variableName);
|
|||
|
if (tooltipInfo) {
|
|||
|
let tableBoundingSize = this.$refs.tableWrapper.getBoundingClientRect();
|
|||
|
this.tooltip.left =
|
|||
|
event.target.getBoundingClientRect().left -
|
|||
|
this.$refs.tableWrapper.getBoundingClientRect().left +
|
|||
|
event.offsetX;
|
|||
|
if (this.tooltip.left < 140) {
|
|||
|
this.tooltip.isFirst = true;
|
|||
|
this.tooltip.left -= 26;
|
|||
|
} else if (tableBoundingSize.width - this.tooltip.left < 120) {
|
|||
|
this.tooltip.isLast = true;
|
|||
|
this.tooltip.left += 26;
|
|||
|
} else {
|
|||
|
this.tooltip.isFirst = false;
|
|||
|
this.tooltip.isLast = false;
|
|||
|
}
|
|||
|
|
|||
|
this.tooltip.description = tooltipInfo.description;
|
|||
|
this.tooltip.type = tooltipInfo.db_type;
|
|||
|
this.tooltip.visible = true;
|
|||
|
} else {
|
|||
|
this.hideTooltip();
|
|||
|
}
|
|||
|
},
|
|||
|
hideTooltip () {
|
|||
|
this.tooltip.visible = false;
|
|||
|
this.tooltip.isFirst = false;
|
|||
|
this.tooltip.isLast = false;
|
|||
|
},
|
|||
|
getFormURL () {
|
|||
|
return formURL(this.dataset);
|
|||
|
},
|
|||
|
scrollToVariables () {
|
|||
|
window.scrollTo({
|
|||
|
top: this.$refs.variablesSection.offsetTop,
|
|||
|
left: 0,
|
|||
|
behavior: 'smooth'
|
|||
|
});
|
|||
|
}
|
|||
|
},
|
|||
|
mounted () {
|
|||
|
this.fetchVariables();
|
|||
|
}
|
|||
|
};
|
|||
|
</script>
|
|||
|
|
|||
|
<style scoped lang="scss">
|
|||
|
@import 'new-dashboard/styles/variables';
|
|||
|
|
|||
|
.title a {
|
|||
|
margin-left: 26px;
|
|||
|
}
|
|||
|
|
|||
|
a {
|
|||
|
cursor: pointer;
|
|||
|
}
|
|||
|
|
|||
|
.scrollable-table {
|
|||
|
width: 100%;
|
|||
|
overflow: auto;
|
|||
|
|
|||
|
td,
|
|||
|
th {
|
|||
|
padding: 12px 24px 12px 8px;
|
|||
|
white-space: nowrap;
|
|||
|
}
|
|||
|
tr:nth-child(even) {
|
|||
|
background-color: $color-primary--soft;
|
|||
|
}
|
|||
|
|
|||
|
th {
|
|||
|
position: relative;
|
|||
|
color: $link__color;
|
|||
|
text-align: left;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.info-row {
|
|||
|
padding: 14px 0;
|
|||
|
border-bottom: 1px solid $blue--100;
|
|||
|
}
|
|||
|
|
|||
|
.name-cell {
|
|||
|
overflow: hidden;
|
|||
|
text-overflow: ellipsis;
|
|||
|
}
|
|||
|
|
|||
|
.header-row {
|
|||
|
padding-bottom: 12px;
|
|||
|
border-bottom: 2px solid $blue--100;
|
|||
|
}
|
|||
|
|
|||
|
.tooltip-container {
|
|||
|
position: absolute;
|
|||
|
z-index: 2;
|
|||
|
bottom: 100%;
|
|||
|
margin-left: 32px;
|
|||
|
padding-bottom: 8px;
|
|||
|
}
|
|||
|
|
|||
|
.table-wrapper {
|
|||
|
position: relative;
|
|||
|
}
|
|||
|
|
|||
|
.tooltip {
|
|||
|
position: absolute;
|
|||
|
bottom: calc(100% + 8px);
|
|||
|
width: 300px;
|
|||
|
padding: 12px 16px 8px;
|
|||
|
transform: translateX(-50%);
|
|||
|
border: 1px solid $border-color;
|
|||
|
border-radius: 4px;
|
|||
|
background-color: #fff;
|
|||
|
word-break: break-word;
|
|||
|
|
|||
|
&::before {
|
|||
|
content: '';
|
|||
|
position: absolute;
|
|||
|
bottom: -8px;
|
|||
|
left: calc(50% - 12px); // To compensate right extra padding
|
|||
|
width: 14px;
|
|||
|
height: 14px;
|
|||
|
transform: rotate(45deg);
|
|||
|
border: 1px solid $neutral--200;
|
|||
|
border-top: none;
|
|||
|
border-left: none;
|
|||
|
border-radius: 2px;
|
|||
|
background-color: #fff;
|
|||
|
}
|
|||
|
|
|||
|
&.first {
|
|||
|
transform: translateX(0);
|
|||
|
|
|||
|
&::before {
|
|||
|
left: 12px;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
&.last {
|
|||
|
transform: translateX(-100%);
|
|||
|
|
|||
|
&::before {
|
|||
|
right: 24px;
|
|||
|
left: auto;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
.grey {
|
|||
|
opacity: 0.48;
|
|||
|
}
|
|||
|
.source {
|
|||
|
&:after {
|
|||
|
content: url('../../assets/icons/catalog/interface-alert-triangle.svg');
|
|||
|
margin-left: 12px;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@media (max-width: $layout-mobile) {
|
|||
|
.title-container {
|
|||
|
flex-wrap: wrap;
|
|||
|
>h2 {
|
|||
|
width: 100%;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
justify-content: space-between;
|
|||
|
}
|
|||
|
>div {
|
|||
|
width: 100%;
|
|||
|
text-align: right;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
</style>
|