refactor: ts and composition api for base components

This commit is contained in:
Fabio Di Stasio 2022-05-10 13:02:01 +02:00
parent cc5910b88f
commit ae377a6c3c
21 changed files with 489 additions and 529 deletions

View File

@ -46,70 +46,57 @@
</div>
</template>
<script lang="ts">
import { computed, defineComponent, onBeforeUnmount } from 'vue';
<script setup lang="ts">
import { computed, onBeforeUnmount, PropType, useSlots } from 'vue';
export default defineComponent({
name: 'BaseConfirmModal',
props: {
size: {
type: String,
validator: (prop: string) => ['small', 'medium', '400', 'large'].includes(prop),
default: 'small'
},
hideFooter: {
type: Boolean,
default: false
},
confirmText: String,
cancelText: String
const props = defineProps({
size: {
type: String as PropType<'small' | 'medium' | '400' | 'large'>,
validator: (prop: string) => ['small', 'medium', '400', 'large'].includes(prop),
default: 'small'
},
emits: ['confirm', 'hide'],
setup (props, { slots, emit }) {
const hasHeader = computed(() => !!slots.header);
const hasBody = computed(() => !!slots.body);
const hasDefault = computed(() => !!slots.default);
const modalSizeClass = computed(() => {
if (props.size === 'small')
return 'modal-sm';
if (props.size === '400')
return 'modal-400';
else if (props.size === 'large')
return 'modal-lg';
else return '';
});
hideFooter: {
type: Boolean,
default: false
},
confirmText: String,
cancelText: String
});
const emit = defineEmits(['confirm', 'hide']);
const slots = useSlots();
const confirmModal = () => {
emit('confirm');
hideModal();
};
const hasHeader = computed(() => !!slots.header);
const hasBody = computed(() => !!slots.body);
const hasDefault = computed(() => !!slots.default);
const modalSizeClass = computed(() => {
if (props.size === 'small')
return 'modal-sm';
if (props.size === '400')
return 'modal-400';
else if (props.size === 'large')
return 'modal-lg';
else return '';
});
const hideModal = () => {
emit('hide');
};
const confirmModal = () => {
emit('confirm');
hideModal();
};
const onKey = (e: KeyboardEvent) => {
e.stopPropagation();
if (e.key === 'Escape')
hideModal();
};
const hideModal = () => {
emit('hide');
};
window.addEventListener('keydown', onKey);
const onKey = (e: KeyboardEvent) => {
e.stopPropagation();
if (e.key === 'Escape')
hideModal();
};
onBeforeUnmount(() => {
window.removeEventListener('keydown', onKey);
});
window.addEventListener('keydown', onKey);
return {
hasHeader,
hasBody,
hasDefault,
modalSizeClass,
confirmModal,
hideModal,
onKey
};
}
onBeforeUnmount(() => {
window.removeEventListener('keydown', onKey);
});
</script>

View File

@ -15,67 +15,60 @@
</div>
</template>
<script>
export default {
name: 'BaseContextMenu',
props: {
contextEvent: MouseEvent
},
emits: ['close-context'],
data () {
return {
contextSize: null,
isBottom: false
};
},
computed: {
position () {
let topCord = 0;
let leftCord = 0;
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, Ref, ref } from 'vue';
if (this.contextEvent) {
const { clientY, clientX } = this.contextEvent;
topCord = `${clientY + 2}px`;
leftCord = `${clientX + 5}px`;
const contextContent: Ref<HTMLDivElement> = ref(null);
const contextSize: Ref<DOMRect> = ref(null);
const isBottom: Ref<boolean> = ref(false);
const props = defineProps<{contextEvent: MouseEvent}>();
const emit = defineEmits(['close-context']);
if (this.contextSize) {
if (clientY + (this.contextSize.height < 200 ? 200 : this.contextSize.height) + 5 >= window.innerHeight) {
topCord = `${clientY + 3 - this.contextSize.height}px`;
this.isBottom = true;
}
const position = computed(() => {
let topCord = '0px';
let leftCord = '0px';
if (clientX + this.contextSize.width + 5 >= window.innerWidth)
leftCord = `${clientX - this.contextSize.width}px`;
}
if (props.contextEvent) {
const { clientY, clientX } = props.contextEvent;
topCord = `${clientY + 2}px`;
leftCord = `${clientX + 5}px`;
if (contextSize.value) {
if (clientY + (contextSize.value.height < 200 ? 200 : contextSize.value.height) + 5 >= window.innerHeight) {
topCord = `${clientY + 3 - contextSize.value.height}px`;
isBottom.value = true;
}
return {
top: topCord,
left: leftCord
};
}
},
created () {
window.addEventListener('keydown', this.onKey);
},
mounted () {
if (this.$refs.contextContent)
this.contextSize = this.$refs.contextContent.getBoundingClientRect();
},
beforeUnmount () {
window.removeEventListener('keydown', this.onKey);
},
methods: {
close () {
this.$emit('close-context');
},
onKey (e) {
e.stopPropagation();
if (e.key === 'Escape')
this.close();
if (clientX + contextSize.value.width + 5 >= window.innerWidth)
leftCord = `${clientX - contextSize.value.width}px`;
}
}
return {
top: topCord,
left: leftCord
};
});
const close = () => {
emit('close-context');
};
const onKey = (e: KeyboardEvent) => {
e.stopPropagation();
if (e.key === 'Escape')
close();
};
window.addEventListener('keydown', onKey);
onMounted(() => {
if (contextContent.value)
contextSize.value = contextContent.value.getBoundingClientRect();
});
onBeforeUnmount(() => {
window.removeEventListener('keydown', onKey);
});
</script>
<style lang="scss">

View File

@ -4,11 +4,6 @@
</div>
</template>
<script>
export default {
name: 'BaseLoader'
};
</script>
<style scoped>
.empty {
position: absolute;

View File

@ -1,95 +1,93 @@
<template>
<div id="map" class="map" />
</template>
<script>
import L from 'leaflet';
<script setup lang="ts">
import { onMounted, PropType, Ref, ref } from 'vue';
import * as L from 'leaflet';
import {
point,
lineString,
polygon
} from '@turf/helpers';
import { GeoJsonObject } from 'geojson';
import { getArrayDepth } from 'common/libs/getArrayDepth';
export default {
name: 'BaseMap',
props: {
points: [Object, Array],
isMultiSpatial: Boolean
},
data () {
return {
map: null,
markers: [],
center: null
};
},
mounted () {
if (this.isMultiSpatial) {
for (const element of this.points)
this.markers.push(this.getMarkers(element));
}
else {
this.markers = this.getMarkers(this.points);
interface Coordinates { x: number; y: number }
if (!Array.isArray(this.points))
this.center = [this.points.y, this.points.x];
}
const props = defineProps({
points: [Object, Array] as PropType<Coordinates | Coordinates[]>,
isMultiSpatial: Boolean
});
const map: Ref<L.Map> = ref(null);
const markers: Ref<GeoJsonObject | GeoJsonObject[]> = ref(null);
const center: Ref<[number, number]> = ref(null);
this.map = L.map('map', {
center: this.center || [0, 0],
zoom: 15,
minZoom: 1,
attributionControl: false
});
L.control.attribution({ prefix: '<b>Leaflet</b>' }).addTo(this.map);
const geoJsonObj = L.geoJSON(this.markers, {
style: function () {
return {
weight: 2,
fillColor: '#ff7800',
color: '#ff7800',
opacity: 0.8,
fillOpacity: 0.4
};
},
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, {
radius: 7,
weight: 2,
fillColor: '#ff7800',
color: '#ff7800',
opacity: 0.8,
fillOpacity: 0.4
});
}
}).addTo(this.map);
const southWest = L.latLng(-90, -180);
const northEast = L.latLng(90, 180);
const bounds = L.latLngBounds(southWest, northEast);
this.map.setMaxBounds(bounds);
if (!this.center) this.map.fitBounds(geoJsonObj.getBounds());
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <b>OpenStreetMap</b>'
}).addTo(this.map);
},
methods: {
getMarkers (points) {
if (Array.isArray(points)) {
if (getArrayDepth(points) === 1)
return lineString(points.reduce((acc, curr) => [...acc, [curr.x, curr.y]], []));
else
return polygon(points.map(arr => arr.reduce((acc, curr) => [...acc, [curr.x, curr.y]], [])));
}
else
return point([points.x, points.y]);
}
const getMarkers = (points: Coordinates) => {
if (Array.isArray(points)) {
if (getArrayDepth(points) === 1)
return lineString(points.reduce((acc, curr) => [...acc, [curr.x, curr.y]], []));
else
return polygon(points.map(arr => arr.reduce((acc: Coordinates[], curr: Coordinates) => [...acc, [curr.x, curr.y]], [])));
}
else
return point([points.x, points.y]);
};
onMounted(() => {
if (props.isMultiSpatial) {
for (const element of props.points as Coordinates[])
(markers.value as GeoJsonObject[]).push(getMarkers(element));
}
else {
markers.value = getMarkers(props.points as Coordinates);
if (!Array.isArray(props.points))
center.value = [props.points.y, props.points.x];
}
map.value = L.map('map', {
center: center.value || [0, 0],
zoom: 15,
minZoom: 1,
attributionControl: false
});
L.control.attribution({ prefix: '<b>Leaflet</b>' }).addTo(map.value);
const geoJsonObj = L.geoJSON((markers.value as GeoJsonObject), {
style: function () {
return {
weight: 2,
fillColor: '#ff7800',
color: '#ff7800',
opacity: 0.8,
fillOpacity: 0.4
};
},
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, {
radius: 7,
weight: 2,
fillColor: '#ff7800',
color: '#ff7800',
opacity: 0.8,
fillOpacity: 0.4
});
}
}).addTo(map.value);
const southWest = L.latLng(-90, -180);
const northEast = L.latLng(90, 180);
const bounds = L.latLngBounds(southWest, northEast);
map.value.setMaxBounds(bounds);
if (!center.value) map.value.fitBounds(geoJsonObj.getBounds());
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <b>OpenStreetMap</b>'
}).addTo(map.value);
});
</script>
<style lang="scss">

View File

@ -14,64 +14,58 @@
</div>
</template>
<script>
export default {
name: 'BaseNotification',
props: {
message: {
type: String,
default: ''
},
status: {
type: String,
default: ''
}
},
emits: ['close'],
data () {
return {
isExpanded: false
};
},
computed: {
notificationStatus () {
let className = '';
let iconName = '';
switch (this.status) {
case 'success':
className = 'toast-success';
iconName = 'mdi-check';
break;
case 'error':
className = 'toast-error';
iconName = 'mdi-alert-rhombus';
break;
case 'warning':
className = 'toast-warning';
iconName = 'mdi-alert';
break;
case 'primary':
className = 'toast-primary';
iconName = 'mdi-information-outline';
break;
}
<script setup lang="ts">
import { computed, ref } from 'vue';
return { className, iconName };
},
isExpandable () {
return this.message.length > 80;
}
const props = defineProps({
message: {
type: String,
default: ''
},
methods: {
hideToast () {
this.$emit('close');
},
toggleExpand () {
this.isExpanded = !this.isExpanded;
}
status: {
type: String,
default: ''
}
});
const isExpanded = ref(false);
const emit = defineEmits(['close']);
const notificationStatus = computed(() => {
let className = '';
let iconName = '';
switch (props.status) {
case 'success':
className = 'toast-success';
iconName = 'mdi-check';
break;
case 'error':
className = 'toast-error';
iconName = 'mdi-alert-rhombus';
break;
case 'warning':
className = 'toast-warning';
iconName = 'mdi-alert';
break;
case 'primary':
className = 'toast-primary';
iconName = 'mdi-information-outline';
break;
}
return { className, iconName };
});
const isExpandable = computed(() => props.message.length > 80);
const hideToast = () => {
emit('close');
};
const toggleExpand = () => {
isExpanded.value = !isExpanded.value;
};
</script>
<style scoped>
.toast {
display: flex;

View File

@ -9,121 +9,112 @@
</div>
</template>
<script>
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import * as ace from 'ace-builds';
import { storeToRefs } from 'pinia';
import 'ace-builds/webpack-resolver';
import { storeToRefs } from 'pinia';
import { useSettingsStore } from '@/stores/settings';
import { uidGen } from 'common/libs/uidGen';
export default {
name: 'BaseTextEditor',
props: {
modelValue: String,
mode: { type: String, default: 'text' },
editorClass: { type: String, default: '' },
autoFocus: { type: Boolean, default: false },
readOnly: { type: Boolean, default: false },
showLineNumbers: { type: Boolean, default: true },
height: { type: Number, default: 200 }
},
emits: ['update:modelValue'],
setup () {
const settingsStore = useSettingsStore();
const props = defineProps({
modelValue: String,
mode: { type: String, default: 'text' },
editorClass: { type: String, default: '' },
autoFocus: { type: Boolean, default: false },
readOnly: { type: Boolean, default: false },
showLineNumbers: { type: Boolean, default: true },
height: { type: Number, default: 200 }
});
const emit = defineEmits(['update:modelValue']);
const settingsStore = useSettingsStore();
const mode = ref(props.mode);
const {
editorTheme,
editorFontSize,
autoComplete,
lineWrap
} = storeToRefs(settingsStore);
const {
editorTheme,
editorFontSize,
autoComplete,
lineWrap
} = storeToRefs(settingsStore);
return {
editorTheme,
editorFontSize,
autoComplete,
lineWrap
};
},
data () {
return {
editor: null,
id: uidGen()
};
},
watch: {
mode () {
if (this.editor)
this.editor.session.setMode(`ace/mode/${this.mode}`);
},
editorTheme () {
if (this.editor)
this.editor.setTheme(`ace/theme/${this.editorTheme}`);
},
editorFontSize () {
const sizes = {
small: '12px',
medium: '14px',
large: '16px'
};
let editor: ace.Ace.Editor;
const id = uidGen();
if (this.editor) {
this.editor.setOptions({
fontSize: sizes[this.editorFontSize]
});
}
},
autoComplete () {
if (this.editor) {
this.editor.setOptions({
enableLiveAutocompletion: this.autoComplete
});
}
},
lineWrap () {
if (this.editor) {
this.editor.setOptions({
wrap: this.lineWrap
});
}
}
},
mounted () {
this.editor = ace.edit(`editor-${this.id}`, {
mode: `ace/mode/${this.mode}`,
theme: `ace/theme/${this.editorTheme}`,
value: this.modelValue || '',
fontSize: '14px',
printMargin: false,
readOnly: this.readOnly,
showLineNumbers: this.showLineNumbers,
showGutter: this.showLineNumbers
watch(mode, () => {
if (editor)
editor.session.setMode(`ace/mode/${props.mode}`);
});
watch(editorTheme, () => {
if (editor)
editor.setTheme(`ace/theme/${editorTheme.value}`);
});
watch(editorFontSize, () => {
const sizes = {
small: 12,
medium: 14,
large: 16
};
if (editor) {
editor.setOptions({
fontSize: sizes[editorFontSize.value as undefined as 'small' | 'medium' | 'large']
});
}
});
this.editor.setOptions({
enableBasicAutocompletion: false,
wrap: this.lineWrap,
enableSnippets: false,
enableLiveAutocompletion: false
watch(autoComplete, () => {
if (editor) {
editor.setOptions({
enableLiveAutocompletion: autoComplete.value
});
}
});
this.editor.session.on('change', () => {
const content = this.editor.getValue();
this.$emit('update:modelValue', content);
watch(lineWrap, () => {
if (editor) {
editor.setOptions({
wrap: lineWrap.value
});
}
});
if (this.autoFocus) {
setTimeout(() => {
this.editor.focus();
this.editor.resize();
}, 20);
}
onMounted(() => {
editor = ace.edit(`editor-${id}`, {
mode: `ace/mode/${mode.value}`,
theme: `ace/theme/${editorTheme.value}`,
value: props.modelValue || '',
fontSize: 14,
printMargin: false,
readOnly: props.readOnly,
showLineNumbers: props.showLineNumbers,
showGutter: props.showLineNumbers
});
editor.setOptions({
enableBasicAutocompletion: false,
wrap: lineWrap,
enableSnippets: false,
enableLiveAutocompletion: false
});
editor.session.on('changeFold', () => {
const content = editor.getValue();
emit('update:modelValue', content);
});
if (props.autoFocus) {
setTimeout(() => {
this.editor.resize();
editor.focus();
editor.resize();
}, 20);
}
};
setTimeout(() => {
editor.resize();
}, 20);
});
</script>
<style lang="scss" scoped>

View File

@ -9,67 +9,64 @@
</div>
</template>
<script>
export default {
name: 'BaseToast',
props: {
message: {
type: String,
default: ''
},
status: {
type: String,
default: ''
}
},
emits: ['close'],
data () {
return {
isVisible: false
};
},
computed: {
toastStatus () {
let className = '';
let iconName = '';
switch (this.status) {
case 'success':
className = 'toast-success';
iconName = 'mdi-check';
break;
case 'error':
className = 'toast-error';
iconName = 'mdi-alert-rhombus';
break;
case 'warning':
className = 'toast-warning';
iconName = 'mdi-alert';
break;
case 'primary':
className = 'toast-primary';
iconName = 'mdi-information-outline';
break;
}
<script setup lang="ts">
import { computed } from '@vue/reactivity';
import { ref, watch } from 'vue';
return { className, iconName };
}
const props = defineProps({
message: {
type: String,
default: ''
},
watch: {
message: function () {
if (this.message)
this.isVisible = true;
else
this.isVisible = false;
}
},
methods: {
hideToast () {
this.isVisible = false;
this.$emit('close');
}
status: {
type: String,
default: ''
}
});
const isVisible = ref(false);
const message = ref(props.message);
const emit = defineEmits(['close']);
const toastStatus = computed(() => {
let className = '';
let iconName = '';
switch (props.status) {
case 'success':
className = 'toast-success';
iconName = 'mdi-check';
break;
case 'error':
className = 'toast-error';
iconName = 'mdi-alert-rhombus';
break;
case 'warning':
className = 'toast-warning';
iconName = 'mdi-alert';
break;
case 'primary':
className = 'toast-primary';
iconName = 'mdi-information-outline';
break;
}
return { className, iconName };
});
watch(message, () => {
if (message.value)
isVisible.value = true;
else
isVisible.value = false;
});
const hideToast = () => {
isVisible.value = false;
emit('close');
};
</script>
<style scoped>
.toast {
display: flex;

View File

@ -7,7 +7,7 @@
{{ lastPart(modelValue) }}
</span>
<i
v-if="modelValue.length"
v-if="modelValue"
class="file-uploader-reset mdi mdi-close"
@click.prevent="clear"
/>
@ -22,41 +22,35 @@
</label>
</template>
<script>
export default {
name: 'BaseUploadInput',
props: {
message: {
default: 'Browse',
type: String
},
modelValue: {
default: '',
type: String
}
},
emits: ['change', 'clear'],
data () {
return {
id: null
};
},
mounted () {
this.id = this._uid;
},
methods: {
clear () {
this.$emit('clear');
},
lastPart (string) {
if (!string) return '';
<script setup lang="ts">
import { uidGen } from 'common/libs/uidGen';
string = string.split(/[/\\]+/).pop();
if (string.length >= 19)
string = `...${string.slice(-19)}`;
return string;
}
defineProps({
message: {
default: 'Browse',
type: String
},
modelValue: {
default: '',
type: String
}
});
const emit = defineEmits(['change', 'clear']);
const id = uidGen();
const clear = () => {
emit('clear');
};
const lastPart = (string: string) => {
if (!string) return '';
string = string.split(/[/\\]+/).pop();
if (string.length >= 19)
string = `...${string.slice(-19)}`;
return string;
};
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="vscroll-holder">
<div ref="root" class="vscroll-holder">
<div
class="vscroll-spacer"
:style="{
@ -20,71 +20,77 @@
</div>
</template>
<script>
export default {
name: 'BaseVirtualScroll',
props: {
items: Array,
itemHeight: Number,
visibleHeight: Number,
scrollElement: {
type: HTMLDivElement,
default: null
}
},
data () {
return {
topHeight: 0,
bottomHeight: 0,
visibleItems: [],
renderTimeout: null,
localScrollElement: null
};
},
watch: {
scrollElement () {
this.setScrollElement();
}
},
mounted () {
this.setScrollElement();
},
beforeUnmount () {
this.localScrollElement.removeEventListener('scroll', this.checkScrollPosition);
},
methods: {
checkScrollPosition (e) {
clearTimeout(this.renderTimeout);
<script setup lang="ts">
import { onBeforeUnmount, onMounted, Ref, ref, watch } from 'vue';
this.renderTimeout = setTimeout(() => {
this.updateWindow(e);
}, 200);
},
updateWindow () {
const visibleItemsCount = Math.ceil(this.visibleHeight / this.itemHeight);
const totalScrollHeight = this.items.length * this.itemHeight;
const offset = 50;
const scrollTop = this.localScrollElement.scrollTop;
const firstVisibleIndex = Math.floor(scrollTop / this.itemHeight);
const lastVisibleIndex = firstVisibleIndex + visibleItemsCount;
const firstCutIndex = Math.max(firstVisibleIndex - offset, 0);
const lastCutIndex = lastVisibleIndex + offset;
this.visibleItems = this.items.slice(firstCutIndex, lastCutIndex);
this.topHeight = firstCutIndex * this.itemHeight;
this.bottomHeight = totalScrollHeight - this.visibleItems.length * this.itemHeight - this.topHeight;
},
setScrollElement () {
if (this.localScrollElement)
this.localScrollElement.removeEventListener('scroll', this.checkScrollPosition);
this.localScrollElement = this.scrollElement ? this.scrollElement : this.$el;
this.updateWindow();
this.localScrollElement.addEventListener('scroll', this.checkScrollPosition);
}
const props = defineProps({
items: Array,
itemHeight: Number,
visibleHeight: Number,
scrollElement: {
type: HTMLDivElement,
default: null
}
});
const root = ref(null);
const topHeight: Ref<number> = ref(0);
const bottomHeight: Ref<number> = ref(0);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const visibleItems: Ref<any[]> = ref([]);
const renderTimeout: Ref<NodeJS.Timeout> = ref(null);
const localScrollElement: Ref<HTMLDivElement> = ref(null);
const scrollElement = ref(props.scrollElement);
const checkScrollPosition = () => {
clearTimeout(renderTimeout.value);
renderTimeout.value = setTimeout(() => {
updateWindow();
}, 200);
};
const updateWindow = () => {
const visibleItemsCount = Math.ceil(props.visibleHeight / props.itemHeight);
const totalScrollHeight = props.items.length * props.itemHeight;
const offset = 50;
const scrollTop = localScrollElement.value.scrollTop;
const firstVisibleIndex = Math.floor(scrollTop / props.itemHeight);
const lastVisibleIndex = firstVisibleIndex + visibleItemsCount;
const firstCutIndex = Math.max(firstVisibleIndex - offset, 0);
const lastCutIndex = lastVisibleIndex + offset;
visibleItems.value = props.items.slice(firstCutIndex, lastCutIndex);
topHeight.value = firstCutIndex * props.itemHeight;
bottomHeight.value = totalScrollHeight - visibleItems.value.length * props.itemHeight - topHeight.value;
};
const setScrollElement = () => {
if (localScrollElement.value)
localScrollElement.value.removeEventListener('scroll', checkScrollPosition);
localScrollElement.value = scrollElement.value ? scrollElement.value : root.value;
updateWindow();
localScrollElement.value.addEventListener('scroll', checkScrollPosition);
};
watch(scrollElement, () => {
setScrollElement();
});
onMounted(() => {
setScrollElement();
});
onBeforeUnmount(() => {
localScrollElement.value.removeEventListener('scroll', checkScrollPosition);
});
defineExpose({
updateWindow
});
</script>

View File

@ -52,7 +52,7 @@
>
<BaseUploadInput
v-else-if="inputProps().type === 'file'"
:value="selectedValue"
:model-value="selectedValue"
:message="$t('word.browse')"
@clear="clearValue"
@change="filesChange($event)"

View File

@ -134,7 +134,7 @@
</template>
<script>
import arrayToFile from '../libs/arrayToFile';
import { arrayToFile } from '../libs/arrayToFile';
import { useNotificationsStore } from '@/stores/notifications';
import Schema from '@/ipc-api/Schema';
import { useConnectionsStore } from '@/stores/connections';

View File

@ -328,7 +328,7 @@ import { storeToRefs } from 'pinia';
import { useApplicationStore } from '@/stores/application';
import { useSettingsStore } from '@/stores/settings';
import { useWorkspacesStore } from '@/stores/workspaces';
import localesNames from '@/i18n/supported-locales';
import { localesNames } from '@/i18n/supported-locales';
import ModalSettingsUpdate from '@/components/ModalSettingsUpdate';
import ModalSettingsChangelog from '@/components/ModalSettingsChangelog';
import BaseTextEditor from '@/components/BaseTextEditor';

View File

@ -96,7 +96,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="connection.databasePath"
:model-value="connection.databasePath"
:message="$t('word.browse')"
@clear="pathClear('databasePath')"
@change="pathSelection($event, 'databasePath')"
@ -211,7 +211,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="connection.key"
:model-value="connection.key"
:message="$t('word.browse')"
@clear="pathClear('key')"
@change="pathSelection($event, 'key')"
@ -224,7 +224,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="connection.cert"
:model-value="connection.cert"
:message="$t('word.browse')"
@clear="pathClear('cert')"
@change="pathSelection($event, 'cert')"
@ -237,7 +237,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="connection.ca"
:model-value="connection.ca"
:message="$t('word.browse')"
@clear="pathClear('ca')"
@change="pathSelection($event, 'ca')"
@ -342,7 +342,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="connection.sshKey"
:model-value="connection.sshKey"
:message="$t('word.browse')"
@clear="pathClear('sshKey')"
@change="pathSelection($event, 'sshKey')"

View File

@ -92,7 +92,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="localConnection.databasePath"
:model-value="localConnection.databasePath"
:message="$t('word.browse')"
@clear="pathClear('databasePath')"
@change="pathSelection($event, 'databasePath')"
@ -207,7 +207,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="localConnection.key"
:model-value="localConnection.key"
:message="$t('word.browse')"
@clear="pathClear('key')"
@change="pathSelection($event, 'key')"
@ -220,7 +220,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="localConnection.cert"
:model-value="localConnection.cert"
:message="$t('word.browse')"
@clear="pathClear('cert')"
@change="pathSelection($event, 'cert')"
@ -233,7 +233,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="localConnection.ca"
:model-value="localConnection.ca"
:message="$t('word.browse')"
@clear="pathClear('ca')"
@change="pathSelection($event, 'ca')"
@ -330,7 +330,7 @@
</div>
<div class="column col-8 col-sm-12">
<BaseUploadInput
:value="localConnection.sshKey"
:model-value="localConnection.sshKey"
:message="$t('word.browse')"
@clear="pathClear('sshKey')"
@change="pathSelection($event, 'sshKey')"

View File

@ -90,7 +90,7 @@
</label>
</div>
<div class="td p-0 type-int" tabindex="0">
<template v-if="fieldType.length">
<template v-if="fieldType?.length">
<span
v-if="!isInlineEditor.length"
class="cell-content"
@ -355,7 +355,7 @@ export default {
},
props: {
row: Object,
dataTypes: Array,
dataTypes: { type: Array, default: () => [] },
indexes: Array,
foreigns: Array,
customizations: Object

View File

@ -112,7 +112,7 @@ import { uidGen } from 'common/libs/uidGen';
import { useNotificationsStore } from '@/stores/notifications';
import { useSettingsStore } from '@/stores/settings';
import { useWorkspacesStore } from '@/stores/workspaces';
import arrayToFile from '../libs/arrayToFile';
import { arrayToFile } from '../libs/arrayToFile';
import { TEXT, LONG_TEXT, BLOB } from 'common/fieldTypes';
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
import WorkspaceTabQueryTableRow from '@/components/WorkspaceTabQueryTableRow';

View File

@ -1,4 +1,4 @@
export default {
export const localesNames = {
'en-US': 'English',
'it-IT': 'Italiano',
'ar-SA': 'العربية',

View File

@ -29,7 +29,7 @@ createApp(App)
.mount('#app');
const { locale } = useSettingsStore();
i18n.global.locale = locale;
i18n.global.locale = locale as string;// TODO: temp
// IPC exceptions
ipcRenderer.on('unhandled-exception', (event, error) => {
@ -59,7 +59,7 @@ ipcRenderer.on('no-auto-update', () => {
ipcRenderer.on('download-progress', (event, data) => {
useApplicationStore().updateStatus = 'downloading';
useApplicationStore().downloadprogress = data.percent;
useApplicationStore().downloadProgress = data.percent;
});
ipcRenderer.on('update-downloaded', () => {

View File

@ -4,6 +4,9 @@ import Connection from '@/ipc-api/Connection';
import Schema from '@/ipc-api/Schema';
import Users from '@/ipc-api/Users';
import { uidGen } from 'common/libs/uidGen';
import customizations from 'common/customizations';
import { useConnectionsStore } from '@/stores/connections';
import { useNotificationsStore } from '@/stores/notifications';
import { useSettingsStore } from '@/stores/settings';
@ -22,14 +25,14 @@ export const useWorkspacesStore = defineStore('workspaces', {
if (state.selectedWorkspace) return state.selectedWorkspace;
return state.workspaces[0].uid;
},
getWorkspace: state => uid => {
getWorkspace: state => (uid) => {
return state.workspaces.find(workspace => workspace.uid === uid);
},
getDatabaseVariable: state => (uid, name) => {
return state.workspaces.find(workspace => workspace.uid === uid).variables.find(variable => variable.name === name);
},
getWorkspaceTab (state) {
return tUid => {
return (tUid) => {
if (!this.getSelected) return;
const workspace = state.workspaces.find(workspace => workspace.uid === this.getSelected);
if ('tabs' in workspace)
@ -89,24 +92,24 @@ export const useWorkspacesStore = defineStore('workspaces', {
else {
let dataTypes = [];
let indexTypes = [];
let customizations = {};
let clientCustomizations;
switch (connection.client) {
case 'mysql':
case 'maria':
dataTypes = require('common/data-types/mysql');
indexTypes = require('common/index-types/mysql');
customizations = require('common/customizations/mysql');
dataTypes = require('common/data-types/mysql').default;
indexTypes = require('common/index-types/mysql').default;
clientCustomizations = customizations.mysql;
break;
case 'pg':
dataTypes = require('common/data-types/postgresql');
indexTypes = require('common/index-types/postgresql');
customizations = require('common/customizations/postgresql');
dataTypes = require('common/data-types/postgresql').default;
indexTypes = require('common/index-types/postgresql').default;
clientCustomizations = customizations.pg;
break;
case 'sqlite':
dataTypes = require('common/data-types/sqlite');
indexTypes = require('common/index-types/sqlite');
customizations = require('common/customizations/sqlite');
dataTypes = require('common/data-types/sqlite').default;
indexTypes = require('common/index-types/sqlite').default;
clientCustomizations = customizations.sqlite;
break;
}
@ -144,7 +147,7 @@ export const useWorkspacesStore = defineStore('workspaces', {
client: connection.client,
dataTypes,
indexTypes,
customizations,
customizations: clientCustomizations,
structure: response,
connectionStatus: 'connected',
tabs: cachedTabs,

2
src/renderer/untyped.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
declare module '@/App.vue';
declare module 'v-mask';