summaryrefslogtreecommitdiff
path: root/src/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/views')
-rw-r--r--src/views/AccessControl/SslCertificates/ModalUploadCertificate.vue164
-rw-r--r--src/views/AccessControl/SslCertificates/SslCertificates.vue209
-rw-r--r--src/views/AccessControl/SslCertificates/index.js2
3 files changed, 375 insertions, 0 deletions
diff --git a/src/views/AccessControl/SslCertificates/ModalUploadCertificate.vue b/src/views/AccessControl/SslCertificates/ModalUploadCertificate.vue
new file mode 100644
index 00000000..653a232f
--- /dev/null
+++ b/src/views/AccessControl/SslCertificates/ModalUploadCertificate.vue
@@ -0,0 +1,164 @@
+<template>
+ <b-modal id="upload-certificate" ref="modal" @ok="onOk" @hidden="resetForm">
+ <template v-slot:modal-title>
+ <template v-if="certificate">
+ {{ $t('pageSslCertificates.replaceCertificate') }}
+ </template>
+ <template v-else>
+ {{ $t('pageSslCertificates.addNewCertificate') }}
+ </template>
+ </template>
+ <b-form>
+ <!-- Replace Certificate type -->
+ <template v-if="certificate !== null">
+ <dl class="mb-4">
+ <dt>{{ $t('pageSslCertificates.modal.certificateType') }}</dt>
+ <dd>{{ certificate.certificate }}</dd>
+ </dl>
+ </template>
+
+ <!-- Add new Certificate type -->
+ <template v-else>
+ <b-form-group
+ :label="$t('pageSslCertificates.modal.certificateType')"
+ label-for="certificate-type"
+ >
+ <b-form-select
+ id="certificate-type"
+ v-model="form.certificateType"
+ :options="certificateOptions"
+ :state="getValidationState($v.form.certificateType)"
+ @input="$v.form.certificateType.$touch()"
+ >
+ </b-form-select>
+ <b-form-invalid-feedback role="alert">
+ <template v-if="!$v.form.certificateType.required">
+ {{ $t('global.form.fieldRequired') }}
+ </template>
+ </b-form-invalid-feedback>
+ </b-form-group>
+ </template>
+
+ <b-form-group
+ :label="$t('pageSslCertificates.modal.certificateFile')"
+ label-for="certificate-file"
+ >
+ <b-form-file
+ id="certificate-file"
+ v-model="form.file"
+ accept=".pem"
+ plain
+ :state="getValidationState($v.form.file)"
+ />
+ <b-form-invalid-feedback role="alert">
+ <template v-if="!$v.form.file.required">
+ {{ $t('global.form.required') }}
+ </template>
+ </b-form-invalid-feedback>
+ </b-form-group>
+ </b-form>
+ <template v-slot:modal-ok>
+ <template v-if="certificate">
+ {{ $t('global.action.replace') }}
+ </template>
+ <template v-else>
+ {{ $t('global.action.add') }}
+ </template>
+ </template>
+ </b-modal>
+</template>
+
+<script>
+import { required, requiredIf } from 'vuelidate/lib/validators';
+import VuelidateMixin from '../../../components/Mixins/VuelidateMixin.js';
+
+export default {
+ mixins: [VuelidateMixin],
+ props: {
+ certificate: {
+ type: Object,
+ default: null,
+ validator: prop => {
+ if (prop === null) return true;
+ return (
+ prop.hasOwnProperty('type') && prop.hasOwnProperty('certificate')
+ );
+ }
+ }
+ },
+ data() {
+ return {
+ form: {
+ certificateType: null,
+ file: null
+ }
+ };
+ },
+ computed: {
+ certificateTypes() {
+ return this.$store.getters['sslCertificates/availableUploadTypes'];
+ },
+ certificateOptions() {
+ return this.certificateTypes.map(({ type, label }) => {
+ return {
+ text: label,
+ value: type
+ };
+ });
+ }
+ },
+ watch: {
+ certificateOptions: function(options) {
+ if (options.length) {
+ this.form.certificateType = options[0].value;
+ }
+ }
+ },
+ validations() {
+ return {
+ form: {
+ certificateType: {
+ required: requiredIf(function() {
+ return !this.certificate;
+ })
+ },
+ file: {
+ required
+ }
+ }
+ };
+ },
+ methods: {
+ handleSubmit() {
+ this.$v.$touch();
+ if (this.$v.$invalid) return;
+ this.$emit('ok', {
+ addNew: !this.certificate,
+ file: this.form.file,
+ location: this.certificate ? this.certificate.location : null,
+ type: this.certificate
+ ? this.certificate.type
+ : this.form.certificateType
+ });
+ this.closeModal();
+ },
+ closeModal() {
+ this.$nextTick(() => {
+ this.$refs.modal.hide();
+ });
+ },
+ resetForm() {
+ this.form.certificateType = this.certificateOptions.length
+ ? this.certificateOptions[0].value
+ : null;
+ this.form.file = null;
+ this.$v.$reset();
+ },
+ onOk(bvModalEvt) {
+ // prevent modal close
+ bvModalEvt.preventDefault();
+ this.handleSubmit();
+ }
+ }
+};
+</script>
diff --git a/src/views/AccessControl/SslCertificates/SslCertificates.vue b/src/views/AccessControl/SslCertificates/SslCertificates.vue
new file mode 100644
index 00000000..ae28271f
--- /dev/null
+++ b/src/views/AccessControl/SslCertificates/SslCertificates.vue
@@ -0,0 +1,209 @@
+<template>
+ <b-container fluid>
+ <page-title />
+ <b-row>
+ <b-col xl="9" class="text-right">
+ <b-button
+ variant="primary"
+ :disabled="certificatesForUpload.length === 0"
+ @click="initModalUploadCertificate(null)"
+ >
+ <icon-add />
+ {{ $t('pageSslCertificates.addNewCertificate') }}
+ </b-button>
+ </b-col>
+ </b-row>
+ <b-row>
+ <b-col xl="9">
+ <b-table :fields="fields" :items="tableItems">
+ <template v-slot:cell(validFrom)="{ value }">
+ {{ value | formatDate }}
+ </template>
+
+ <template v-slot:cell(validUntil)="{ value }">
+ {{ value | formatDate }}
+ </template>
+
+ <template v-slot:cell(actions)="{ value, item }">
+ <table-row-action
+ v-for="(action, index) in value"
+ :key="index"
+ :value="action.value"
+ :title="action.title"
+ :enabled="action.enabled"
+ @click:tableAction="onTableRowAction($event, item)"
+ >
+ <template v-slot:icon>
+ <icon-replace v-if="action.value === 'replace'" />
+ <icon-trashcan v-if="action.value === 'delete'" />
+ </template>
+ </table-row-action>
+ </template>
+ </b-table>
+ </b-col>
+ </b-row>
+
+ <!-- Modals -->
+ <modal-upload-certificate :certificate="modalCertificate" @ok="onModalOk" />
+ </b-container>
+</template>
+
+<script>
+import IconAdd from '@carbon/icons-vue/es/add--alt/20';
+import IconReplace from '@carbon/icons-vue/es/renew/20';
+import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
+
+import ModalUploadCertificate from './ModalUploadCertificate';
+import PageTitle from '../../../components/Global/PageTitle';
+import TableRowAction from '../../../components/Global/TableRowAction';
+
+import BVToastMixin from '../../../components/Mixins/BVToastMixin';
+
+export default {
+ name: 'SslCertificates',
+ components: {
+ IconAdd,
+ IconReplace,
+ IconTrashcan,
+ ModalUploadCertificate,
+ PageTitle,
+ TableRowAction
+ },
+ mixins: [BVToastMixin],
+ data() {
+ return {
+ modalCertificate: null,
+ fields: [
+ {
+ key: 'certificate',
+ label: this.$t('pageSslCertificates.table.certificate')
+ },
+ {
+ key: 'issuedBy',
+ label: this.$t('pageSslCertificates.table.issuedBy')
+ },
+ {
+ key: 'issuedTo',
+ label: this.$t('pageSslCertificates.table.issuedTo')
+ },
+ {
+ key: 'validFrom',
+ label: this.$t('pageSslCertificates.table.validFrom')
+ },
+ {
+ key: 'validUntil',
+ label: this.$t('pageSslCertificates.table.validUntil')
+ },
+ {
+ key: 'actions',
+ label: '',
+ tdClass: 'text-right'
+ }
+ ]
+ };
+ },
+ computed: {
+ certificates() {
+ return this.$store.getters['sslCertificates/allCertificates'];
+ },
+ tableItems() {
+ return this.certificates.map(certificate => {
+ return {
+ ...certificate,
+ actions: [
+ {
+ value: 'replace',
+ title: this.$t('pageSslCertificates.replaceCertificate')
+ },
+ {
+ value: 'delete',
+ title: this.$t('pageSslCertificates.deleteCertificate'),
+ enabled:
+ certificate.type === 'TrustStore Certificate' ? true : false
+ }
+ ]
+ };
+ });
+ },
+ certificatesForUpload() {
+ return this.$store.getters['sslCertificates/availableUploadTypes'];
+ }
+ },
+ created() {
+ this.$store.dispatch('sslCertificates/getCertificates');
+ },
+ methods: {
+ onTableRowAction(event, rowItem) {
+ switch (event) {
+ case 'replace':
+ this.initModalUploadCertificate(rowItem);
+ break;
+ case 'delete':
+ this.initModalDeleteCertificate(rowItem);
+ break;
+ default:
+ break;
+ }
+ },
+ initModalUploadCertificate(certificate = null) {
+ this.modalCertificate = certificate;
+ this.$bvModal.show('upload-certificate');
+ },
+ initModalDeleteCertificate(certificate) {
+ this.$bvModal
+ .msgBoxConfirm(
+ this.$t('pageSslCertificates.modal.deleteConfirmMessage', {
+ issuedBy: certificate.issuedBy,
+ certificate: certificate.certificate
+ }),
+ {
+ title: this.$t('pageSslCertificates.deleteCertificate'),
+ okTitle: this.$t('global.action.delete')
+ }
+ )
+ .then(deleteConfirmed => {
+ if (deleteConfirmed) this.deleteCertificate(certificate);
+ });
+ },
+ onModalOk({ addNew, file, type, location }) {
+ if (addNew) {
+ // Upload a new certificate
+ this.addNewCertificate(file, type);
+ } else {
+ // Replace an existing certificate
+ this.replaceCertificate(file, type, location);
+ }
+ },
+ addNewCertificate(file, type) {
+ this.$store
+ .dispatch('sslCertificates/addNewCertificate', { file, type })
+ .then(success => this.successToast(success))
+ .catch(({ message }) => this.errorToast(message));
+ },
+ replaceCertificate(file, type, location) {
+ const reader = new FileReader();
+ reader.readAsBinaryString(file);
+ reader.onloadend = event => {
+ const certificateString = event.target.result;
+ this.$store
+ .dispatch('sslCertificates/replaceCertificate', {
+ certificateString,
+ type,
+ location
+ })
+ .then(success => this.successToast(success))
+ .catch(({ message }) => this.errorToast(message));
+ };
+ },
+ deleteCertificate({ type, location }) {
+ this.$store
+ .dispatch('sslCertificates/deleteCertificate', {
+ type,
+ location
+ })
+ .then(success => this.successToast(success))
+ .catch(({ message }) => this.errorToast(message));
+ }
+ }
+};
+</script>
diff --git a/src/views/AccessControl/SslCertificates/index.js b/src/views/AccessControl/SslCertificates/index.js
new file mode 100644
index 00000000..03daa565
--- /dev/null
+++ b/src/views/AccessControl/SslCertificates/index.js
@@ -0,0 +1,2 @@
+import SslCertificates from './SslCertificates.vue';
+export default SslCertificates;