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

(-)a/admin/record_sources.pl (+37 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2023 Theke Solutions
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use CGI        qw ( -utf8 );
23
use C4::Auth   qw( get_template_and_user );
24
use C4::Output qw( output_html_with_http_headers );
25
26
my $query = CGI->new;
27
28
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
29
    {
30
        template_name => "admin/record_sources.tt",
31
        query         => $query,
32
        type          => "intranet",
33
        flagsrequired => { parameters => 'manage_record_sources' },
34
    }
35
);
36
37
output_html_with_http_headers $query, $cookie, $template->output;
(-)a/debian/templates/apache-shared-intranet.conf (+1 lines)
Lines 23-28 RewriteRule ^(.*)_[0-9]{2}\.[0-9]{7}\.(js|css)$ $1.$2 [L] Link Here
23
RewriteRule ^/cgi-bin/koha/erm/.*$ /cgi-bin/koha/erm/erm.pl [PT]
23
RewriteRule ^/cgi-bin/koha/erm/.*$ /cgi-bin/koha/erm/erm.pl [PT]
24
RewriteCond %{REQUEST_URI} !^/cgi-bin/koha/preservation/.*.pl$
24
RewriteCond %{REQUEST_URI} !^/cgi-bin/koha/preservation/.*.pl$
25
RewriteRule ^/cgi-bin/koha/preservation/.*$ /cgi-bin/koha/preservation/home.pl [PT]
25
RewriteRule ^/cgi-bin/koha/preservation/.*$ /cgi-bin/koha/preservation/home.pl [PT]
26
RewriteRule ^/cgi-bin/koha/admin/record_sources(.*)?$ /cgi-bin/koha/admin/record_sources.pl$1 [PT]
26
27
27
Alias "/api" "/usr/share/koha/api"
28
Alias "/api" "/usr/share/koha/api"
28
<Directory "/usr/share/koha/api">
29
<Directory "/usr/share/koha/api">
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt (+4 lines)
Lines 210-215 Link Here
210
                        <dt><a href="/cgi-bin/koha/admin/searchengine/elasticsearch/mappings.pl">Search engine configuration (Elasticsearch)</a></dt>
210
                        <dt><a href="/cgi-bin/koha/admin/searchengine/elasticsearch/mappings.pl">Search engine configuration (Elasticsearch)</a></dt>
211
                        <dd>Manage indexes, facets, and their mappings to MARC fields and subfields</dd>
211
                        <dd>Manage indexes, facets, and their mappings to MARC fields and subfields</dd>
212
                    [% END %]
212
                    [% END %]
213
                    [% IF ( CAN_user_parameters_manage_record_sources ) %]
214
                        <dt><a href="/cgi-bin/koha/admin/record_sources">Record sources</a></dt>
215
                        <dd>Define record sources to import from</dd>
216
                    [% END %]
213
                </dl>
217
                </dl>
214
            [% END %]
218
            [% END %]
215
219
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/record_sources.tt (+34 lines)
Line 0 Link Here
1
[% USE raw %]
2
[% USE To %]
3
[% USE Asset %]
4
[% USE KohaDates %]
5
[% USE TablesSettings %]
6
[% USE AuthorisedValues %]
7
[% SET footerjs = 1 %]
8
[% PROCESS 'i18n.inc' %]
9
[% INCLUDE 'doc-head-open.inc' %]
10
<title>
11
    Record sources &rsaquo; Koha
12
</title>
13
[% INCLUDE 'doc-head-close.inc' %]
14
</head>
15
16
<body id="record_sources" class="record_sources">
17
[% WRAPPER 'header.inc' %]
18
    [% INCLUDE 'prefs-admin-search.inc' %]
19
[% END %]
20
21
<div id="record-source"> <!-- this is closed in intranet-bottom.inc -->
22
23
[% MACRO jsinclude BLOCK %]
24
    [% INCLUDE 'calendar.inc' %] <!-- FIXME: this shouldn't be needed -->
25
    [% INCLUDE 'datatables.inc' %]
26
    [% INCLUDE 'columns_settings.inc' %]
27
    [% INCLUDE 'js-patron-format.inc' %]
28
    [% INCLUDE 'js-date-format.inc' %]
29
30
    [% Asset.js("js/vue/dist/admin/record_sources.js") | $raw %]
31
32
[% END %]
33
34
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/FormAdd.vue (+121 lines)
Line 0 Link Here
1
<template>
2
    <div v-if="!initialized">{{ $__("Loading") }}</div>
3
    <div v-else id="record_source_edit">
4
        <h1 v-if="record_source.record_source_id">
5
            {{ $__("Edit '%s'").format(record_source.name) }}
6
        </h1>
7
        <h1 v-else>{{ $__("Add record source") }}</h1>
8
        <form @submit="onSubmit($event)">
