Bug 34587: Add data providers components and sub-components

Signed-off-by: Jessica Zairo <jzairo@bywatersolutions.com>
Signed-off-by: Michaela Sieber <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
Matt Blenkinsop 2023-04-27 10:52:52 +00:00 committed by Tomas Cohen Arazi
parent 383f42b6ef
commit 033b683813
No known key found for this signature in database
GPG Key ID: 0A272EA1B2F3C15F
10 changed files with 1673 additions and 0 deletions

View File

@ -95,6 +95,11 @@ export default {
av_package_types: "ERM_PACKAGE_TYPE",
av_package_content_types: "ERM_PACKAGE_CONTENT_TYPE",
av_title_publication_types: "ERM_TITLE_PUBLICATION_TYPE",
av_report_types: "ERM_REPORT_TYPES",
av_platform_reports_metrics: "ERM_PLATFORM_REPORTS_METRICS",
av_database_reports_metrics: "ERM_DATABASE_REPORTS_METRICS",
av_title_reports_metrics: "ERM_TITLE_REPORTS_METRICS",
av_item_reports_metrics: "ERM_ITEM_REPORTS_METRICS",
}
let av_cat_array = Object.keys(authorised_values).map(function (

View File

@ -0,0 +1,103 @@
<template>
<legend>{{ $__("Data provider") }}</legend>
<fieldset class="rows">
<ol>
<li>
<label>{{ $__("Data provider name") }}:</label>
<span id="usage_data_provider_name">
{{ usage_data_provider.name }}
</span>
</li>
<li>
<label>{{ $__("Description") }}:</label>
<span id="usage_data_provider_description">
{{ usage_data_provider.description }}
</span>
</li>
<li>
<label>{{ $__("Status") }}:</label>
<span id="harvester_status">
{{ usage_data_provider.active ? "Active" : "Inactive" }}
</span>
</li>
<li>
<label>{{ $__("Service Type") }}:</label>
<span id="usage_data_provider_service_type">
{{ usage_data_provider.service_type }}
</span>
</li>
<li>
<label>{{ $__("Harvest Start") }}:</label>
<span id="usage_data_provider_begin_date">
{{ usage_data_provider.begin_date }}
</span>
</li>
<li>
<label>{{ $__("Harvest End") }}:</label>
<span id="usage_data_provider_end_date">
{{ usage_data_provider.end_date }}
</span>
</li>
<li>
<label>{{ $__("Report types") }}:</label>
<span id="report_type">
{{ usage_data_provider.report_types }}
</span>
</li>
</ol>
</fieldset>
<legend>{{ $__("Sushi credentials") }}</legend>
<fieldset class="rows">
<ol>
<li>
<label>{{ $__("Service URL") }}:</label>
<span id="usage_data_provider_service_url">
{{ usage_data_provider.service_url }}
</span>
</li>
<li>
<label>{{ $__("Report Release") }}:</label>
<span id="usage_data_provider_report_release">
{{ usage_data_provider.report_release }}
</span>
</li>
<li>
<label>{{ $__("Customer Id") }}:</label>
<span id="usage_data_provider_customer_id">
{{ usage_data_provider.customer_id }}
</span>
</li>
<li>
<label>{{ $__("Requestor Id") }}:</label>
<span id="usage_data_provider_requestor_id">
{{ usage_data_provider.requestor_id }}
</span>
</li>
<li>
<label>{{ $__("API Key") }}:</label>
<span id="usage_data_provider_api_key">
{{ usage_data_provider.api_key }}
</span>
</li>
<li>
<label>{{ $__("Requestor Name") }}:</label>
<span id="usage_data_provider_requestor_name">
{{ usage_data_provider.requestor_name }}
</span>
</li>
<li>
<label>{{ $__("Requestor Email") }}:</label>
<span id="usage_data_provider_requestor_email">
{{ usage_data_provider.requestor_email }}
</span>
</li>
</ol>
</fieldset>
</template>
<script>
export default {
props: ["usage_data_provider"],
name: "UsageStatisticsDataProviderDetails",
}
</script>

View File

@ -0,0 +1,155 @@
<template>
<div v-if="!initialized">{{ $__("Loading") }}</div>
<div v-else id="counter_logs_list">
<div v-if="counter_files_count > 0" class="page-section">
<KohaTable
ref="table"
v-bind="tableOptions"
@delete="delete_counter_file"
@download="download_counter_file"
></KohaTable>
</div>
<div v-else-if="initialized" class="dialog message">
{{ $__("There are no import logs defined") }}
</div>
</div>
</template>
<script>
import { APIClient } from "../../fetch/api-client.js"
import { inject, ref } from "vue"
import KohaTable from "../KohaTable.vue"
export default {
setup() {
const { setConfirmationDialog, setMessage } = inject("mainStore")
const table = ref()
return {
table,
setConfirmationDialog,
setMessage,
}
},
data: function () {
return {
counter_files_count: 0,
initialized: false,
before_route_entered: false,
building_table: false,
tableOptions: {
columns: this.getTableColumns(),
options: { embed: "counter_logs" },
url: () => this.table_url(),
table_settings: this.counter_log_table_settings,
add_filters: true,
filters_options: {},
actions: {
0: ["show"],
"-1": [
{
download: {
text: this.$__("Download"),
icon: "fa fa-download",
},
},
"delete",
],
},
},
}
},
methods: {
async getCounterFiles() {
const client = APIClient.erm
await client.counter_files
.count({
usage_data_provider_id:
this.$route.params.usage_data_provider_id,
})
.then(
// paginated as this request is just to check if there are any counter_files and set this.initialized
count => {
this.counter_files_count = count
this.initialized = true
},
error => {}
)
},
table_url() {
let url = `/api/v1/erm/counter_files?usage_data_provider_id=${this.$route.params.usage_data_provider_id}`
return url
},
download_counter_file(counter_log, dt, event) {
window.location.href =
"/api/v1/erm/counter_files/" +
counter_log.counter_files_id +
"/file/content"
},
delete_counter_file(counter_file, dt, event) {
this.setConfirmationDialog(
{
title: this.$__(
"Are you sure you want to remove this file?"
),
message: counter_file.filename,
accept_label: this.$__("Yes, delete"),
cancel_label: this.$__("No, do not delete"),
},
() => {
const client = APIClient.erm
client.counter_files
.delete(counter_file.erm_counter_files_id)
.then(
success => {
this.setMessage(
this.$__("File %s deleted").format(
counter_file.filename
),
true
)
dt.draw()
},
error => {}
)
}
)
},
getTableColumns() {
return [
{
title: __("Filename"),
data: "filename",
searchable: true,
orderable: true,
},
{
title: __("Import date"),
render: function (data, type, row, meta) {
const date = row.date_uploaded.substr(0, 10)
const time = row.date_uploaded.substr(11, 8)
return `${date} ${time}`
},
searchable: true,
orderable: true,
},
]
},
},
mounted() {
if (!this.building_table) {
this.building_table = true
this.getCounterFiles()
}
},
components: { KohaTable },
name: "UsageStatisticsTitlesList",
}
</script>
<style scoped>
#title_list {
display: table;
}
</style>

View File

@ -0,0 +1,110 @@
<template>
<div class="page-section" id="files">
<form @submit="addDocument($event)" class="file_upload">
<h2>Manual upload:</h2>
<label>{{ $__("File") }}:</label>
<div class="file_information">
<span v-if="!file.filename">
{{ $__("Select a file") }}
<input
type="file"
@change="selectFile($event)"
:id="`import_file`"
:name="`import_file`"
/>
</span>
<ol>
<li v-show="file.filename">
{{ $__("File name") }}:
<span>{{ file.filename }}</span>
</li>
<li v-show="file.file_type">
{{ $__("File type") }}:
<span>{{ file.file_type }}</span>
</li>
</ol>
</div>
<fieldset class="action">
<ButtonSubmit />
<a @click="clearForm($event)" role="button" class="cancel">{{
$__("Clear form")
}}</a>
</fieldset>
</form>
</div>
</template>
<script>
import { inject } from "vue"
import ButtonSubmit from "../ButtonSubmit.vue"
import { storeToRefs } from "pinia"
import { APIClient } from "../../fetch/api-client.js"
export default {
data() {
return {
file: {
filename: null,
usage_data_provider_id: null,
file_type: null,
file_content: null,
date: null,
date_uploaded: null,
},
}
},
methods: {
selectFile(e) {
let files = e.target.files
if (!files) return
let file = files[0]
const reader = new FileReader()
reader.onload = e => this.loadFile(file.name, e.target.result)
reader.readAsBinaryString(file)
},
loadFile(filename, content) {
this.file.filename = filename
this.file.file_content = btoa(content)
},
addDocument(e) {
e.preventDefault()
// Harvesting and import to happen here
},
clearForm(e) {
e.preventDefault()
this.file = {
filename: null,
usage_data_provider_id: null,
file_type: null,
file_content: null,
date: null,
date_uploaded: null,
}
},
async getDataProvider(usage_data_provider_id) {
const client = APIClient.erm
await client.usage_data_providers.get(usage_data_provider_id).then(
usage_data_provider => {
this.file.usage_data_provider_id =
usage_data_provider.erm_usage_data_provider_id
},
error => {}
)
},
},
mounted() {
this.getDataProvider(this.$route.params.usage_data_provider_id)
},
components: {
ButtonSubmit,
},
name: "UsageStatisticsDataProvidersFileImport",
}
</script>
<style scoped>
label {
margin: 0px 10px 0px 0px;
}
</style>

View File

@ -0,0 +1,391 @@
<template>
<div v-if="!initialized">{{ $__("Loading") }}</div>
<div v-else id="data_providers_add">
<h2 v-if="usage_data_provider.erm_usage_data_provider_id">
{{
$__("Edit usage data provider #%s").format(
usage_data_provider.erm_usage_data_provider_id
)
}}
</h2>
<h2 v-else>{{ $__("New usage data provider") }}</h2>
<div class="page-section">
<form @submit="onSubmit($event)">
<!-- <div class="page-section"> This is on other components such as AgreementsFormAdd.vue and just makes it look messy - what purpose is it serving?-->
<legend>{{ $__("Data provider") }}</legend>
<fieldset class="rows">
<ol>
<li>
<label
class="required"
for="usage_data_provider_name"
>{{ $__("Data provider name") }}:</label
>
<input
id="usage_data_provider_name"
v-model="usage_data_provider.name"
:placeholder="$__('Data provider name')"
required
/>
<span class="required">{{ $__("Required") }}</span>
</li>
<li>
<label for="usage_data_provider_description"
>{{ $__("Description") }}:
</label>
<textarea
id="usage_data_provider_description"
v-model="usage_data_provider.description"
:placeholder="$__('Description')"
rows="10"
cols="50"
/>
</li>
<li>
<label for="usage_data_provider_status"
>{{ $__("Harvester status") }}:</label
>
<v-select
id="harvester_status"
v-model="usage_data_provider.active"
label="description"
:reduce="status => status.value"
:options="statuses"
/>
</li>
<!-- <li>
<label for="usage_data_provider_method"
>{{ $__("Method") }}:
</label>
<input
id="usage_data_provider_method"
v-model="usage_data_provider.method"
/>
</li>
<li>
<label for="usage_data_provider_aggregator"
>{{ $__("Aggregator") }}:
</label>
<input
id="usage_data_provider_aggregator"
v-model="usage_data_provider.aggregator"
/>
</li> -->
<li>
<label for="usage_data_provider_service_type"
>{{ $__("Service type") }}:
</label>
<input
id="usage_data_provider_service_type"
v-model="usage_data_provider.service_type"
/>
</li>
<li>
<label for="usage_data_provider_begin_date"
>{{ $__("Harvest start date") }}:
</label>
<flat-pickr
id="usage_data_provider_begin_date"
v-model="usage_data_provider.begin_date"
:config="fp_config"
data-date_to="usage_data_provider_end_date"
/>
</li>
<li>
<label for="usage_data_provider_end_date"
>{{ $__("Harvest end date") }}:
</label>
<flat-pickr
id="usage_data_provider_end_date"
v-model="usage_data_provider.end_date"
:config="fp_config"
/>
</li>
<li>
<label
class="required"
for="usage_data_provider_report_types"
>{{ $__("Report types") }}:
</label>
<v-select
id="report_type"
v-model="usage_data_provider.report_types"
label="description"
:reduce="av => av.value"
:options="av_report_types"
multiple
:required="
!usage_data_provider.report_types.length
"
>
<template #search="{ attributes, events }">
<input
:required="
!usage_data_provider.report_types
.length
"
class="vs__search"
v-bind="attributes"
v-on="events"
/>
</template>
</v-select>
<span class="required">{{ $__("Required") }}</span>
</li>
</ol>
</fieldset>
<legend>{{ $__("Sushi credentials") }}</legend>
<fieldset class="rows">
<ol>
<li>
<label
class="required"
for="usage_data_provider_service_url"
>{{ $__("Service URL") }}:
</label>
<input
id="usage_data_provider_service_url"
v-model="usage_data_provider.service_url"
required
/>
<span class="required">{{ $__("Required") }}</span>
</li>
<li>
<label
class="required"
for="usage_data_provider_report_release"
>{{ $__("Report release") }}:
</label>
<input
id="usage_data_provider_report_release"
v-model="usage_data_provider.report_release"
required
/>
<span class="required">{{ $__("Required") }}</span>
</li>
<li>
<label
class="required"
for="usage_data_provider_customer_id"
>{{ $__("Customer Id") }}:
</label>
<input
id="usage_data_provider_customer_id"
v-model="usage_data_provider.customer_id"
required
/>
<span class="required">{{ $__("Required") }}</span>
</li>
<li>
<label
class="required"
for="usage_data_provider_requestor_id"
>{{ $__("Requestor Id") }}:
</label>
<input
id="usage_data_provider_requestor_id"
v-model="usage_data_provider.requestor_id"
required
/>
<span class="required">{{ $__("Required") }}</span>
</li>
<li>
<label for="usage_data_provider_api_key"
>{{ $__("API key") }}:
</label>
<input
id="usage_data_provider_api_key"
v-model="usage_data_provider.api_key"
/>
</li>
<li>
<label for="usage_data_provider_requestor_name"
>{{ $__("Requestor name") }}:
</label>
<input
id="usage_data_provider_requestor_name"
v-model="usage_data_provider.requestor_name"
/>
</li>
<li>
<label for="usage_data_provider_requestor_email"
>{{ $__("Requestor email") }}:
</label>
<input
id="usage_data_provider_requestor_email"
v-model="usage_data_provider.requestor_email"
/>
</li>
</ol>
</fieldset>
<fieldset class="action">
<ButtonSubmit />
<router-link
v-if="previous_route === 'data_provider_show'"
:to="{ name: 'UsageStatisticsDataProvidersShow' }"
role="button"
class="cancel"
>{{ $__("Cancel") }}</router-link
>
<router-link
v-else
:to="{ name: 'UsageStatisticsDataProvidersList' }"
role="button"
class="cancel"
>{{ $__("Cancel") }}</router-link
>
</fieldset>
</form>
</div>
</div>
</template>
<script>
import ButtonSubmit from "../ButtonSubmit.vue"
import { setMessage, setError, setWarning } from "../../messages"
import { APIClient } from "../../fetch/api-client.js"
import { inject } from "vue"
import { storeToRefs } from "pinia"
import flatPickr from "vue-flatpickr-component"
export default {
setup() {
const AVStore = inject("AVStore")
const { av_report_types } = storeToRefs(AVStore)
return {
av_report_types,
}
},
data() {
return {
usage_data_provider: {
erm_usage_data_provider_id: null,
name: "",
description: "",
active: 1,
method: "",
aggregator: "",
service_type: "",
service_url: "",
report_release: "",
begin_date: null,
end_date: null,
customer_id: "",
requestor_id: "",
api_key: "",
requestor_name: "",
requestor_email: "",
report_types: [],
},
initialized: false,
previous_route: "",
statuses: [
{ description: "Active", value: 1 },
{ description: "Inactive", value: 0 },
],
fp_config: flatpickr_defaults,
}
},
beforeRouteEnter(to, from, next) {
next(vm => {
if (to.params.usage_data_provider_id) {
vm.getDataProvider(to.params.usage_data_provider_id)
} else {
vm.initialized = true
}
if (from.params.usage_data_provider_id) {
vm.previous_route = "data_provider_show"
} else {
vm.previous_route = "data_provider_list"
}
})
},
methods: {
async getDataProvider(erm_usage_data_provider_id) {
const client = APIClient.erm
client.usage_data_providers.get(erm_usage_data_provider_id).then(
usage_data_provider => {
this.usage_data_provider = usage_data_provider
this.usage_data_provider.report_types =
this.formatReportTypes(usage_data_provider.report_types)
this.initialized = true
},
error => {}
)
},
formatReportTypes(reportTypes) {
const dataType =
typeof reportTypes === "string" ? "string" : "array"
if (dataType === "array") {
let report_types_string = ""
reportTypes.forEach(item => {
report_types_string += item
report_types_string += ";"
})
return report_types_string
}
if (dataType === "string") {
const single_report_types = reportTypes.split(";")
single_report_types.pop() // remove trailing "" from array
return single_report_types
}
},
onSubmit(e) {
e.preventDefault()
let usage_data_provider = JSON.parse(
JSON.stringify(this.usage_data_provider)
)
let erm_usage_data_provider_id =
usage_data_provider.erm_usage_data_provider_id
usage_data_provider.report_types = this.formatReportTypes(
usage_data_provider.report_types
)
delete usage_data_provider.erm_usage_data_provider_id
const client = APIClient.erm
if (erm_usage_data_provider_id) {
client.usage_data_providers
.update(usage_data_provider, erm_usage_data_provider_id)
.then(
success => {
setMessage(this.$__("Data provider updated"))
this.$router.push({
name: "UsageStatisticsDataProvidersShow",
params: {
usage_data_provider_id:
erm_usage_data_provider_id,
},
})
},
error => {}
)
} else {
client.usage_data_providers.create(usage_data_provider).then(
success => {
erm_usage_data_provider_id =
success.erm_usage_data_provider_id
setMessage(this.$__("Data provider created"))
this.$router.push({
name: "UsageStatisticsDataProvidersShow",
params: {
usage_data_provider_id:
erm_usage_data_provider_id,
},
})
},
error => {}
)
}
},
},
components: {
ButtonSubmit,
flatPickr,
},
name: "UsageStatisticsDataProvidersFormAdd",
}
</script>

View File

@ -0,0 +1,297 @@
<template>
<div v-if="!initialized">{{ $__("Loading") }}</div>
<div v-else id="usage_data_providers_list">
<template class="toolbar_options">
<Toolbar />
<div
v-if="usage_data_provider_count > 0"
id="toolbar"
class="btn-toolbar"
>
<router-link
:to="{ name: 'UsageStatisticsDataProvidersSummary' }"
class="btn btn-default"
>
<i class="fa fa-list"></i>
{{ $__("Data providers summary") }}</router-link
>
</div>
</template>
<div v-if="usage_data_provider_count > 0" class="page-section">
<KohaTable
ref="table"
v-bind="tableOptions"
@show="show_usage_data_provider"
@edit="edit_usage_data_provider"
@delete="delete_usage_data_provider"
@run_now="run_harvester_now"
></KohaTable>
</div>
<div v-else-if="initialized" class="dialog message">
{{ $__("There are no usage data providers defined") }}
</div>
</div>
</template>
<script>
import Toolbar from "./UsageStatisticsDataProvidersToolbar.vue"
import { inject, ref } from "vue"
import { APIClient } from "../../fetch/api-client.js"
import KohaTable from "../KohaTable.vue"
export default {
setup() {
const AVStore = inject("AVStore") // Left in for future permissions fixes
const { get_lib_from_av, map_av_dt_filter } = AVStore
const { setConfirmationDialog, setMessage } = inject("mainStore")
const table = ref()
return {
get_lib_from_av,
map_av_dt_filter,
setConfirmationDialog,
setMessage,
table,
}
},
data: function () {
return {
usage_data_provider_count: 0,
initialized: false,
building_table: false,
tableOptions: {
columns: this.getTableColumns(),
options: { embed: "counter_files" },
url: () => this.table_url(),
table_settings: this.usage_data_provider_table_settings,
add_filters: true,
actions: {
0: ["show"],
"-1": [
{
run_now: {
text: this.$__("Run now"),
icon: "fa fa-play",
},
},
"edit",
"delete",
],
},
},
}
},
methods: {
async getUsageDataProviderCount() {
const client = APIClient.erm
await client.usage_data_providers.count().then(
count => {
this.usage_data_provider_count = count
this.initialized = true
},
error => {}
)
},
table_url() {
let url = "/api/v1/erm/usage_data_providers"
return url
},
show_usage_data_provider(usage_data_provider, dt, event) {
event.preventDefault()
this.$router.push({
name: "UsageStatisticsDataProvidersShow",
params: {
usage_data_provider_id:
usage_data_provider.erm_usage_data_provider_id,
},
})
},
edit_usage_data_provider(usage_data_provider, dt, event) {
this.$router.push({
name: "UsageStatisticsDataProvidersFormAddEdit",
params: {
usage_data_provider_id:
usage_data_provider.erm_usage_data_provider_id,
},
})
},
delete_usage_data_provider(usage_data_provider, dt, event) {
this.setConfirmationDialog(
{
title: this.$__(
"Are you sure you want to remove this data provider?"
),
message: usage_data_provider.name,
accept_label: this.$__("Yes, delete"),
cancel_label: this.$__("No, do not delete"),
},
() => {
const client = APIClient.erm
client.usage_data_providers
.delete(usage_data_provider.erm_usage_data_provider_id)
.then(
success => {
this.setMessage(
this.$__("Data provider %s deleted").format(
usage_data_provider.name
),
true
)
dt.draw()
},
error => {}
)
}
)
},
run_harvester_now(usage_data_provider, dt, event) {
const { erm_usage_data_provider_id: id, name } = usage_data_provider
if (!usage_data_provider.active) {
this.setConfirmationDialog(
{
title: this.$__(
"This data provider is set to 'Inactive', do you wish to update the status to 'Active'?"
),
message: name,
accept_label: this.$__("Yes, update status"),
cancel_label: this.$__("No, do not update status"),
},
() => {
usage_data_provider.active = 1
delete usage_data_provider.erm_usage_data_provider_id
const counter_files = usage_data_provider.counter_files
delete usage_data_provider.counter_files
const client = APIClient.erm
client.usage_data_providers
.update(usage_data_provider, id)
.then(
success => {
this.setMessage(
this.$__(
"Updated status for usage data provider %s"
).format(name),
true
)
usage_data_provider.counter_files =
counter_files
dt.draw()
},
error => {}
)
}
)
} else {
this.setConfirmationDialog(
{
title: this.$__(
"Are you sure you want to run the harvester for this data provider?"
),
message: name,
accept_label: this.$__("Yes, run"),
cancel_label: this.$__("No, do not run"),
},
() => {
const client = APIClient.erm
// TODO: below begin_date and end_date need to be dynamic, or are they needed at all?
client.usage_data_providers
.run(id, "2022-06-01", "2022-12-31")
.then(
success => {
this.setMessage(
this.$__(
"Ran harvester for usage data provider %s"
).format(name),
true
)
},
error => {}
)
}
)
}
},
getTableColumns() {
return [
{
title: __("Name"),
data: "me.erm_usage_data_provider_id:me.name",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
return (
'<a href="/cgi-bin/koha/erm/eusage/usage_data_providers/' +
row.erm_usage_data_provider_id +
'" class="show">' +
escape_str(
`${row.name} (#${row.erm_usage_data_provider_id})`
) +
"</a>"
)
},
},
{
title: __("Description"),
data: "description",
searchable: true,
orderable: true,
},
{
title: __("Status"),
render: function (data, type, row, meta) {
const status = row.active ? "Active" : "Inactive"
return status
},
searchable: true,
orderable: true,
},
{
title: __("Last run"),
render: function (data, type, row, meta) {
const counter_files = row.counter_files
if (counter_files.length === 0) {
return "No run history found"
}
const findMostRecent = counter_files.sort(
(a, b) =>
new Date(b.date_uploaded) -
new Date(a.date_uploaded)
)
const date = findMostRecent[0].date_uploaded.substr(
0,
10
)
const time = findMostRecent[0].date_uploaded.substr(
11,
8
)
return `${date} ${time}`
},
searchable: true,
orderable: true,
},
]
},
},
mounted() {
if (!this.building_table) {
this.building_table = true
this.getUsageDataProviderCount()
}
},
components: { Toolbar, KohaTable },
name: "DataProvidersList",
}
</script>
<style scoped>
#usage_data_provider_list {
display: table;
}
.toolbar_options {
display: flex;
}
</style>

