View | Details | Raw Unified | Return to bug 39320
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ModuleDashboard/Widgets/ERMCounts.vue (+144 lines)
Line 0 Link Here
1
<template>
2
    <WidgetWrapper v-bind="widgetWrapperProps">
3
        <template #default>
4
            <p class="text-left">
5
                {{ $__("There are") }}
6
                <template
7
                    v-for="(definition, index) in countDefinitions"
8
                    :key="index"
9
                >
10
                    <strong>
11
                        <a
12
                            v-if="definition.page"
13
                            href="#"
14
                            @click.prevent="goToPage(definition.page)"
15
                        >
16
                            {{ definition.count }}
17
                            <span v-if="definition.count === 1">{{
18
                                definition.labelSingular
19
                            }}</span>
20
                            <span v-else>{{ definition.labelPlural }}</span>
21
                        </a>
22
                        <span v-else>
23
                            {{ definition.count }}
24
                            <span v-if="definition.count === 1">{{
25
                                definition.labelSingular
26
                            }}</span>
27
                            <span v-else>{{ definition.labelPlural }}</span>
28
                        </span>
29
                    </strong>
30
                    <template v-if="index < countDefinitions.length - 1"
31
                        >,&nbsp;</template
32
                    >
33
                    <template v-else>.</template>
34
                </template>
35
            </p>
36
        </template>
37
    </WidgetWrapper>
38
</template>
39
<script>
40
import { reactive } from "vue";
41
import { useBaseWidget } from "../../../composables/base-widget.js";
42
import { APIClient } from "../../../fetch/api-client.js";
43
import WidgetWrapper from "../WidgetWrapper.vue";
44
import { useRouter } from "vue-router";
45
import { $__ } from "@koha-vue/i18n";
46
47
export default {
48
    name: "ERMCounts",
49
    components: { WidgetWrapper },
50
    props: {
51
        display: String,
52
    },
53
    emits: ["removed", "added", "moveWidget"],
54
    setup(props, { emit }) {
55
        const router = useRouter();
56
        const baseWidget = useBaseWidget(
57
            {
58
                id: "ERMCounts",
59
                name: $__("Counts"),
60
                icon: "fas fa-chart-bar",
61
                description: $__(
62
                    "Shows the number of ERM related resources such as agreements, licenses, local packages, local titles, documents, etc."
63
                ),
64
                ...props,
65
            },
66
            emit
67
        );
68
        const countDefinitions = reactive([
69
            {
70
                page: "AgreementsList",
71
                name: "agreements_count",
72
                labelSingular: __("agreement"),
73
                labelPlural: __("agreements"),
74
                count: 0,
75
            },
76
            {
77
                page: "LicensesList",
78
                name: "licenses_count",
79
                labelSingular: __("license"),
80
                labelPlural: __("licenses"),
81
                count: 0,
82
            },
83
            {
84
                name: "documents_count",
85
                labelSingular: __("document"),
86
                labelPlural: __("documents"),
87
                count: 0,
88
            },
89
            {
90
                page: "EHoldingsLocalPackagesList",
91
                name: "eholdings_packages_count",
92
                labelSingular: __("local package"),
93
                labelPlural: __("local packages"),
94
                count: 0,
95
            },
96
            {
97
                page: "EHoldingsLocalTitlesList",
98
                name: "eholdings_titles_count",
99
                labelSingular: __("local title"),
100
                labelPlural: __("local titles"),
101
                count: 0,
102
            },
103
            {
104
                page: "UsageStatisticsDataProvidersList",
105
                name: "usage_data_providers_count",
106
                labelSingular: __("usage data provider"),
107
                labelPlural: __("usage data providers"),
108
                count: 0,
109
            },
110
        ]);
111
112
        async function getCounts() {
113
            try {
114
                const response = await APIClient.erm.counts.get();
115
116
                Object.keys(response.counts).forEach(key => {
117
                    const item = countDefinitions.find(i => i.name === key);
118
                    if (item) {
119
                        item.count = response.counts[key];
120
                    }
121
                });
122
123
                baseWidget.loading.value = false;
124
            } catch (error) {
125
                console.error(error);
126
            }
127
        }
128
129
        baseWidget.onDashboardMounted(() => {
130
            getCounts();
131
        });
132
133
        function goToPage(page) {
134
            router.push({ name: page });
135
        }
136
137
        return {
138
            ...baseWidget,
139
            countDefinitions,
140
            goToPage,
141
        };
142
    },
143
};
144
</script>
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ModuleDashboard/Widgets/ERMLatestSUSHIJobs.vue (+147 lines)
Line 0 Link Here
1
<template>
2
    <WidgetWrapper v-bind="widgetWrapperProps">