9
            <fieldset class="rows">
10
                <ol>
11
                    <li>
12
                        <label class="required" for="name">
13
                            {{ $__("Name") }}:
14
                        </label>
15
                        <input
16
                            id="name"
17
                            v-model="record_source.name"
18
                            required
19
                        />
20
                        <span class="required">{{ $__("Required") }}</span>
21
                    </li>
22
                    <li>
23
                        <label for="can_be_edited">
24
                            {{ $__("Can be edited") }}:
25
                        </label>
26
                        <input
27
                            id="can_be_edited"
28
                            type="checkbox"
29
                            v-model="record_source.can_be_edited"
30
                        />
31
                    </li>
32
                </ol>
33
            </fieldset>
34
            <fieldset class="action">
35
                <input type="submit" :value="$__('Submit')" />
36
                <router-link
37
                    :to="{ name: 'RecordSourcesList' }"
38
                    role="button"
39
                    class="cancel"
40
                    >{{ $__("Cancel") }}</router-link
41
                >
42
            </fieldset>
43
        </form>
44
    </div>
45
</template>
46
47
<script>
48
import { inject } from "vue"
49
import { setMessage, setError, setWarning } from "../../../messages"
50
import { APIClient } from "../../../fetch/api-client.js"
51
52
export default {
53
    setup() {
54
        const { setMessage } = inject("mainStore")
55
        return {
56
            setMessage,
57
        }
58
    },
59
    data() {
60
        return {
61
            record_source: {
62
                record_source_id: null,
63
                name: "",
64
                can_be_edited: false,
65
            },
66
            initialized: false,
67
        }
68
    },
69
    beforeRouteEnter(to, from, next) {
70
        next(vm => {
71
            if (to.params.record_source_id) {
72
                vm.getRecordSource(to.params.record_source_id)
73
            } else {
74
                vm.initialized = true
75
            }
76
        })
77
    },
78
    methods: {
79
        async getRecordSource(record_source_id) {
80
            const client = APIClient.record_sources
81
            client.record_sources.get(record_source_id).then(
82
                record_source => {
83
                    this.record_source = record_source
84
                    this.record_source_id = record_source_id
85
                    this.initialized = true
86
                },
87
                error => {}
88
            )
89
        },
90
        onSubmit(e) {
91
            e.preventDefault()
92
            const client = APIClient.record_sources
93
            let response
94
            // RO attribute
95
            delete this.record_source.record_source_id
96
            if (this.record_source_id) {
97
                // update
98
                response = client.record_sources
99
                    .update(this.record_source, this.record_source_id)
100
                    .then(
101
                        success => {
102
                            setMessage(this.$__("Record source updated!"))
103
                            this.$router.push({ name: "RecordSourcesList" })
104
                        },
105
                        error => {}
106
                    )
107
            } else {
108
                response = client.record_sources
109
                    .create(this.record_source)
110
                    .then(
111
                        success => {
112
                            setMessage(this.$__("Record source created!"))
113
                            this.$router.push({ name: "RecordSourcesList" })
114
                        },
115
                        error => {}
116
                    )
117
            }
118
        },
119
    },
120
}
121
</script>
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue (+140 lines)
Line 0 Link Here
1
<template>
2
    <div v-if="!initialized">{{ $__("Loading") }}</div>
3
    <div v-else id="record_sources_list">
4
        <Toolbar>
5
            <ToolbarButton
6
                :to="{ name: 'RecordSourcesFormAdd' }"
7
                icon="plus"
8
                :title="$__('New record source')"
9
            />
10
        </Toolbar>
11
        <h1>{{ title }}</h1>
12
        <div v-if="record_sources_count > 0" class="page-section">
13
            <KohaTable
14
                ref="table"
15
                v-bind="tableOptions"
16
                @edit="doEdit"
17
                @delete="doDelete"
18
            ></KohaTable>
19
        </div>
20
        <div v-else class="dialog message">
21
            {{ $__("There are no record sources defined") }}
22
        </div>
23
    </div>