View File

@ -0,0 +1,236 @@
<template>
<div v-if="!initialized">{{ $__("Loading") }}</div>
<div v-else id="usage_data_providers_show">
<h2>
{{
$__("Data provider #%s").format(
usage_data_provider.erm_usage_data_provider_id
)
}}
<span class="action_links">
<router-link
:to="{
name: 'UsageStatisticsDataProvidersFormAddEdit',
params: {
usage_data_provider_id:
usage_data_provider.erm_usage_data_provider_id,
},
}"
:title="$__('Edit')"
><i class="fa fa-pencil"></i
></router-link>
<a
@click="
delete_usage_data_provider(
usage_data_provider.erm_usage_data_provider_id,
usage_data_provider.name
)
"
><i class="fa fa-trash"></i
></a>
</span>
</h2>
<div id="usage_data_providerstabs" class="toptabs numbered">
<ul class="nav nav-tabs" role="tablist">
<li
role="presentation"
v-bind:class="tab_content === 'detail' ? 'active' : ''"
>
<a
href="#"
role="tab"
data-content="detail"
@click="change_tab_content"
>Detail</a
>
</li>
<li
role="presentation"
v-bind:class="tab_content === 'titles' ? 'active' : ''"
>
<a
href="#"
role="tab"
data-content="titles"
@click="change_tab_content"
>Titles</a
>
</li>
<li
role="presentation"
v-bind:class="tab_content === 'upload' ? 'active' : ''"
>
<a
href="#"
role="tab"
data-content="upload"
@click="change_tab_content"
>Manual upload</a
>
</li>
<li
role="presentation"
v-bind:class="tab_content === 'imports' ? 'active' : ''"
>
<a
href="#"
role="tab"
data-content="imports"
@click="change_tab_content"
>Import logs</a
>
</li>
</ul>
</div>
<div class="tab-content">
<div
v-if="tab_content === 'detail'"
class="usage_data_provider_detail"
>
<UsageStatisticsDataProviderDetails
:usage_data_provider="usage_data_provider"
/>
</div>
<div v-if="tab_content === 'titles'">
<UsageStatisticsTitlesList />
</div>
<div v-if="tab_content === 'upload'">
<UsageStatisticsDataProvidersFileImport />
</div>
<div v-if="tab_content === 'imports'">
<UsageStatisticsDataProvidersCounterLogs />
</div>
</div>
<fieldset class="action">
<router-link
:to="{ name: 'UsageStatisticsDataProvidersList' }"
role="button"
class="cancel"
>{{ $__("Close") }}</router-link
>
</fieldset>
</div>
</template>
<script>
import { inject } from "vue"
import { APIClient } from "../../fetch/api-client.js"
import UsageStatisticsTitlesList from "./UsageStatisticsTitlesList.vue"
import UsageStatisticsDataProvidersFileImport from "./UsageStatisticsDataProvidersFileImport.vue"
import UsageStatisticsDataProvidersCounterLogs from "./UsageStatisticsDataProvidersCounterLogs.vue"
import UsageStatisticsDataProviderDetails from "./UsageStatisticsDataProviderDetails.vue"
export default {
setup() {
const AVStore = inject("AVStore")
const { get_lib_from_av } = AVStore
const { setConfirmationDialog, setMessage } = inject("mainStore")
return {
get_lib_from_av,
setConfirmationDialog,
setMessage,
}
},
data() {
return {
usage_data_provider: {
erm_usage_data_provider_id: null,
name: "",
description: "",
active: 1,
method: "",
aggregator: "",
service_type: "",
service_url: "",
report_release: "",
begin_date: null,
end_date: null,
customer_id: "",
requestor_id: "",
api_key: "",
requestor_name: "",
requestor_email: "",
report_types: [],
},
initialized: false,
tab_content: "detail",
}
},
beforeRouteEnter(to, from, next) {
next(vm => {
vm.getUsageDataProvider(to.params.usage_data_provider_id)
})
},
methods: {
async getUsageDataProvider(usage_data_provider_id) {
const client = APIClient.erm
client.usage_data_providers.get(usage_data_provider_id).then(
usage_data_provider => {
this.usage_data_provider = usage_data_provider
this.initialized = true
},
error => {}
)
},
change_tab_content(e) {
this.tab_content = e.target.getAttribute("data-content")
},
delete_usage_data_provider: function (
usage_data_provider_id,
usage_data_provider_name
) {
this.setConfirmationDialog(
{
title: this.$__(
"Are you sure you want to remove this data provider?"
),
message: usage_data_provider_name,
accept_label: this.$__("Yes, delete"),
cancel_label: this.$__("No, do not delete"),
},
() => {
const client = APIClient.erm
client.usage_data_providers
.delete(usage_data_provider_id)
.then(
success => {
this.setMessage(
this.$__(
"Usage data provider %s deleted"
).format(usage_data_provider_name),
true
)
this.$router.push({
name: "UsageStatisticsDataProvidersList",
})
},
error => {}
)
}
)
},
},
name: "UsageStatisticsDataProvidersShow",
components: {
UsageStatisticsTitlesList,
UsageStatisticsDataProvidersFileImport,
UsageStatisticsDataProvidersCounterLogs,
UsageStatisticsDataProviderDetails,
},
}
</script>
<style scoped>
.action_links a {
padding-left: 0.2em;
font-size: 11px;
cursor: pointer;
}
.active {
cursor: pointer;
}
.rows {
float: none;
}
</style>

