Bugzilla – Attachment 163394 Details for
Bug 35919
Add record sources CRUD
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 35919: Add record sources admin page
Bug-35919-Add-record-sources-admin-page.patch (text/plain), 23.79 KB, created by
Jonathan Druart
on 2024-03-19 11:28:27 UTC
(
hide
)
Description:
Bug 35919: Add record sources admin page
Filename:
MIME Type:
Creator:
Jonathan Druart
Created:
2024-03-19 11:28:27 UTC
Size:
23.79 KB
patch
obsolete
>From 8b9446d803bcf922620bc24c95625b949746e69e Mon Sep 17 00:00:00 2001 >From: Tomas Cohen Arazi <tomascohen@theke.io> >Date: Wed, 24 Jan 2024 16:18:13 -0300 >Subject: [PATCH] Bug 35919: Add record sources admin page > >This patch introduces a Vue.js based record sources managing page. To >test it: > >1. Apply this patch >2. Build the Vue.js stuff: > $ ktd --shell > k$ yarn js:build > k$ restart_all >3. On the staff interface, go to Administration > Record sources >4. Play with the interface and the offered actions >=> SUCCESS: Things go well >5. Sign off :-D > >Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io> >Signed-off-by: Matt Blenkinsop <matt.blenkinsop@ptfs-europe.com> > >Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org> >--- > admin/record_sources.pl | 37 +++++ > debian/templates/apache-shared-intranet.conf | 2 + > .../prog/en/modules/admin/admin-home.tt | 4 + > .../prog/en/modules/admin/record_sources.tt | 34 +++++ > .../Admin/RecordSources/FormAdd.vue | 121 +++++++++++++++ > .../components/Admin/RecordSources/List.vue | 140 ++++++++++++++++++ > .../components/Admin/RecordSources/Main.vue | 34 +++++ > .../prog/js/vue/fetch/api-client.js | 2 + > .../js/vue/fetch/record-sources-api-client.js | 51 +++++++ > .../js/vue/modules/admin/record_sources.ts | 54 +++++++ > .../js/vue/routes/admin/record_sources.js | 38 +++++ > webpack.config.js | 1 + > 12 files changed, 518 insertions(+) > create mode 100755 admin/record_sources.pl > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/record_sources.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/FormAdd.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Main.vue > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources-api-client.js > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js > >diff --git a/admin/record_sources.pl b/admin/record_sources.pl >new file mode 100755 >index 00000000000..9524f32dd65 >--- /dev/null >+++ b/admin/record_sources.pl >@@ -0,0 +1,37 @@ >+#!/usr/bin/perl >+ >+# Copyright 2023 Theke Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use CGI qw ( -utf8 ); >+use C4::Auth qw( get_template_and_user ); >+use C4::Output qw( output_html_with_http_headers ); >+ >+my $query = CGI->new; >+ >+my ( $template, $loggedinuser, $cookie ) = get_template_and_user( >+ { >+ template_name => "admin/record_sources.tt", >+ query => $query, >+ type => "intranet", >+ flagsrequired => { parameters => 'manage_record_sources' }, >+ } >+); >+ >+output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/debian/templates/apache-shared-intranet.conf b/debian/templates/apache-shared-intranet.conf >index b4fe0ea2263..835b0812b6b 100644 >--- a/debian/templates/apache-shared-intranet.conf >+++ b/debian/templates/apache-shared-intranet.conf >@@ -13,6 +13,7 @@ ScriptAlias /search "/usr/share/koha/intranet/cgi-bin/catalogue/search.pl" > > # Protect dev package install > RewriteEngine on >+ > RewriteRule ^/cgi-bin/koha/(C4|debian|etc|installer/data|install_misc|Koha|misc|selenium|t|test|tmp|xt)/|\.PL$ /notfound [PT] > > RewriteRule ^/bib/([^\/]*)/?$ /cgi-bin/koha/catalogue/detail.pl?biblionumber=$1 [PT] >@@ -23,6 +24,7 @@ RewriteRule ^(.*)_[0-9]{2}\.[0-9]{7}\.(js|css)$ $1.$2 [L] > RewriteRule ^/cgi-bin/koha/erm/.*$ /cgi-bin/koha/erm/erm.pl [PT] > RewriteCond %{REQUEST_URI} !^/cgi-bin/koha/preservation/.*.pl$ > RewriteRule ^/cgi-bin/koha/preservation/.*$ /cgi-bin/koha/preservation/home.pl [PT] >+RewriteRule ^/cgi-bin/koha/admin/record_sources(.*)?$ /cgi-bin/koha/admin/record_sources.pl$1 [PT] > > Alias "/api" "/usr/share/koha/api" > <Directory "/usr/share/koha/api"> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt >index 1320214b653..8f920678ba6 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt >@@ -210,6 +210,10 @@ > <dt><a href="/cgi-bin/koha/admin/searchengine/elasticsearch/mappings.pl">Search engine configuration (Elasticsearch)</a></dt> > <dd>Manage indexes, facets, and their mappings to MARC fields and subfields</dd> > [% END %] >+ [% IF ( CAN_user_parameters_manage_record_sources ) %] >+ <dt><a href="/cgi-bin/koha/admin/record_sources">Record sources</a></dt> >+ <dd>Define record sources to import from</dd> >+ [% END %] > </dl> > [% END %] > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/record_sources.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/record_sources.tt >new file mode 100644 >index 00000000000..533a171ec2c >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/record_sources.tt >@@ -0,0 +1,34 @@ >+[% USE raw %] >+[% USE To %] >+[% USE Asset %] >+[% USE KohaDates %] >+[% USE TablesSettings %] >+[% USE AuthorisedValues %] >+[% SET footerjs = 1 %] >+[% PROCESS 'i18n.inc' %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title> >+ Record sources › Koha >+</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+ >+<body id="record_sources" class="record_sources"> >+[% WRAPPER 'header.inc' %] >+ [% INCLUDE 'prefs-admin-search.inc' %] >+[% END %] >+ >+<div id="record-source"> <!-- this is closed in intranet-bottom.inc --> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'calendar.inc' %] <!-- FIXME: this shouldn't be needed --> >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+ [% INCLUDE 'js-patron-format.inc' %] >+ [% INCLUDE 'js-date-format.inc' %] >+ >+ [% Asset.js("js/vue/dist/admin/record_sources.js") | $raw %] >+ >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/FormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/FormAdd.vue >new file mode 100644 >index 00000000000..2b7994224cb >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/FormAdd.vue >@@ -0,0 +1,121 @@ >+<template> >+ <div v-if="!initialized">{{ $__("Loading") }}</div> >+ <div v-else id="record_source_edit"> >+ <h1 v-if="record_source.record_source_id"> >+ {{ $__("Edit '%s'").format(record_source.name) }} >+ </h1> >+ <h1 v-else>{{ $__("Add record source") }}</h1> >+ <form @submit="onSubmit($event)"> >+ <fieldset class="rows"> >+ <ol> >+ <li> >+ <label class="required" for="name"> >+ {{ $__("Name") }}: >+ </label> >+ <input >+ id="name" >+ v-model="record_source.name" >+ required >+ /> >+ <span class="required">{{ $__("Required") }}</span> >+ </li> >+ <li> >+ <label for="can_be_edited"> >+ {{ $__("Can be edited") }}: >+ </label> >+ <input >+ id="can_be_edited" >+ type="checkbox" >+ v-model="record_source.can_be_edited" >+ /> >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset class="action"> >+ <input type="submit" :value="$__('Submit')" /> >+ <router-link >+ :to="{ name: 'RecordSourcesList' }" >+ role="button" >+ class="cancel" >+ >{{ $__("Cancel") }}</router-link >+ > >+ </fieldset> >+ </form> >+ </div> >+</template> >+ >+<script> >+import { inject } from "vue" >+import { setMessage, setError, setWarning } from "../../../messages" >+import { APIClient } from "../../../fetch/api-client.js" >+ >+export default { >+ setup() { >+ const { setMessage } = inject("mainStore") >+ return { >+ setMessage, >+ } >+ }, >+ data() { >+ return { >+ record_source: { >+ record_source_id: null, >+ name: "", >+ can_be_edited: false, >+ }, >+ initialized: false, >+ } >+ }, >+ beforeRouteEnter(to, from, next) { >+ next(vm => { >+ if (to.params.record_source_id) { >+ vm.getRecordSource(to.params.record_source_id) >+ } else { >+ vm.initialized = true >+ } >+ }) >+ }, >+ methods: { >+ async getRecordSource(record_source_id) { >+ const client = APIClient.record_sources >+ client.record_sources.get(record_source_id).then( >+ record_source => { >+ this.record_source = record_source >+ this.record_source_id = record_source_id >+ this.initialized = true >+ }, >+ error => {} >+ ) >+ }, >+ onSubmit(e) { >+ e.preventDefault() >+ const client = APIClient.record_sources >+ let response >+ // RO attribute >+ delete this.record_source.record_source_id >+ if (this.record_source_id) { >+ // update >+ response = client.record_sources >+ .update(this.record_source, this.record_source_id) >+ .then( >+ success => { >+ setMessage(this.$__("Record source updated!")) >+ this.$router.push({ name: "RecordSourcesList" }) >+ }, >+ error => {} >+ ) >+ } else { >+ response = client.record_sources >+ .create(this.record_source) >+ .then( >+ success => { >+ setMessage(this.$__("Record source created!")) >+ this.$router.push({ name: "RecordSourcesList" }) >+ }, >+ error => {} >+ ) >+ } >+ }, >+ }, >+} >+</script> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue >new file mode 100644 >index 00000000000..f8776f9b35d >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/List.vue >@@ -0,0 +1,140 @@ >+<template> >+ <div v-if="!initialized">{{ $__("Loading") }}</div> >+ <div v-else id="record_sources_list"> >+ <Toolbar> >+ <ToolbarButton >+ :to="{ name: 'RecordSourcesFormAdd' }" >+ icon="plus" >+ :title="$__('New record source')" >+ /> >+ </Toolbar> >+ <h1>{{ title }}</h1> >+ <div v-if="record_sources_count > 0" class="page-section"> >+ <KohaTable >+ ref="table" >+ v-bind="tableOptions" >+ @edit="doEdit" >+ @delete="doDelete" >+ ></KohaTable> >+ </div> >+ <div v-else class="dialog message"> >+ {{ $__("There are no record sources defined") }} >+ </div> >+ </div> >+</template> >+ >+<script> >+import Toolbar from "../../Toolbar.vue" >+import ToolbarButton from "../../ToolbarButton.vue" >+import { inject } from "vue" >+import { APIClient } from "../../../fetch/api-client.js" >+import KohaTable from "../../KohaTable.vue" >+ >+export default { >+ data() { >+ return { >+ title: this.$__("Record sources"), >+ tableOptions: { >+ columns: [ >+ { >+ title: this.$__("ID"), >+ data: "record_source_id", >+ searchable: true, >+ }, >+ { >+ title: this.$__("Name"), >+ data: "name", >+ searchable: true, >+ }, >+ { >+ title: __("Can be edited"), >+ data: "can_be_edited", >+ searchable: true, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return escape_str( >+ row.can_be_edited ? __("Yes") : __("No") >+ ) >+ }, >+ }, >+ ], >+ actions: { >+ "-1": ["edit", "delete"], >+ }, >+ url: "/api/v1/record_sources", >+ }, >+ initialized: false, >+ record_sources_count: 0, >+ } >+ }, >+ setup() { >+ const { setWarning, setMessage, setError, setConfirmationDialog } = >+ inject("mainStore") >+ return { >+ setWarning, >+ setMessage, >+ setError, >+ setConfirmationDialog, >+ } >+ }, >+ beforeRouteEnter(to, from, next) { >+ next(vm => { >+ vm.getRecordSourcesCount().then(() => (vm.initialized = true)) >+ }) >+ }, >+ methods: { >+ async getRecordSourcesCount() { >+ const client = APIClient.record_sources >+ await client.record_sources.count().then( >+ count => { >+ this.record_sources_count = count >+ }, >+ error => {} >+ ) >+ }, >+ newRecordSource() { >+ this.$router.push({ name: "RecordSourcesFormAdd" }) >+ }, >+ doEdit: function ({ record_source_id }, dt, event) { >+ this.$router.push({ >+ name: "RecordSourcesFormAddEdit", >+ params: { record_source_id }, >+ }) >+ }, >+ doDelete: function (record_source, dt, event) { >+ this.setConfirmationDialog( >+ { >+ title: this.$__( >+ "Are you sure you want to remove this record source?" >+ ), >+ message: record_source.name, >+ accept_label: this.$__("Yes, delete"), >+ cancel_label: this.$__("No, do not delete"), >+ }, >+ () => { >+ const client = APIClient.record_sources >+ client.record_sources >+ .delete(record_source.record_source_id) >+ .then( >+ success => { >+ this.setMessage( >+ this.$__("Record source %s deleted").format( >+ record_source.name >+ ), >+ true >+ ) >+ dt.draw() >+ }, >+ error => {} >+ ) >+ } >+ ) >+ }, >+ }, >+ components: { >+ KohaTable, >+ Toolbar, >+ ToolbarButton, >+ }, >+} >+</script> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Main.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Main.vue >new file mode 100644 >index 00000000000..057c78a4ae1 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/RecordSources/Main.vue >@@ -0,0 +1,34 @@ >+<template> >+ <div> >+ <div id="sub-header"> >+ <Breadcrumbs></Breadcrumbs> >+ <Help /> >+ </div> >+ <div class="main container-fluid"> >+ <div class="row"> >+ <div class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"> >+ <main> >+ <Dialog></Dialog> >+ <router-view /> >+ </main> >+ </div> >+ </div> >+ </div> >+ </div> >+</template> >+ >+<script> >+import Breadcrumbs from "../../Breadcrumbs.vue" >+import Help from "../../Help.vue" >+import Dialog from "../../Dialog.vue" >+ >+export default { >+ components: { >+ Breadcrumbs, >+ Dialog, >+ Help, >+ }, >+} >+</script> >+ >+<style></style> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js >index 294693c238e..4bfd3c8dd0c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js >@@ -3,6 +3,7 @@ import PatronAPIClient from "./patron-api-client"; > import AcquisitionAPIClient from "./acquisition-api-client"; > import AVAPIClient from "./authorised-values-api-client"; > import ItemAPIClient from "./item-api-client"; >+import RecordSourcesAPIClient from "./record-sources-api-client"; > import SysprefAPIClient from "./system-preferences-api-client"; > import PreservationAPIClient from "./preservation-api-client"; > >@@ -14,4 +15,5 @@ export const APIClient = { > item: new ItemAPIClient(), > sysprefs: new SysprefAPIClient(), > preservation: new PreservationAPIClient(), >+ record_sources: new RecordSourcesAPIClient(), > }; >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources-api-client.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources-api-client.js >new file mode 100644 >index 00000000000..b12882d1dca >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/record-sources-api-client.js >@@ -0,0 +1,51 @@ >+import HttpClient from "./http-client"; >+ >+export class RecordSourcesAPIClient extends HttpClient { >+ constructor() { >+ super({ >+ baseURL: "/api/v1/record_sources", >+ }); >+ } >+ >+ get record_sources() { >+ return { >+ create: record_source => >+ this.post({ >+ endpoint: "", >+ body: record_source, >+ }), >+ delete: id => >+ this.delete({ >+ endpoint: "/" + id, >+ }), >+ update: (record_source, id) => >+ this.put({ >+ endpoint: "/" + id, >+ body: record_source, >+ }), >+ get: id => >+ this.get({ >+ endpoint: "/" + id, >+ }), >+ getAll: (query, params) => >+ this.getAll({ >+ endpoint: "/", >+ query, >+ params, >+ headers: {}, >+ }), >+ count: (query = {}) => >+ this.count({ >+ endpoint: >+ "?" + >+ new URLSearchParams({ >+ _page: 1, >+ _per_page: 1, >+ ...(query && { q: JSON.stringify(query) }), >+ }), >+ }), >+ }; >+ } >+} >+ >+export default RecordSourcesAPIClient; >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts >new file mode 100644 >index 00000000000..80f43f4ea2f >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts >@@ -0,0 +1,54 @@ >+import { createApp } from "vue"; >+import { createPinia } from "pinia"; >+import { createWebHistory, createRouter } from "vue-router"; >+ >+import { library } from "@fortawesome/fontawesome-svg-core"; >+import { >+ faPlus, >+ faMinus, >+ faPencil, >+ faTrash, >+ faSpinner, >+} from "@fortawesome/free-solid-svg-icons"; >+import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; >+import vSelect from "vue-select"; >+import { useNavigationStore } from "../../stores/navigation"; >+import { useMainStore } from "../../stores/main"; >+import routesDef from "../../routes/admin/record_sources"; >+ >+library.add(faPlus, faMinus, faPencil, faTrash, faSpinner); >+ >+const pinia = createPinia(); >+const navigationStore = useNavigationStore(pinia); >+const mainStore = useMainStore(pinia); >+const { removeMessages } = mainStore; >+const { setRoutes } = navigationStore; >+const routes = setRoutes(routesDef); >+ >+const router = createRouter({ >+ history: createWebHistory(), >+ linkExactActiveClass: "current", >+ routes, >+}); >+ >+import App from "../../components/Admin/RecordSources/Main.vue"; >+import i18n from "../../i18n"; >+ >+const app = createApp(App); >+ >+const rootComponent = app >+ .use(i18n) >+ .use(pinia) >+ .use(router) >+ .component("font-awesome-icon", FontAwesomeIcon) >+ .component("v-select", vSelect); >+ >+app.config.unwrapInjectedRef = true; >+app.provide("mainStore", mainStore); >+app.provide("navigationStore", navigationStore); >+app.mount("#record-source"); >+ >+router.beforeEach(to => { >+ navigationStore.$patch({ current: to.matched, params: to.params || {} }); >+ removeMessages(); // This will actually flag the messages as displayed already >+}); >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js >new file mode 100644 >index 00000000000..a85fd4b5f41 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/admin/record_sources.js >@@ -0,0 +1,38 @@ >+import { markRaw } from "vue"; >+import RecordSourcesFormAdd from "../../components/Admin/RecordSources/FormAdd.vue"; >+import RecordSourcesList from "../../components/Admin/RecordSources/List.vue"; >+import { $__ } from "../../i18n"; >+ >+export default { >+ title: $__("Administration"), >+ path: "", >+ href: "/cgi-bin/koha/admin/admin-home.pl", >+ is_base: true, >+ is_default: true, >+ children: [ >+ { >+ title: $__("Record sources"), >+ path: "/cgi-bin/koha/admin/record_sources", >+ is_end_node: true, >+ children: [ >+ { >+ path: "", >+ name: "RecordSourcesList", >+ component: markRaw(RecordSourcesList), >+ }, >+ { >+ component: markRaw(RecordSourcesFormAdd), >+ name: "RecordSourcesFormAdd", >+ path: "add", >+ title: $__("Add record source"), >+ }, >+ { >+ component: markRaw(RecordSourcesFormAdd), >+ name: "RecordSourcesFormAddEdit", >+ path: "edit/:record_source_id", >+ title: $__("Edit record source"), >+ }, >+ ], >+ }, >+ ], >+}; >diff --git a/webpack.config.js b/webpack.config.js >index c22256785a4..ae87653c244 100644 >--- a/webpack.config.js >+++ b/webpack.config.js >@@ -7,6 +7,7 @@ module.exports = { > entry: { > erm: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/erm.ts", > preservation: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts", >+ "admin/record_sources": "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts", > }, > output: { > filename: "[name].js", >-- >2.34.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 35919
:
161531
|
161532
|
161533
|
161534
|
161535
|
161537
|
161538
|
161577
|
161578
|
161579
|
161580
|
161581
|
161582
|
161583
|
162489
|
162594
|
162595
|
162596
|
162599
|
163348
|
163349
|
163350
|
163351
|
163352
|
163353
|
163354
|
163355
|
163360
|
163369
|
163389
|
163390
|
163391
|
163392
|
163393
|
163394
|
163395
|
163396
|
163397
|
163398
|
163399
|
163400
|
164708
|
164709
|
164710
|
164711
|
164712
|
164713
|
164714
|
164715
|
164716
|
164717
|
165274