24
</template>
25
26
<script>
27
import Toolbar from "../../Toolbar.vue"
28
import ToolbarButton from "../../ToolbarButton.vue"
29
import { inject } from "vue"
30
import { APIClient } from "../../../fetch/api-client.js"
31
import KohaTable from "../../KohaTable.vue"
32
33
export default {
34
    data() {
35
        return {
36
            title: this.$__("Record sources"),
37
            tableOptions: {
38
                columns: [
39
                    {
40
                        title: this.$__("ID"),
41
                        data: "record_source_id",
42
                        searchable: true,
43
                    },
44
                    {
45
                        title: this.$__("Name"),
46
                        data: "name",
47
                        searchable: true,
48
                    },
49
                    {
50
                        title: __("Can be edited"),
51
                        data: "can_be_edited",
52
                        searchable: true,
53
                        orderable: true,
54
                        render: function (data, type, row, meta) {
55
                            return escape_str(
56
                                row.can_be_edited ? __("Yes") : __("No")
57
                            )
58
                        },
59
                    },
60
                ],
61
                actions: {
62
                    "-1": ["edit", "delete"],
63
                },
64
                url: "/api/v1/record_sources",
65
            },
66
            initialized: false,
67
            record_sources_count: 0,
68
        }
69
    },
70
    setup() {
71
        const { setWarning, setMessage, setError, setConfirmationDialog } =
72
            inject("mainStore")
73
        return {
74
            setWarning,
75
            setMessage,
76
            setError,
77
            setConfirmationDialog,
78
        }
79
    },
80
    beforeRouteEnter(to, from, next) {
81
        next(vm => {
82
            vm.getRecordSourcesCount().then(() => (vm.initialized = true))
83
        })
84
    },
85
    methods: {
86
        async getRecordSourcesCount() {
87
            const client = APIClient.record_sources
88
            await client.record_sources.count().then(
89
                count => {
90
                    this.record_sources_count = count
91
                },
92
                error => {}
93
            )
94
        },
95
        newRecordSource() {
96
            this.$router.push({ name: "RecordSourcesFormAdd" })
97
        },
98
        doEdit: function ({ record_source_id }, dt, event) {
99
            this.$router.push({
100
                name: "RecordSourcesFormAddEdit",
101
                params: { record_source_id },
102
            })
103
        },
104
        doDelete: function (record_source, dt, event) {
105
            this.setConfirmationDialog(
106
                {
107
                    title: this.$__(
108
                        "Are you sure you want to remove this record source?"
109
                    ),
110
                    message: record_source.name,
111
                    accept_label: this.$__("Yes, delete"),
112
                    cancel_label: this.$__("No, do not delete"),
113
                },
114
                () => {
115
                    const client = APIClient.record_sources
116
                    client.record_sources
117
                        .delete(record_source.record_source_id)
118
                        .then(
119
                            success => {
120
                                this.setMessage(
121
                                    this.$__("Record source %s deleted").format(
122
                                        record_source.name
123
                                    ),
124
                                    true
125
                                )
126
                                dt.draw()
127
                            },
128
                            error => {}
129
                        )
130
                }
131
            )
132
        },
133
    },
134
    components: {
135
        KohaTable,
136
        Toolbar,
137
        ToolbarButton,
138
    },
139
}
140
</script>
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Main.vue (+34 lines)
Line 0 Link Here
1
<template>
2
    <div>
3
        <div id="sub-header">
4
            <Breadcrumbs></Breadcrumbs>
5
            <Help />
6
        </div>
7
        <div class="main container-fluid">
8
            <div class="row">
9
                <div class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
10
                    <main>
11
                        <Dialog></Dialog>
12
                        <router-view />
13
                    </main>
14
                </div>
15
            </div>
16
        </div>
17
    </div>