View File

@ -0,0 +1,249 @@
<template>
<div v-if="!initialized">{{ $__("Loading") }}</div>
<div
v-else-if="usage_data_providers.length"
id="usage_data_providers_summary"
>
<div id="toolbar" class="btn-toolbar">
<router-link
:to="{ name: 'UsageStatisticsDataProvidersList' }"
class="btn btn-default"
>
<i class="fa fa-list"></i>
{{ $__("Data providers list") }}</router-link
>
</div>
<div
v-if="usage_data_providers.length"
class="page-section hide-table"
ref="table_div"
>
<KohaTable ref="table" v-bind="tableOptions"></KohaTable>
</div>
</div>
</template>
<script>
import Toolbar from "./UsageStatisticsDataProvidersToolbar.vue"
import { inject, ref } from "vue"
import { APIClient } from "../../fetch/api-client.js"
import KohaTable from "../KohaTable.vue"
export default {
setup() {
const AVStore = inject("AVStore") // Left in for future permissions fixes
const { get_lib_from_av, map_av_dt_filter } = AVStore
const { setConfirmationDialog, setMessage } = inject("mainStore")
const table = ref()
return {
get_lib_from_av,
map_av_dt_filter,
setConfirmationDialog,
setMessage,
table,
}
},
data: function () {
return {
usage_data_providers: [],
initialized: false,
building_table: false,
tableOptions: {
columns: this.getTableColumns(),
options: { embed: "counter_files" },
url: () => this.table_url(),
table_settings: this.usage_data_provider_table_settings,
// add_filters: true,
actions: {},
},
}
},
methods: {
async getUsageDataProviders() {
const client = APIClient.erm
await client.usage_data_providers.getAll().then(
usage_data_providers => {
this.usage_data_providers = usage_data_providers
this.initialized = true
},
error => {}
)
},
table_url() {
let url = "/api/v1/erm/usage_data_providers"
return url
},
getEarliestDate(row, identifier) {
const counter_files = row.counter_files.filter(file =>
file.type.includes(identifier)
)
if (counter_files.length === 0) {
return "Not run"
}
const findData = counter_files.sort(
(a, b) => new Date(a.date_uploaded) - new Date(b.date_uploaded)
)
const date = findData[0].date_uploaded.substr(0, 10)
return `${date}`
},
getLatestDate(row, identifier) {
const counter_files = row.counter_files.filter(file =>
file.type.includes(identifier)
)
if (counter_files.length === 0) {
return "Not run"
}
const findData = counter_files.sort(
(a, b) => new Date(b.date_uploaded) - new Date(a.date_uploaded)
)
const date = findData[0].date_uploaded.substr(0, 10)
return `${date}`
},
getTableColumns() {
const getEarliestDate = this.getEarliestDate
const getLatestDate = this.getLatestDate
return [
{
title: __("Provider"),
data: "me.erm_usage_data_provider_id:me.name",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
return row.name
},
},
{
title: __("Start"),
data: "description",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
const date = getEarliestDate(row, "TR")
return date
},
},
{
title: __("End"),
data: "description",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
const date = getLatestDate(row, "TR")
return date
},
},
{
title: __("Start"),
data: "description",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
const date = getEarliestDate(row, "PR")
return date
},
},
{
title: __("End"),
data: "description",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
const date = getLatestDate(row, "PR")
return date
},
},
{
title: __("Start"),
data: "description",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
const date = getEarliestDate(row, "DR")
return date
},
},
{
title: __("End"),
data: "description",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
const date = getLatestDate(row, "PR")
return date
},
},
{
title: __("Start"),
data: "description",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
const date = getEarliestDate(row, "IR")
return date
},
},
{
title: __("End"),
data: "description",
searchable: true,
orderable: true,
render: function (data, type, row, meta) {
const date = getLatestDate(row, "IR")
return date
},
},
]
},
createTableHeader() {
const table = this.$refs.table.$el.getElementsByTagName("table")[0]
const row = table.insertRow(0)
const [cellOne, cellTwo, cellThree, cellFour, cellFive] = [
...Array(5).keys(),
].map(item => {
const cell = document.createElement("th")
row.appendChild(cell)
return cell
})
cellTwo.colSpan = 2
cellTwo.innerHTML = "Title reports"
cellThree.colSpan = 2
cellThree.innerHTML = "Platform reports"
cellFour.colSpan = 2
cellFour.innerHTML = "Database reports"
cellFive.colSpan = 2
cellFive.innerHTML = "Item reports"
this.$refs.table_div.classList.remove("hide-table")
},
},
watch: {
table() {
// table needs to be rendered before header can be created and
// table is hidden by .hide-table until table header is created
this.createTableHeader()
},
},
mounted() {
if (!this.building_table) {
this.building_table = true
this.getUsageDataProviders()
}
},
components: { Toolbar, KohaTable },
name: "UsageStatisticsDataProvidersSummary",
}
</script>
<style scoped>
#usage_data_provider_summary {
display: table;
}
.hide-table {
display: none;
}
</style>