3
        <template #default>
4
            <KohaTable
5
                ref="table"
6
                v-bind="tableOptions"
7
                :key="JSON.stringify(tableOptions)"
8
                @view="viewJob"
9
            />
10
        </template>
11
    </WidgetWrapper>
12
</template>
13
14
<script>
15
import { ref, computed } from "vue";
16
import WidgetWrapper from "../WidgetWrapper.vue";
17
import KohaTable from "../../KohaTable.vue";
18
import { useBaseWidget } from "../../../composables/base-widget.js";
19
import { $__ } from "@koha-vue/i18n";
20
21
export default {
22
    name: "ERMLatestSUSHIJobs",
23
    components: { WidgetWrapper, KohaTable },
24
    props: {
25
        display: String,
26
    },
27
    emits: ["removed", "added", "moveWidget"],
28
    setup(props, { emit }) {
29
        const baseWidget = useBaseWidget(
30
            {
31
                id: "ERMLatestSUSHIJobs",
32
                name: $__("Latest SUSHI Counter jobs"),
33
                icon: "fa-solid fa-gears",
34
                description: $__("Show latest SUSHI Counter background jobs."),
35
                loading: false,
36
                ...props,
37
            },
38
            emit
39
        );
40
41
        const table = ref();
42
43
        const job_statuses = [
44
            { _id: "new", _str: $__("New") },
45
            { _id: "cancelled", _str: $__("Cancelled") },
46
            { _id: "finished", _str: $__("Finished") },
47
            { _id: "started", _str: $__("Started") },
48
            { _id: "running", _str: $__("Running") },
49
            { _id: "failed", _str: $__("Failed") },
50
        ];
51
52
        function get_job_status(status) {
53
            const status_lib = job_statuses.find(s => s._id === status);
54
            return status_lib ? status_lib._str : status;
55
        }
56
57
        function getTableColumns() {
58
            return [
59
                {
60
                    title: $__("Status"),
61
                    data: "status",
62
                    searchable: true,
63
                    orderable: true,
64
                    render(data, type, row) {
65
                        return get_job_status(row.status).escapeHtml();
66
                    },
67
                },
68
                {
69
                    title: $__("Data Provider"),
70
                    data: "data",
71
                    searchable: true,
72
                    orderable: true,
73
                    render(data) {
74
                        return (
75
                            '<a href="/cgi-bin/koha/erm/eusage/usage_data_providers/' +
76
                            data.ud_provider_id +
77
                            '" class="show">' +
78
                            escape_str(data.ud_provider_name) +
79
                            "</a>"
80
                        );
81
                    },
82
                },
83
                {
84
                    title: $__("Started"),
85
                    data: "started_date",
86
                    searchable: true,
87
                    orderable: true,
88
                    render(data, type, row) {
89
                        return $datetime(row.started_date);
90
                    },
91
                },
92
                {
93
                    title: $__("Ended"),
94
                    data: "ended_date",
95
                    searchable: true,
96
                    orderable: true,
97
                    render(data, type, row) {
98
                        return $datetime(row.ended_date);
99
                    },
100
                },
101
            ];
102
        }
103
104
        const tableOptions = computed(() => ({
105
            columns: getTableColumns(),
106
            options: {
107
                dom: "t",
108
                pageLength: 5,
109
                order: [2, "desc"],
110
            },
111
            url: "/api/v1/jobs",
112
            default_filters: {
113
                only_current: 0,
114
                type: "erm_sushi_harvester",
115
            },
116
            actions: {
117
                0: ["show"],
118
                "-1": [
119
                    {
120
                        view: {
121
                            text: $__("View"),
122
                            icon: "fa fa-eye",
123
                        },
124
                    },
125
                ],
126
            },
127
        }));
128
129
        function viewJob(job, dt, event) {
130
            event.preventDefault();
131
            window.open(
132
                "/cgi-bin/koha/admin/background_jobs.pl?op=view&id=" +
133
                    encodeURIComponent(job.job_id),
134
                "_blank"
135
            );
136
        }
137
138
        return {
139
            ...baseWidget,
140
            table,
141
            tableOptions,
142
            viewJob,
143
            getTableColumns,
144
        };
145
    },
146
};
147
</script>
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ModuleDashboard/Widgets/ERMLicensesNeedingAction.vue (+199 lines)
Line 0 Link Here
1
<template>
2
    <WidgetWrapper v-bind="widgetWrapperProps">
3
        <template #default>
4
            <KohaTable
5
                ref="table"
6
                v-bind="tableOptions"
7
                :key="JSON.stringify(tableOptions)"
8
            />