18
</template>
19
20
<script>
21
import Breadcrumbs from "../../Breadcrumbs.vue"
22
import Help from "../../Help.vue"
23
import Dialog from "../../Dialog.vue"
24
25
export default {
26
    components: {
27
        Breadcrumbs,
28
        Dialog,
29
        Help,
30
    },
31
}
32
</script>
33
34
<style></style>
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js (+2 lines)
Lines 3-8 import PatronAPIClient from "./patron-api-client"; Link Here
3
import AcquisitionAPIClient from "./acquisition-api-client";
3
import AcquisitionAPIClient from "./acquisition-api-client";
4
import AVAPIClient from "./authorised-values-api-client";
4
import AVAPIClient from "./authorised-values-api-client";
5
import ItemAPIClient from "./item-api-client";
5
import ItemAPIClient from "./item-api-client";
6
import RecordSourcesAPIClient from "./record-sources-api-client";
6
import SysprefAPIClient from "./system-preferences-api-client";
7
import SysprefAPIClient from "./system-preferences-api-client";
7
import PreservationAPIClient from "./preservation-api-client";
8
import PreservationAPIClient from "./preservation-api-client";
8
9
Lines 14-17 export const APIClient = { Link Here
14
    item: new ItemAPIClient(),
15
    item: new ItemAPIClient(),
15
    sysprefs: new SysprefAPIClient(),
16
    sysprefs: new SysprefAPIClient(),
16
    preservation: new PreservationAPIClient(),
17
    preservation: new PreservationAPIClient(),
18
    record_sources: new RecordSourcesAPIClient(),
17
};
19
};
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources-api-client.js (+51 lines)
Line 0 Link Here
1
import HttpClient from "./http-client";
2
3
export class RecordSourcesAPIClient extends HttpClient {
4
    constructor() {
5
        super({
6
            baseURL: "/api/v1/record_sources",
7
        });
8
    }
9
10
    get record_sources() {
11
        return {
12
            create: record_source =>
13
                this.post({
14
                    endpoint: "",
15
                    body: record_source,
16
                }),
17
            delete: id =>
18
                this.delete({
19
                    endpoint: "/" + id,
20
                }),
21
            update: (record_source, id) =>
22
                this.put({
23
                    endpoint: "/" + id,
24
                    body: record_source,
25
                }),
26
            get: id =>
27
                this.get({
28
                    endpoint: "/" + id,
29
                }),
30
            getAll: (query, params) =>
31
                this.getAll({
32
                    endpoint: "/",
33
                    query,
34
                    params,
35
                    headers: {},
36
                }),
37
            count: (query = {}) =>
38
                this.count({
39
                    endpoint:
40
                        "?" +
41
                        new URLSearchParams({
42
                            _page: 1,
43
                            _per_page: 1,
44
                            ...(query && { q: JSON.stringify(query) }),
45
                        }),
46
                }),
47
        };
48
    }
49
}
50
51
export default RecordSourcesAPIClient;
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts (+54 lines)
Line 0 Link Here
1
import { createApp } from "vue";
2
import { createPinia } from "pinia";
3
import { createWebHistory, createRouter } from "vue-router";
4
5
import { library } from "@fortawesome/fontawesome-svg-core";
6
import {
7
    faPlus,
8
    faMinus,
9
    faPencil,
10
    faTrash,
11
    faSpinner,
12
} from "@fortawesome/free-solid-svg-icons";
13
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
14
import vSelect from "vue-select";
15
import { useNavigationStore } from "../../stores/navigation";
16
import { useMainStore } from "../../stores/main";
17
import routesDef from "../../routes/admin/record_sources";
18
19
library.add(faPlus, faMinus, faPencil, faTrash, faSpinner);
20
21
const pinia = createPinia();
22
const navigationStore = useNavigationStore(pinia);
23
const mainStore = useMainStore(pinia);
24
const { removeMessages } = mainStore;
25
const { setRoutes } = navigationStore;
26
const routes = setRoutes(routesDef);
27
28
const router = createRouter({
29
    history: createWebHistory(),
30
    linkExactActiveClass: "current",
31
    routes,
32
});
33
34
import App from "../../components/Admin/RecordSources/Main.vue";
35
import i18n from "../../i18n";
36
37
const app = createApp(App);
38
39
const rootComponent = app
40
    .use(i18n)
41
    .use(pinia)
42
    .use(router)
43
    .component("font-awesome-icon", FontAwesomeIcon)
44
    .component("v-select", vSelect);
45
46
app.config.unwrapInjectedRef = true;
47
app.provide("mainStore", mainStore);
48
app.provide("navigationStore", navigationStore);
49
app.mount("#record-source");
50
51
router.beforeEach(to => {
52
    navigationStore.$patch({ current: to.matched, params: to.params || {} });
53
    removeMessages(); // This will actually flag the messages as displayed already
54
});
(-)a/koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js (+38 lines)
Line 0 Link Here
1
import { markRaw } from "vue";
2
import RecordSourcesFormAdd from "../../components/Admin/RecordSources/FormAdd.vue";
3
import RecordSourcesList from "../../components/Admin/RecordSources/List.vue";
4
import { $__ } from "../../i18n";
5
6
export default {
7
    title: $__("Administration"),
8
    path: "",
9
    href: "/cgi-bin/koha/admin/admin-home.pl",
10
    is_base: true,
11
    is_default: true,
12
    children: [
13
        {
14
            title: $__("Record sources"),
15
            path: "/cgi-bin/koha/admin/record_sources",
16
            is_end_node: true,
17
            children: [
18
                {
19
                    path: "",
20
                    name: "RecordSourcesList",
21
                    component: markRaw(RecordSourcesList),
22
                },
23
                {
24
                    component: markRaw(RecordSourcesFormAdd),
25
                    name: "RecordSourcesFormAdd",
26
                    path: "add",
27
                    title: $__("Add record source"),
28
                },
29
                {
30
                    component: markRaw(RecordSourcesFormAdd),
31
                    name: "RecordSourcesFormAddEdit",
32
                    path: "edit/:record_source_id",
33
                    title: $__("Edit record source"),
34
                },
35
            ],
36
        },
37
    ],
38
};
(-)a/webpack.config.js (-1 / +1 lines)
Lines 7-12 module.exports = { Link Here
7
  entry: {
7
  entry: {
8
    erm: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/erm.ts",
8
    erm: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/erm.ts",
9
    preservation: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts",
9
    preservation: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts",
10
    "admin/record_sources": "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts",
10
  },
11
  },
11
  output: {
12
  output: {
12
    filename: "[name].js",
13
    filename: "[name].js",
13
- 

Return to bug 35919