View File

@ -0,0 +1,16 @@
<template>
<div id="toolbar" class="btn-toolbar">
<router-link
:to="{ name: 'UsageStatisticsDataProvidersFormAdd' }"
class="btn btn-default"
><font-awesome-icon icon="plus" />
{{ $__("New data provider") }}</router-link
>
</div>
</template>
<script>
export default {
name: "UsageStatisticsDataProvidersToolbar",
}
</script>

View File

@ -0,0 +1,111 @@
<template>
<div v-if="!initialized">{{ $__("Loading") }}</div>
<div v-else id="titles_list">
<div v-if="titles_count > 0" class="page-section">
<KohaTable ref="table" v-bind="tableOptions"></KohaTable>
</div>
<div v-else-if="initialized" class="dialog message">
{{ $__("No title data has been harvested for this provider") }}
</div>
</div>
</template>
<script>
import { APIClient } from "../../fetch/api-client.js"
import { ref } from "vue"
import KohaTable from "../KohaTable.vue"
export default {
setup() {
const table = ref()
return {
table,
}
},
data: function () {
return {
titles_count: 0,
initialized: false,
before_route_entered: false,
building_table: false,
tableOptions: {
columns: this.getTableColumns(),
options: {},
url: () => this.table_url(),
table_settings: this.title_table_settings,
add_filters: true,
},
}
},
methods: {
async getTitles() {
const client = APIClient.erm
await client.usage_titles
.count({
usage_data_provider_id:
this.$route.params.usage_data_provider_id,
})
.then(
count => {
this.titles_count = count
this.initialized = true
},
error => {}
)
},
table_url() {
let url = `/api/v1/erm/usage_titles?usage_data_provider_id=${this.$route.params.usage_data_provider_id}`
return url
},
getTableColumns() {
return [
{
title: __("Title"),
data: "title",
searchable: true,
orderable: true,
},
{
title: __("DOI"),
data: "title_doi",
searchable: true,
orderable: true,
},
{
title: __("Print ISSN"),
data: "print_issn",
searchable: true,
orderable: true,
},
{
title: __("Online ISSN"),
data: "online_issn",
searchable: true,
orderable: true,
},
{
title: __("URI"),
data: "title_uri",
searchable: true,
orderable: true,
},
]
},
},
mounted() {
if (!this.building_table) {
this.building_table = true
this.getTitles()
}
},
components: { KohaTable },
name: "UsageStatisticsTitlesList",
}
</script>
<style scoped>
#title_list {
display: table;
}
</style>