9
        </template>
10
    </WidgetWrapper>
11
</template>
12
13
<script>
14
import { inject, ref, computed } from "vue";
15
import { storeToRefs } from "pinia";
16
import WidgetWrapper from "../WidgetWrapper.vue";
17
import KohaTable from "../../KohaTable.vue";
18
import { useBaseWidget } from "../../../composables/base-widget.js";
19
import { $__ } from "@koha-vue/i18n";
20
21
export default {
22
    name: "ERMLicensesNeedingAction",
23
    components: { WidgetWrapper, KohaTable },
24
    props: {
25
        display: String,
26
    },
27
    emits: ["removed", "added", "moveWidget"],
28
    setup(props, { emit }) {
29
        const ERMStore = inject("ERMStore");
30
        const { get_lib_from_av } = ERMStore;
31
        const { authorisedValues } = storeToRefs(ERMStore);
32
        const av_license_statuses = authorisedValues.value.av_license_statuses;
33
34
        const table = ref();
35
        const default_settings = {
36
            status: ["in_negotiation", "not_yet_active", "rejected"],
37
            per_page: 5,
38
        };
39
        const settings = ref(default_settings);
40
        const settings_definitions = ref([
41
            {
42
                name: "status",
43
                type: "select",
44
                label: __("Status"),
45
                showInTable: true,
46
                options: av_license_statuses.map(status => ({
47
                    value: status.value,
48
                    description: status.description,
49
                })),
50
                allowMultipleChoices: true,
51
                requiredKey: "value",
52
                selectLabel: "description",
53
            },
54
            {
55
                name: "ended_on",
56
                type: "select",
57
                label: __("Ends in the next"),
58
                showInTable: true,
59
                options: [
60
                    { value: "week", description: __("Week") },
61
                    { value: "two_weeks", description: __("Two weeks") },
62
                    { value: "month", description: __("Month") },
63
                    { value: "two_months", description: __("Two months") },
64
                ],
65
                requiredKey: "value",
66
                selectLabel: "description",
67
            },
68
            {
69
                name: "per_page",
70
                type: "select",
71
                label: __("Show"),
72
                showInTable: true,
73
                options: [
74
                    { value: 5, description: "5" },
75
                    { value: 10, description: "10" },
76
                    { value: 20, description: "20" },
77
                ],
78
                requiredKey: "value",
79
                selectLabel: "description",
80
            },
81
        ]);
82
83
        function settingsToQueryParams(settings) {
84
            const params = {};
85
86
            if (settings.status && settings.status.length > 0) {
87
                params["me.status"] = {
88
                    "-in": settings.status,
89
                };
90
            }
91
92
            if (settings.ended_on) {
93
                const now = new Date();
94
                let limitDate;
95
96
                switch (settings.ended_on) {
97
                    case "week":
98
                        limitDate = new Date(now.setDate(now.getDate() + 7));
99
                        break;
100
                    case "two_weeks":
101
                        limitDate = new Date(now.setDate(now.getDate() + 14));
102
                        break;
103
                    case "month":
104
                        limitDate = new Date(now.setMonth(now.getMonth() + 1));
105
                        break;
106
                    case "two_months":
107
                        limitDate = new Date(now.setMonth(now.getMonth() + 2));
108
                        break;
109
                }
110
111
                if (limitDate) {
112
                    params["me.ended_on"] = { "<=": limitDate };
113
                }
114
            }
115
116
            return params;
117
        }
118
119
        const tableOptions = computed(() => ({
120
            columns: [
121
                {
122
                    title: __("Name"),
123
                    data: "name",
124
                    searchable: true,
125
                    orderable: true,
126
                    render(data, type, row) {
127
                        const name = escape_str(row.name);
128
                        const shortName =
129
                            name.length > 25
130
                                ? name.substring(0, 22) + "..."
131
                                : name;
132
                        return `<a href="/cgi-bin/koha/erm/licenses/${row.license_id}" class="show">${shortName}</a>`;
133
                    },
134
                },
135
                {
136
                    title: __("Type"),
137
                    data: "type",
138
                    searchable: true,
139
                    orderable: true,
140
                    render(data, type, row) {
141
                        return escape_str(
142
                            get_lib_from_av("av_license_types", row.type)
143
                        );
144
                    },
145
                },
146
                {
147
                    title: __("Status"),
148
                    data: "status",
149
                    searchable: true,
150
                    orderable: true,
151
                    render(data, type, row) {
152
                        return escape_str(
153
                            get_lib_from_av("av_license_statuses", row.status)
154
                        );
155
                    },
156
                },
157
                {
158
                    title: __("Ends on"),
159
                    data: "ended_on",
160
                    searchable: true,
161
                    orderable: true,
162
                    render(data, type, row) {
163
                        return $date(row.ended_on);
164
                    },
165
                },
166
            ],
167
            options: {
168
                dom: "t",
169
                embed: "vendor,extended_attributes,+strings",
170
                pageLength: settings.value.per_page || 5,
171
            },
172
            url: "/api/v1/erm/licenses",
173
            default_filters: settingsToQueryParams(settings.value),
174
        }));
175
176
        const baseWidget = useBaseWidget(
177
            {
178
                id: "ERMLicensesNeedingAction",
179
                name: $__("Licenses needing action"),
180
                icon: "fa fa-gavel",
181
                description: $__(
182
                    "Show licenses that need action. It filters licenses by status and end date. This widget is configurable."
183
                ),
184
                loading: false,
185
                settings: settings,
186
                settings_definitions: settings_definitions,
187
                ...props,
188
            },
189
            emit
190
        );
191
192
        return {
193
            ...baseWidget,
194
            table,
195
            tableOptions,
196
        };
197
    },
198
};
199
</script>
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ModuleDashboard/Widgets/ERMRunUsageReport.vue (-1 / +113 lines)
Line 0 Link Here
0
- 
1
<template>
2
    <WidgetWrapper v-bind="widgetWrapperProps">
