Browse Source

barcode: add wrapper component around JSBarcode

pull/4641/head
Daniel Spaude 2 years ago
parent
commit
aaf3b9b4b8
No known key found for this signature in database
GPG Key ID: 654A3D1FA4F35FFE
  1. 14
      packages/nc-gui/components/smartsheet/column/BarcodeOptions.vue
  2. 59
      packages/nc-gui/components/virtual-cell/barcode/Barcode.vue
  3. 68
      packages/nc-gui/components/virtual-cell/barcode/JsBarcodeWrapper.ts
  4. 42
      packages/nc-gui/components/virtual-cell/barcode/JsBarcodeWrapper.vue
  5. 3
      packages/nc-gui/lang/de.json
  6. 3
      packages/nc-gui/lang/en.json
  7. 85
      packages/nc-gui/package-lock.json
  8. 1
      packages/nc-gui/package.json
  9. 47
      packages/nocodb/package-lock.json

14
packages/nc-gui/components/smartsheet/column/BarcodeOptions.vue

@ -40,16 +40,16 @@ const columnsAllowedAsQrValue = computed<SelectProps['options']>(() => {
const supportedBarcodeFormats = [ const supportedBarcodeFormats = [
{ value: 'CODE128', label: 'CODE128' }, { value: 'CODE128', label: 'CODE128' },
{ value: 'UPC', label: 'UPC' }, { value: 'upc', label: 'UPC' },
{ value: 'EAN13', label: 'EAN13' }, { value: 'EAN13', label: 'EAN-13' },
{ value: 'EAN8', label: 'EAN8' }, { value: 'EAN8', label: 'EAN-8' },
{ value: 'EAN5', label: 'EAN5' }, { value: 'EAN5', label: 'EAN-5' },
{ value: 'EAN2', label: 'EAN2' }, { value: 'EAN2', label: 'EAN-2' },
{ value: 'CODE39', label: 'CODE39' }, { value: 'CODE39', label: 'CODE39' },
{ value: 'ITF14', label: 'ITF14' }, { value: 'ITF14', label: 'ITF-14' },
{ value: 'MSI', label: 'MSI' }, { value: 'MSI', label: 'MSI' },
{ value: 'PHARMACODE', label: 'pharmacode' }, { value: 'PHARMACODE', label: 'pharmacode' },
{ value: 'CODEBAR', label: 'codabar' }, { value: 'CODABAR', label: 'codabar' },
] ]
onMounted(() => { onMounted(() => {

59
packages/nc-gui/components/virtual-cell/barcode/Barcode.vue

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import JsBarcodeWrapper from './JsBarcodeWrapper' import JsBarcodeWrapper from './JsBarcodeWrapper.vue'
const maxNumberOfAllowedCharsForQrValue = 2000 const maxNumberOfAllowedCharsForBarcodeValue = 100
const cellValue = inject(CellValueInj) const cellValue = inject(CellValueInj)
@ -9,12 +9,11 @@ const column = inject(ColumnInj)
const barcodeValue = computed(() => String(cellValue?.value)) const barcodeValue = computed(() => String(cellValue?.value))
const tooManyCharsForQrCode = computed(() => barcodeValue?.value.length > maxNumberOfAllowedCharsForQrValue) const tooManyCharsForBarcode = computed(() => barcodeValue?.value.length > maxNumberOfAllowedCharsForBarcodeValue)
const modalVisible = ref(false) const modalVisible = ref(false)
const showQrModal = (ev: MouseEvent) => { const showBarcodeModal = () => {
ev.stopPropagation()
modalVisible.value = true modalVisible.value = true
} }
@ -25,11 +24,6 @@ const barcodeMeta = $computed(() => {
} }
}) })
const jsBarcodeOptions = $computed(() => ({
format: barcodeMeta.barcodeFormat,
// format: 'CODE128',
}))
const handleModalOkClick = () => (modalVisible.value = false) const handleModalOkClick = () => (modalVisible.value = false)
const { showEditNonEditableFieldWarning, showClearNonEditableFieldWarning } = useShowNotEditableWarning() const { showEditNonEditableFieldWarning, showClearNonEditableFieldWarning } = useShowNotEditableWarning()
@ -39,39 +33,44 @@ const { showEditNonEditableFieldWarning, showClearNonEditableFieldWarning } = us
<a-modal <a-modal
v-model:visible="modalVisible" v-model:visible="modalVisible"
:class="{ active: modalVisible }" :class="{ active: modalVisible }"
wrap-class-name="nc-qr-code-large amodal-wrapper" wrap-class-name="nc-barcode-large amodal-wrapper"
:body-style="{ padding: '0px' }" :body-style="{ padding: '0px' }"
:footer="null" :footer="null"
@ok="handleModalOkClick" @ok="handleModalOkClick"
> >
<JsBarcodeWrapper <JsBarcodeWrapper
v-if="barcodeValue && !tooManyCharsForQrCode" v-if="barcodeValue && !tooManyCharsForBarcode"
:options="jsBarcodeOptions" :barcode-value="barcodeValue"
tag="svg" :barcode-format="barcodeMeta.barcodeFormat"
:value="barcodeValue" >
width="3" <template #barcodeRenderError>
/> <div class="text-left text-wrap mt-2 text-[#e65100] text-xs">
{{ $t('msg.warning.barcode.renderError') }}
</div>
</template>
</JsBarcodeWrapper>
</a-modal> </a-modal>
<div @click="showQrModal"> <JsBarcodeWrapper
FOO: {{ JSON.stringify(jsBarcodeOptions) }} v-if="barcodeValue && !tooManyCharsForBarcode"
<JsBarcodeWrapper :barcode-value="barcodeValue"
v-if="barcodeValue && !tooManyCharsForQrCode" :barcode-format="barcodeMeta.barcodeFormat"
:options="jsBarcodeOptions" @on-click-barcode="showBarcodeModal"
tag="svg" >
class="w-full" <template #barcodeRenderError>
:value="barcodeValue" <div class="text-left text-wrap mt-2 text-[#e65100] text-xs">
width="3" {{ $t('msg.warning.barcode.renderError') }}
></JsBarcodeWrapper> </div>
</div> </template>
</JsBarcodeWrapper>
<div v-if="tooManyCharsForQrCode" class="text-left text-wrap mt-2 text-[#e65100] text-xs"> <div v-if="tooManyCharsForBarcode" class="text-left text-wrap mt-2 text-[#e65100] text-xs">
{{ $t('labels.barcodeValueTooLong') }} {{ $t('labels.barcodeValueTooLong') }}
</div> </div>
<div v-if="showEditNonEditableFieldWarning" class="text-left text-wrap mt-2 text-[#e65100] text-xs"> <div v-if="showEditNonEditableFieldWarning" class="text-left text-wrap mt-2 text-[#e65100] text-xs">
{{ $t('msg.warning.nonEditableFields.computedFieldUnableToClear') }} {{ $t('msg.warning.nonEditableFields.computedFieldUnableToClear') }}
</div> </div>
<div v-if="showClearNonEditableFieldWarning" class="text-left text-wrap mt-2 text-[#e65100] text-xs"> <div v-if="showClearNonEditableFieldWarning" class="text-left text-wrap mt-2 text-[#e65100] text-xs">
{{ $t('msg.warning.nonEditableFields.qrFieldsCannotBeDirectlyChanged') }} {{ $t('msg.warning.nonEditableFields.barcodeFieldsCannotBeDirectlyChanged') }}
</div> </div>
</template> </template>

68
packages/nc-gui/components/virtual-cell/barcode/JsBarcodeWrapper.ts

@ -1,68 +0,0 @@
import { defineComponent, h } from 'vue'
import JsBarcode from 'jsbarcode'
// TODO: add proper reference for the origin of this code here
export default defineComponent({
name: 'JsBarcodeWrapper',
props: {
/**
* The value of the bar code.
*/
value: {
type: String,
default: undefined,
},
/**
* The options for the bar code generator.
* {@link https://github.com/lindell/JsBarcode#options}
*/
options: {
type: Object,
default: undefined,
},
/**
* The tag name of the component's root element.
*/
tag: {
type: String,
default: 'canvas',
},
},
watch: {
$props: {
deep: true,
immediate: true,
/**
* Update the bar code when props changed.
*/
handler() {
if (this.$el) {
this.generate()
}
},
},
},
mounted() {
this.generate()
},
methods: {
/**
* Generate bar code.
*/
generate() {
// debugger
JsBarcode(this.$el, String(this.value), this.options)
},
},
render() {
return h(this.tag, this.$slots.default)
},
})

42
packages/nc-gui/components/virtual-cell/barcode/JsBarcodeWrapper.vue

@ -0,0 +1,42 @@
<script lang="ts" setup>
import JsBarcode from 'jsbarcode'
const props = defineProps({
barcodeValue: { type: String, required: true },
barcodeFormat: { type: String, required: true },
})
const emit = defineEmits(['onClickBarcode'])
const barcodeSvgRef = ref(null)
const errorForCurrentInput = ref(false)
const generate = () => {
try {
JsBarcode(barcodeSvgRef.value, String(props.barcodeValue), {
format: props.barcodeFormat,
})
errorForCurrentInput.value = false
} catch (e) {
console.log('e', e)
errorForCurrentInput.value = true
}
}
const onBarcodeClick = (ev: MouseEvent) => {
ev.stopPropagation()
emit('onClickBarcode')
}
watch(() => props.barcodeValue, generate)
watch(() => props.barcodeFormat, generate)
onMounted(generate)
</script>
<template>
<svg v-show="!errorForCurrentInput" ref="barcodeSvgRef" @click="onBarcodeClick"></svg>
<slot v-if="errorForCurrentInput" name="barcodeRenderError" />
</template>
<style scoped>
svg {
width: 100%;
}
</style>

3
packages/nc-gui/lang/de.json

@ -498,7 +498,8 @@
"warning": { "warning": {
"nonEditableFields": { "nonEditableFields": {
"computedFieldUnableToClear": "Warning: Computed field - unable to clear text", "computedFieldUnableToClear": "Warning: Computed field - unable to clear text",
"qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed." "qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed.",
"barcodeFieldsCannotBeDirectlyChanged": "Warning: Barcode fields cannot be directly changed."
} }
}, },
"info": { "info": {

3
packages/nc-gui/lang/en.json

@ -499,6 +499,9 @@
}, },
"msg": { "msg": {
"warning": { "warning": {
"barcode": {
"renderError": "Barcode error - please check compatibility between input and barcode type"
},
"nonEditableFields": { "nonEditableFields": {
"computedFieldUnableToClear": "Warning: Computed field - unable to clear text", "computedFieldUnableToClear": "Warning: Computed field - unable to clear text",
"qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed." "qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed."

85
packages/nc-gui/package-lock.json generated

@ -8,7 +8,6 @@
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@chenfengyuan/vue-barcode": "^2.0.1",
"@ckpack/vue-color": "^1.2.0", "@ckpack/vue-color": "^1.2.0",
"@types/file-saver": "^2.0.5", "@types/file-saver": "^2.0.5",
"@vue-flow/additional-components": "^1.2.0", "@vue-flow/additional-components": "^1.2.0",
@ -92,28 +91,6 @@
"windicss": "^3.5.6" "windicss": "^3.5.6"
} }
}, },
"../nocodb-sdk": {
"version": "0.100.2",
"license": "AGPL-3.0-or-later",
"dependencies": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"cspell": "^4.1.0",
"eslint": "^7.8.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^4.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.1.1",
"typescript": "^4.0.2"
}
},
"node_modules/@ampproject/remapping": { "node_modules/@ampproject/remapping": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
@ -873,15 +850,6 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@chenfengyuan/vue-barcode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@chenfengyuan/vue-barcode/-/vue-barcode-2.0.1.tgz",
"integrity": "sha512-YTSV1o0vOIRDZMiZZ9t09zkc9VZXN8CG8rriJUZUMtrvdg4Xt/qOOuzRlZEyRD7hsSYjbQy/3RcByGn1WOb1EA==",
"peerDependencies": {
"jsbarcode": "^3.11.0",
"vue": "^3.0.0"
}
},
"node_modules/@ckpack/vue-color": { "node_modules/@ckpack/vue-color": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz",
@ -8450,7 +8418,6 @@
"version": "1.15.1", "version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"devOptional": true,
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -11866,8 +11833,21 @@
} }
}, },
"node_modules/nocodb-sdk": { "node_modules/nocodb-sdk": {
"resolved": "../nocodb-sdk", "version": "0.100.2",
"link": true "resolved": "file:../nocodb-sdk",
"license": "AGPL-3.0-or-later",
"dependencies": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
}
},
"node_modules/nocodb-sdk/node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dependencies": {
"follow-redirects": "^1.14.0"
}
}, },
"node_modules/node-abi": { "node_modules/node-abi": {
"version": "3.23.0", "version": "3.23.0",
@ -18257,12 +18237,6 @@
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
} }
}, },
"@chenfengyuan/vue-barcode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@chenfengyuan/vue-barcode/-/vue-barcode-2.0.1.tgz",
"integrity": "sha512-YTSV1o0vOIRDZMiZZ9t09zkc9VZXN8CG8rriJUZUMtrvdg4Xt/qOOuzRlZEyRD7hsSYjbQy/3RcByGn1WOb1EA==",
"requires": {}
},
"@ckpack/vue-color": { "@ckpack/vue-color": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.2.0.tgz",
@ -23719,8 +23693,7 @@
"follow-redirects": { "follow-redirects": {
"version": "1.15.1", "version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
"devOptional": true
}, },
"form-data": { "form-data": {
"version": "4.0.0", "version": "4.0.0",
@ -26193,22 +26166,20 @@
} }
}, },
"nocodb-sdk": { "nocodb-sdk": {
"version": "file:../nocodb-sdk", "version": "0.100.2",
"requires": { "requires": {
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"axios": "^0.21.1", "axios": "^0.21.1",
"cspell": "^4.1.0", "jsep": "^1.3.6"
"eslint": "^7.8.0", },
"eslint-config-prettier": "^6.11.0", "dependencies": {
"eslint-plugin-eslint-comments": "^3.2.0", "axios": {
"eslint-plugin-functional": "^3.0.2", "version": "0.21.4",
"eslint-plugin-import": "^2.22.0", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"eslint-plugin-prettier": "^4.0.0", "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"jsep": "^1.3.6", "requires": {
"npm-run-all": "^4.1.5", "follow-redirects": "^1.14.0"
"prettier": "^2.1.1", }
"typescript": "^4.0.2" }
} }
}, },
"node-abi": { "node-abi": {

1
packages/nc-gui/package.json

@ -31,7 +31,6 @@
"ci:run": "export NODE_OPTIONS=\"--max_old_space_size=16384\"; npm install; NUXT_PAGE_TRANSITION_DISABLE=true npm run build; NUXT_PUBLIC_NC_BACKEND_URL=http://localhost:8080 npm run start &" "ci:run": "export NODE_OPTIONS=\"--max_old_space_size=16384\"; npm install; NUXT_PAGE_TRANSITION_DISABLE=true npm run build; NUXT_PUBLIC_NC_BACKEND_URL=http://localhost:8080 npm run start &"
}, },
"dependencies": { "dependencies": {
"@chenfengyuan/vue-barcode": "^2.0.1",
"@ckpack/vue-color": "^1.2.0", "@ckpack/vue-color": "^1.2.0",
"@vue-flow/additional-components": "^1.2.0", "@vue-flow/additional-components": "^1.2.0",
"@vue-flow/core": "^1.3.0", "@vue-flow/core": "^1.3.0",

47
packages/nocodb/package-lock.json generated

@ -151,28 +151,6 @@
"vuedraggable": "^2.24.3" "vuedraggable": "^2.24.3"
} }
}, },
"../nocodb-sdk": {
"version": "0.100.2",
"license": "AGPL-3.0-or-later",
"dependencies": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"cspell": "^4.1.0",
"eslint": "^7.8.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^4.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.1.1",
"typescript": "^4.0.2"
}
},
"node_modules/@azure/abort-controller": { "node_modules/@azure/abort-controller": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz",
@ -10656,8 +10634,13 @@
"dev": true "dev": true
}, },
"node_modules/nocodb-sdk": { "node_modules/nocodb-sdk": {
"resolved": "../nocodb-sdk", "version": "0.100.2",
"link": true "resolved": "file:../nocodb-sdk",
"license": "AGPL-3.0-or-later",
"dependencies": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
}
}, },
"node_modules/node-abort-controller": { "node_modules/node-abort-controller": {
"version": "3.0.1", "version": "3.0.1",
@ -26059,22 +26042,10 @@
"dev": true "dev": true
}, },
"nocodb-sdk": { "nocodb-sdk": {
"version": "file:../nocodb-sdk", "version": "0.100.2",
"requires": { "requires": {
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"axios": "^0.21.1", "axios": "^0.21.1",
"cspell": "^4.1.0", "jsep": "^1.3.6"
"eslint": "^7.8.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^4.0.0",
"jsep": "^1.3.6",
"npm-run-all": "^4.1.5",
"prettier": "^2.1.1",
"typescript": "^4.0.2"
} }
}, },
"node-abort-controller": { "node-abort-controller": {

Loading…
Cancel
Save