3
        <template #default>
4
            <div v-if="!default_usage_reports.length">
5
                <div class="d-flex align-items-center alert alert-info">
6
                    {{ noReportsText }}
7
                </div>
8
                <router-link :to="{ name: 'UsageStatisticsReportsHome' }">
9
                    {{ createReportText }}
10
                </router-link>
11
            </div>
12
            <div v-else class="d-flex align-items-center">
13
                <div class="flex-grow-1 me-2">
14
                    <label for="filter" class="visually-hidden">{{
15
                        pickReportText
16
                    }}</label>
17
                    <v-select
18
                        label="report_name"
19
                        :options="default_usage_reports"
20
                        style="min-width: 200px"
21
                        v-model="selected_report"
22
                    ></v-select>
23
                </div>
24
                <div>
25
                    <button
26
                        class="btn btn-primary"
27
                        type="button"
28
                        :disabled="!selected_report"
29
                        @click="runReport"
30
                    >
31
                        {{ runText }}
32
                    </button>
33
                </div>
34
            </div>
35
        </template>
36
    </WidgetWrapper>
37
</template>
38
39
<script>
40
import { ref } from "vue";
41
import { useRouter } from "vue-router";
42
import WidgetWrapper from "../WidgetWrapper.vue";
43
import { APIClient } from "../../../fetch/api-client.js";
44
import { useBaseWidget } from "../../../composables/base-widget.js";
45
import { $__ } from "@koha-vue/i18n";
46
47
export default {
48
    name: "ERMRunUsageReport",
49
    components: { WidgetWrapper },
50
    props: {
51
        display: String,
52
    },
53
    emits: ["removed", "added", "moveWidget"],
54
    setup(props, { emit }) {
55
        const router = useRouter();
56
        const baseWidget = useBaseWidget(
57
            {
58
                id: "ERMRunUsageReport",
59
                name: $__("Run eUsage report"),
60
                icon: "fa-solid fa-file",
61
                description: $__("Select a saved eUsage report to run."),
62
                ...props,
63
            },
64
            emit
65
        );
66
67
        const default_usage_reports = ref([]);
68
        const selected_report = ref(null);
69
70
        const noReportsText = $__(
71
            "No saved eUsage reports are available to run."
72
        );
73
        const createReportText = $__("Create a report");
74
        const pickReportText = $__("Pick a report to run");
75
        const runText = $__("Run");
76
77
        async function getReports() {
78
            try {
79
                const response =
80
                    await APIClient.erm.default_usage_reports.getAll();
81
                default_usage_reports.value = response;
82
            } catch (error) {
83
                console.error("Error getting default usage reports", error);
84
            } finally {
85
                baseWidget.loading.value = false;
86
            }
87
        }
88
89
        baseWidget.onDashboardMounted(() => {
90
            getReports();
91
        });
92
93
        function runReport() {
94
            if (!selected_report.value) return;
95
            router.push({
96
                name: "UsageStatisticsReportsViewer",
97
                query: { data: selected_report.value.report_url_params },
98
            });
99
        }
100
101
        return {
102
            ...baseWidget,
103
            default_usage_reports,
104
            selected_report,
105
            runReport,
106
            noReportsText,
107
            createReportText,
108
            pickReportText,
109
            runText,
110
        };
111
    },
112
};
113
</script>

Return to bug 39320