desktop version supports rtl
This commit is contained in:
@@ -76,8 +76,13 @@
|
||||
"vue-tsc": "^2.2.10"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"last 5 Chrome versions",
|
||||
"last 5 Firefox versions",
|
||||
"last 5 Safari versions",
|
||||
"last 5 Edge versions",
|
||||
"last 5 ChromeAndroid versions",
|
||||
"last 5 iOS versions",
|
||||
"not IE <= 11",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-preset-env': {},
|
||||
},
|
||||
plugins: {
|
||||
'autoprefixer': {
|
||||
logical: false
|
||||
},
|
||||
'postcss-preset-env': {},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<v-tooltip activator="parent">{{ tt('Click to close') }}</v-tooltip>
|
||||
<div class="d-inline-flex">
|
||||
<img alt="logo" class="notification-logo" :src="APPLICATION_LOGO_PATH" />
|
||||
<span class="ml-2">{{ tt('global.app.title') }}</span>
|
||||
<span class="ms-2">{{ tt('global.app.title') }}</span>
|
||||
</div>
|
||||
<div>
|
||||
{{ currentNotificationContent }}
|
||||
|
||||
@@ -307,8 +307,8 @@ init(props.length, props.modelValue);
|
||||
|
||||
.pin-code-input input {
|
||||
text-align: center;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-inline-start: 10px;
|
||||
padding-inline-end: 10px;
|
||||
width: 100%;
|
||||
height: var(--ebk-pin-code-input-height) !important;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { type CommonAccountBalanceTrendsChartProps, useAccountBalanceTrendsChart
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
|
||||
import type { NameValue } from '@/core/base.ts';
|
||||
import { TextDirection } from '@/core/text.ts';
|
||||
import type { ColorValue } from '@/core/color.ts';
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
import { AccountBalanceTrendChartType } from '@/core/statistics.ts';
|
||||
@@ -47,11 +48,12 @@ interface AccountBalanceTrendsChartDataItem {
|
||||
const props = defineProps<DesktopAccountBalanceTrendsChartProps>();
|
||||
|
||||
const theme = useTheme();
|
||||
const { tt, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
const { tt, getCurrentLanguageTextDirection, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
const { allDataItems, allDisplayDateRanges } = useAccountBalanceTrendsChartBase(props);
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
||||
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
||||
|
||||
const allSeries = computed<AccountBalanceTrendsChartDataItem[]>(() => {
|
||||
@@ -203,7 +205,7 @@ const chartOptions = computed<object>(() => {
|
||||
|
||||
for (let i = 0; i < displayItems.length; i++) {
|
||||
tooltip += `<div><span class="chart-pointer" style="background-color: #${DEFAULT_CHART_COLORS[i]}"></span>`
|
||||
+ `<span>${displayItems[i].name}</span><span style="margin-left: 20px; float: right">${displayItems[i].value}</span><br/>`
|
||||
+ `<span>${displayItems[i].name}</span><span class="ms-5" style="float: inline-end">${displayItems[i].value}</span><br/>`
|
||||
+ `</div>`;
|
||||
}
|
||||
|
||||
@@ -214,7 +216,7 @@ const chartOptions = computed<object>(() => {
|
||||
|
||||
return `${params[0].name}<br/>`
|
||||
+ '<div><span class="chart-pointer" style="background-color: #' + DEFAULT_CHART_COLORS[0] + '"></span>'
|
||||
+ `<span>${props.legendName}</span><span style="margin-left: 20px; float: right">${value}</span><br/>`
|
||||
+ `<span>${props.legendName}</span><span class="ms-5" style="float: inline-end">${value}</span><br/>`
|
||||
+ '</div>';
|
||||
}
|
||||
}
|
||||
@@ -226,7 +228,8 @@ const chartOptions = computed<object>(() => {
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: allDisplayDateRanges.value
|
||||
data: allDisplayDateRanges.value,
|
||||
inverse: textDirection.value === TextDirection.RTL
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="text-no-wrap" v-if="currency && appendText">{{ appendText }}</div>
|
||||
<v-tooltip :text="tt('Enter formula mode')">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-icon class="ml-2" :icon="mdiCalculatorVariantOutline"
|
||||
<v-icon class="ms-2" :icon="mdiCalculatorVariantOutline"
|
||||
@keydown.enter="enterFormulaMode" @keydown.space="enterFormulaMode" @click="enterFormulaMode"
|
||||
v-bind="props" v-if="enableFormula && !formulaMode"></v-icon>
|
||||
</template>
|
||||
@@ -34,14 +34,14 @@
|
||||
<div class="text-no-wrap" v-if="currency && appendText">{{ appendText }}</div>
|
||||
<v-tooltip :text="tt('Calculate formula result')">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-icon class="ml-2" color="primary" :icon="mdiCheck"
|
||||
<v-icon class="ms-2" color="primary" :icon="mdiCheck"
|
||||
@click="calculateFormula" v-bind="props"
|
||||
v-if="formulaMode"></v-icon>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
<v-tooltip :text="tt('Exit formula mode')">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-icon class="ml-2" color="secondary" :icon="mdiClose"
|
||||
<v-icon class="ms-2" color="secondary" :icon="mdiClose"
|
||||
@click="exitFormulaMode" v-bind="props"
|
||||
v-if="formulaMode"></v-icon>
|
||||
</template>
|
||||
@@ -379,6 +379,6 @@ watch(currentValue, (newValue) => {
|
||||
}
|
||||
|
||||
.text-field-with-colored-label.has-pretend-text .v-field__input {
|
||||
padding-left: 0.5rem;
|
||||
padding-inline-start: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</template>
|
||||
|
||||
<template #no-data>
|
||||
<div class="color-select-dropdown" ref="dropdownMenu">
|
||||
<div class="color-select-dropdown px-2" ref="dropdownMenu">
|
||||
<div class="color-item" :class="{ 'row-has-selected-item': hasSelectedIcon(row) }"
|
||||
:style="`grid-template-columns: repeat(${itemPerRow}, minmax(0, 1fr));`"
|
||||
:key="idx" v-for="(row, idx) in allColorRows">
|
||||
@@ -26,7 +26,9 @@
|
||||
:icon="mdiSquareRounded" :color="getFinalColor(colorInfo.color)"
|
||||
v-if="!modelValue || modelValue !== colorInfo.color" />
|
||||
<v-badge class="right-bottom-icon" color="primary"
|
||||
location="bottom right" offset-x="8" offset-y="8" :icon="mdiCheck"
|
||||
offset-x="8" offset-y="8"
|
||||
:location="`bottom ${textDirection === TextDirection.LTR ? 'right' : 'left'}`"
|
||||
:icon="mdiCheck"
|
||||
v-if="modelValue && modelValue === colorInfo.color">
|
||||
<v-icon class="ma-2" size="28" :icon="mdiSquareRounded" :color="getFinalColor(colorInfo.color)" />
|
||||
</v-badge>
|
||||
@@ -41,6 +43,9 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, useTemplateRef, nextTick } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { TextDirection } from '@/core/text.ts';
|
||||
import type { ColorValue, ColorInfo } from '@/core/color.ts';
|
||||
import { DEFAULT_ICON_COLOR } from '@/consts/color.ts';
|
||||
import { arrayContainsFieldValue } from '@/lib/common.ts';
|
||||
@@ -64,9 +69,12 @@ const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: ColorValue): void;
|
||||
}>();
|
||||
|
||||
const { getCurrentLanguageTextDirection } = useI18n();
|
||||
|
||||
const dropdownMenu = useTemplateRef<HTMLElement>('dropdownMenu');
|
||||
const itemPerRow = ref<number>(props.columnCount || 7);
|
||||
|
||||
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
||||
const allColorRows = computed<ColorInfo[][]>(() => getColorsInRows(props.allColorInfos, itemPerRow.value));
|
||||
|
||||
const color = computed<ColorValue>({
|
||||
@@ -98,11 +106,6 @@ function onMenuStateChanged(state: boolean): void {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.color-select-dropdown {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.color-select-dropdown .color-item {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
@@ -350,10 +350,10 @@ function onKeyDown(type: string, e: KeyboardEvent): void {
|
||||
}
|
||||
|
||||
.date-time-select-time-picker-container .v-autocomplete.v-input--density-compact .v-field__append-inner .v-autocomplete__menu-icon {
|
||||
margin-left: 0;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
.date-time-select-time-picker-container .v-autocomplete .v-field--appended {
|
||||
padding-right: 8px;
|
||||
padding-inline-end: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</template>
|
||||
|
||||
<template #no-data>
|
||||
<div class="icon-select-dropdown" ref="dropdownMenu">
|
||||
<div class="icon-select-dropdown px-2" ref="dropdownMenu">
|
||||
<div class="icon-item" :class="{ 'row-has-selected-item': hasSelectedIcon(row) }"
|
||||
:style="`grid-template-columns: repeat(${itemPerRow}, minmax(0, 1fr));`"
|
||||
:key="idx" v-for="(row, idx) in allIconRows">
|
||||
@@ -24,7 +24,9 @@
|
||||
<div class="cursor-pointer" @click="icon = iconInfo.id">
|
||||
<ItemIcon class="ma-2" icon-type="fixed" :icon-id="iconInfo.icon" :color="color" v-if="!modelValue || modelValue !== iconInfo.id" />
|
||||
<v-badge class="right-bottom-icon" color="primary"
|
||||
location="bottom right" offset-x="8" offset-y="10" :icon="mdiCheck"
|
||||
offset-x="8" offset-y="10"
|
||||
:location="`bottom ${textDirection === TextDirection.LTR ? 'right' : 'left'}`"
|
||||
:icon="mdiCheck"
|
||||
v-if="modelValue && modelValue === iconInfo.id">
|
||||
<ItemIcon class="ma-2" icon-type="fixed" :icon-id="iconInfo.icon" :color="color" />
|
||||
</v-badge>
|
||||
@@ -39,6 +41,9 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, useTemplateRef, nextTick } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { TextDirection } from '@/core/text.ts';
|
||||
import type { ColorValue } from '@/core/color.ts';
|
||||
import type { IconInfo, IconInfoWithId } from '@/core/icon.ts';
|
||||
import { arrayContainsFieldValue } from '@/lib/common.ts';
|
||||
@@ -63,9 +68,12 @@ const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string): void;
|
||||
}>();
|
||||
|
||||
const { getCurrentLanguageTextDirection } = useI18n();
|
||||
|
||||
const dropdownMenu = useTemplateRef<HTMLElement>('dropdownMenu');
|
||||
const itemPerRow = ref<number>(props.columnCount || 7);
|
||||
|
||||
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
||||
const allIconRows = computed<IconInfoWithId[][]>(() => getIconsInRows(props.allIconInfos, itemPerRow.value));
|
||||
|
||||
const icon = computed<string>({
|
||||
@@ -89,11 +97,6 @@ function onMenuStateChanged(state: boolean): void {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-select-dropdown {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.icon-select-dropdown .icon-item {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<i class="item-icon" :class="classes" :style="style" v-if="!hiddenStatus">
|
||||
<slot></slot>
|
||||
</i>
|
||||
<v-badge class="right-bottom-icon" color="secondary"
|
||||
location="bottom right" offset-y="4" :icon="mdiEyeOffOutline"
|
||||
v-if="hiddenStatus">
|
||||
<v-badge class="right-bottom-icon" color="secondary" offset-y="4"
|
||||
:location="`bottom ${textDirection === TextDirection.LTR ? 'right' : 'left'}`"
|
||||
:icon="mdiEyeOffOutline" v-if="hiddenStatus">
|
||||
<i class="item-icon" :class="classes" :style="style">
|
||||
<slot></slot>
|
||||
</i>
|
||||
@@ -15,6 +15,10 @@
|
||||
import { computed } from 'vue';
|
||||
import { type CommonIconProps, useItemIconBase } from '@/components/base/ItemIconBase.ts';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { TextDirection } from '@/core/text.ts';
|
||||
|
||||
import {
|
||||
mdiEyeOffOutline
|
||||
} from '@mdi/js';
|
||||
@@ -25,8 +29,12 @@ interface DesktopItemIconProps extends CommonIconProps {
|
||||
}
|
||||
|
||||
const props = defineProps<DesktopItemIconProps>();
|
||||
|
||||
const { getCurrentLanguageTextDirection } = useI18n();
|
||||
const { style, getAccountIcon, getCategoryIcon } = useItemIconBase(props);
|
||||
|
||||
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
||||
|
||||
const classes = computed<string>(() => {
|
||||
let allClasses = props.class ? (props.class + ' ') : '';
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import { type CommonMonthlyTrendsChartProps, type MonthlyTrendsBarChartClickEven
|
||||
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
|
||||
import { TextDirection } from '@/core/text.ts';
|
||||
import { type Year1BasedMonth, DateRangeScene } from '@/core/datetime.ts';
|
||||
import type { ColorValue } from '@/core/color.ts';
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
@@ -71,7 +72,9 @@ const emit = defineEmits<{
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const { tt,
|
||||
const {
|
||||
tt,
|
||||
getCurrentLanguageTextDirection,
|
||||
formatUnixTimeToShortYear,
|
||||
formatYearQuarter,
|
||||
formatUnixTimeToShortYearMonth,
|
||||
@@ -86,6 +89,7 @@ const userStore = useUserStore();
|
||||
|
||||
const selectedLegends = ref<Record<string, boolean>>({});
|
||||
|
||||
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
||||
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
||||
|
||||
const itemsMap = computed<Record<string, Record<string, unknown>>>(() => {
|
||||
@@ -327,7 +331,7 @@ const chartOptions = computed<object>(() => {
|
||||
if (displayItems.length === 1 || item.totalAmount !== 0) {
|
||||
const value = formatAmountToLocalizedNumeralsWithCurrency(item.totalAmount, props.defaultCurrency);
|
||||
tooltip += '<div><span class="chart-pointer" style="background-color: ' + item.color + '"></span>';
|
||||
tooltip += `<span>${item.name}</span><span style="margin-left: 20px; float: right">${value}</span><br/>`;
|
||||
tooltip += `<span>${item.name}</span><span class="ms-5" style="float: inline-end">${value}</span><br/>`;
|
||||
tooltip += '</div>';
|
||||
}
|
||||
}
|
||||
@@ -336,7 +340,7 @@ const chartOptions = computed<object>(() => {
|
||||
const displayTotalAmount = formatAmountToLocalizedNumeralsWithCurrency(totalAmount, props.defaultCurrency);
|
||||
tooltip = '<div style="border-bottom: ' + (isDarkMode.value ? '#eee' : '#333') + ' dashed 1px">'
|
||||
+ '<span class="chart-pointer" style="background-color: ' + (isDarkMode.value ? '#eee' : '#333') + '"></span>'
|
||||
+ `<span>${tt('Total Amount')}</span><span style="margin-left: 20px; float: right">${displayTotalAmount}</span><br/>`
|
||||
+ `<span>${tt('Total Amount')}</span><span class="ms-5" style="float: inline-end">${displayTotalAmount}</span><br/>`
|
||||
+ '</div>' + tooltip;
|
||||
}
|
||||
|
||||
@@ -365,7 +369,8 @@ const chartOptions = computed<object>(() => {
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: allDisplayDateRanges.value
|
||||
data: allDisplayDateRanges.value,
|
||||
inverse: textDirection.value === TextDirection.RTL
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
|
||||
@@ -143,13 +143,13 @@ const chartOptions = computed<object>(() => {
|
||||
let tooltip = `<div><span class="chart-pointer" style="background-color: ${params.color}"></span>`;
|
||||
|
||||
if (name) {
|
||||
tooltip += `<span>${name}</span><br/>`;
|
||||
tooltip += `<div class="d-inline-flex">${name}</div><br/>`;
|
||||
}
|
||||
|
||||
if (props.showValue) {
|
||||
tooltip += `<span>${value} (${percent})</span>`;
|
||||
tooltip += `<div class="d-inline-flex"><span>${value}</span><span class="ms-1">(${percent})</span></div>`;
|
||||
} else {
|
||||
tooltip += `<span>${percent}</span>`;
|
||||
tooltip += `<div class="d-inline-flex">${percent}</div>`;
|
||||
}
|
||||
|
||||
tooltip += '</div>';
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
:class="{ 'frequency-value-selected v-list-item--active text-primary': isFrequencyValueSelected(weekDay.type) }"
|
||||
v-for="weekDay in allWeekDays">
|
||||
<template #prepend="{ isActive }">
|
||||
<v-checkbox density="compact" class="mr-1" :model-value="isActive"></v-checkbox>
|
||||
<v-checkbox density="compact" class="me-1" :model-value="isActive"></v-checkbox>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
@@ -44,7 +44,7 @@
|
||||
:class="{ 'frequency-value-selected v-list-item--active text-primary': isFrequencyValueSelected(monthDay.day) }"
|
||||
v-for="monthDay in allAvailableMonthDays">
|
||||
<template #prepend="{ isActive }">
|
||||
<v-checkbox density="compact" class="mr-1" :model-value="isActive"></v-checkbox>
|
||||
<v-checkbox density="compact" class="me-1" :model-value="isActive"></v-checkbox>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
<template #selection>
|
||||
<div class="d-flex align-center text-truncate cursor-pointer">
|
||||
<span class="text-truncate" v-if="customSelectionPrimaryText">{{ customSelectionPrimaryText }}</span>
|
||||
<v-icon class="disabled" :icon="mdiChevronRight" size="23" v-if="customSelectionPrimaryText && customSelectionSecondaryText" />
|
||||
<v-icon class="icon-with-direction disabled" :icon="mdiChevronRight" size="23" v-if="customSelectionPrimaryText && customSelectionSecondaryText" />
|
||||
<span class="text-truncate" v-if="customSelectionPrimaryText && customSelectionSecondaryText">{{ customSelectionSecondaryText }}</span>
|
||||
<span class="text-truncate" v-if="!customSelectionPrimaryText && !selectedPrimaryItem && !selectedSecondaryItem">{{ noSelectionText }}</span>
|
||||
<span class="text-truncate" v-if="!customSelectionPrimaryText && showSelectionPrimaryText && selectedPrimaryItem">{{ selectionPrimaryItemText }}</span>
|
||||
<v-icon class="disabled" :icon="mdiChevronRight" size="23" v-if="!customSelectionPrimaryText && showSelectionPrimaryText && selectedPrimaryItem && selectedSecondaryItem" />
|
||||
<ItemIcon class="mr-2" icon-type="account" size="21.5px"
|
||||
<v-icon class="icon-with-direction disabled" :icon="mdiChevronRight" size="23" v-if="!customSelectionPrimaryText && showSelectionPrimaryText && selectedPrimaryItem && selectedSecondaryItem" />
|
||||
<ItemIcon class="me-2" icon-type="account" size="21.5px"
|
||||
:icon-id="selectedSecondaryItem && secondaryIconField ? (selectedSecondaryItem as Record<string, unknown>)[secondaryIconField] : null"
|
||||
:color="selectedSecondaryItem && secondaryColorField ? (selectedSecondaryItem as Record<string, unknown>)[secondaryColorField] : null"
|
||||
v-if="!customSelectionPrimaryText && selectedSecondaryItem && showSelectionSecondaryIcon" />
|
||||
@@ -47,7 +47,7 @@
|
||||
v-for="item in filteredItems"
|
||||
@click="onPrimaryItemClicked(item)">
|
||||
<template #prepend>
|
||||
<ItemIcon class="mr-2" :icon-type="primaryIconType"
|
||||
<ItemIcon class="me-2" :icon-type="primaryIconType"
|
||||
:icon-id="primaryIconField ? (item as Record<string, unknown>)[primaryIconField] : undefined" :color="primaryColorField ? (item as Record<string, unknown>)[primaryColorField] : undefined"></ItemIcon>
|
||||
</template>
|
||||
<template #title>
|
||||
@@ -66,7 +66,7 @@
|
||||
v-for="subItem in filteredSubItems"
|
||||
@click="onSecondaryItemClicked(subItem)">
|
||||
<template #prepend>
|
||||
<ItemIcon class="mr-2" :icon-type="secondaryIconType"
|
||||
<ItemIcon class="me-2" :icon-type="secondaryIconType"
|
||||
:icon-id="secondaryIconField ? subItem[secondaryIconField] : undefined" :color="secondaryColorField ? subItem[secondaryColorField] : undefined"></ItemIcon>
|
||||
</template>
|
||||
<template #title>
|
||||
|
||||
4
src/core/text.ts
Normal file
4
src/core/text.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum TextDirection {
|
||||
LTR = 'ltr',
|
||||
RTL = 'rtl'
|
||||
}
|
||||
@@ -72,7 +72,7 @@ import draggable from 'vuedraggable';
|
||||
import router from '@/router/desktop.ts';
|
||||
|
||||
import { DecimalSeparator } from '@/core/numeral.ts';
|
||||
import { getI18nOptions } from '@/locales/helpers.ts';
|
||||
import { getI18nOptions, getRtlLocales } from '@/locales/helpers.ts';
|
||||
|
||||
import PinCodeInput from '@/components/common/PinCodeInput.vue';
|
||||
import MapView from '@/components/common/MapView.vue';
|
||||
@@ -433,6 +433,7 @@ const vuetify = createVuetify({
|
||||
}
|
||||
},
|
||||
locale: {
|
||||
rtl: getRtlLocales(),
|
||||
adapter: ((i18nGlobal: Composer) => {
|
||||
const instance: LocaleInstance = {
|
||||
name: 'ezBookkeeping i18n',
|
||||
|
||||
@@ -4,7 +4,16 @@ import 'moment-timezone/moment-timezone-utils';
|
||||
|
||||
import type { PartialRecord, NameValue, TypeAndName, TypeAndDisplayName, LocalizedSwitchOption } from '@/core/base.ts';
|
||||
|
||||
import { type LanguageInfo, type LanguageOption, ALL_LANGUAGES, DEFAULT_LANGUAGE } from '@/locales/index.ts';
|
||||
import {
|
||||
type LanguageInfo,
|
||||
type LanguageOption,
|
||||
ALL_LANGUAGES,
|
||||
DEFAULT_LANGUAGE
|
||||
} from '@/locales/index.ts';
|
||||
|
||||
import {
|
||||
TextDirection
|
||||
} from '@/core/text.ts';
|
||||
|
||||
import {
|
||||
type DateFormat,
|
||||
@@ -222,6 +231,24 @@ export function getI18nOptions(): object {
|
||||
};
|
||||
}
|
||||
|
||||
export function getRtlLocales(): Record<string, boolean> {
|
||||
const rtlLocales: Record<string, boolean> = {};
|
||||
|
||||
for (const languageKey in ALL_LANGUAGES) {
|
||||
if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const languageInfo = ALL_LANGUAGES[languageKey];
|
||||
|
||||
if (languageInfo.textDirection === TextDirection.RTL) {
|
||||
rtlLocales[languageKey] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return rtlLocales;
|
||||
}
|
||||
|
||||
export function useI18n() {
|
||||
const { t, locale } = useVueI18n();
|
||||
|
||||
@@ -721,6 +748,11 @@ export function useI18n() {
|
||||
return currentLanguageInfo.displayName;
|
||||
}
|
||||
|
||||
function getCurrentLanguageTextDirection(): TextDirection {
|
||||
const currentLanguageInfo = getCurrentLanguageInfo();
|
||||
return currentLanguageInfo.textDirection;
|
||||
}
|
||||
|
||||
function getDefaultCurrency(): string {
|
||||
return t('default.currency');
|
||||
}
|
||||
@@ -1894,7 +1926,9 @@ export function useI18n() {
|
||||
logger.info(`No specified language, use browser default language ${languageKey}`);
|
||||
}
|
||||
|
||||
if (!getLanguageInfo(languageKey)) {
|
||||
const languageInfo = getLanguageInfo(languageKey);
|
||||
|
||||
if (!languageInfo) {
|
||||
languageKey = getDefaultLanguage();
|
||||
logger.warn(`Not found language ${languageKey}, use browser default language ${languageKey}`);
|
||||
}
|
||||
@@ -1925,6 +1959,12 @@ export function useI18n() {
|
||||
services.setLocale(languageKey);
|
||||
document.querySelector('html')?.setAttribute('lang', languageKey);
|
||||
|
||||
if (languageInfo && languageInfo.textDirection === TextDirection.LTR) {
|
||||
document.querySelector('html')?.removeAttribute('dir');
|
||||
} else if (languageInfo && languageInfo.textDirection === TextDirection.RTL) {
|
||||
document.querySelector('html')?.setAttribute('dir', 'rtl');
|
||||
}
|
||||
|
||||
const defaultCurrency = getDefaultCurrency();
|
||||
const defaultFirstDayOfWeekName = getDefaultFirstDayOfWeek();
|
||||
let defaultFirstDayOfWeek = WeekDay.DefaultFirstDay.type;
|
||||
@@ -1933,10 +1973,12 @@ export function useI18n() {
|
||||
defaultFirstDayOfWeek = (WeekDay.parse(defaultFirstDayOfWeekName) as WeekDay).type;
|
||||
}
|
||||
|
||||
return {
|
||||
const localeDefaultSettings: LocaleDefaultSettings = {
|
||||
currency: defaultCurrency,
|
||||
firstDayOfWeek: defaultFirstDayOfWeek
|
||||
};
|
||||
|
||||
return localeDefaultSettings;
|
||||
}
|
||||
|
||||
function setTimeZone(timezone: string): void {
|
||||
@@ -1987,6 +2029,7 @@ export function useI18n() {
|
||||
getCurrentLanguageTag,
|
||||
getCurrentLanguageInfo,
|
||||
getCurrentLanguageDisplayName,
|
||||
getCurrentLanguageTextDirection,
|
||||
// get localization default type
|
||||
getDefaultCurrency,
|
||||
getDefaultFirstDayOfWeek,
|
||||
|
||||
@@ -11,12 +11,14 @@ import zhHans from './zh_Hans.json';
|
||||
import zhHant from './zh_Hant.json';
|
||||
import ptBR from './pt_BR.json';
|
||||
|
||||
import { TextDirection } from '@/core/text.ts';
|
||||
|
||||
export interface LanguageInfo {
|
||||
readonly name: string;
|
||||
readonly displayName: string;
|
||||
readonly alternativeLanguageTag: string;
|
||||
readonly aliases?: string[];
|
||||
readonly textDirection: TextDirection;
|
||||
readonly content: object;
|
||||
}
|
||||
|
||||
@@ -34,60 +36,70 @@ export const ALL_LANGUAGES: Record<string, LanguageInfo> = {
|
||||
name: 'German',
|
||||
displayName: 'Deutsch',
|
||||
alternativeLanguageTag: 'de-DE',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: de
|
||||
},
|
||||
'en': {
|
||||
name: 'English',
|
||||
displayName: 'English',
|
||||
alternativeLanguageTag: 'en-US',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: en
|
||||
},
|
||||
'es': {
|
||||
name: 'Spanish',
|
||||
displayName: 'Español',
|
||||
alternativeLanguageTag: 'es-ES',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: es
|
||||
},
|
||||
'it': {
|
||||
name: 'Italian',
|
||||
displayName: 'Italiano',
|
||||
alternativeLanguageTag: 'it-IT',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: it
|
||||
},
|
||||
'ja': {
|
||||
name: 'Japanese',
|
||||
displayName: '日本語',
|
||||
alternativeLanguageTag: 'ja-JP',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: ja
|
||||
},
|
||||
'nl': {
|
||||
name: 'Dutch',
|
||||
displayName: 'Nederlands',
|
||||
alternativeLanguageTag: 'nl-NL',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: nl
|
||||
},
|
||||
'pt-BR': {
|
||||
name: 'Portuguese (Brazil)',
|
||||
displayName: 'Português (Brasil)',
|
||||
alternativeLanguageTag: 'pt-BR',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: ptBR
|
||||
},
|
||||
'ru': {
|
||||
name: 'Russian',
|
||||
displayName: 'Русский',
|
||||
alternativeLanguageTag: 'ru-RU',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: ru
|
||||
},
|
||||
'uk': {
|
||||
name: 'Ukrainian',
|
||||
displayName: 'Українська',
|
||||
alternativeLanguageTag: 'uk-UA',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: uk
|
||||
},
|
||||
'vi': {
|
||||
name: 'Vietnamese',
|
||||
displayName: 'Tiếng Việt',
|
||||
alternativeLanguageTag: 'vi-VN',
|
||||
textDirection: TextDirection.LTR,
|
||||
content: vi
|
||||
},
|
||||
'zh-Hans': {
|
||||
@@ -95,6 +107,7 @@ export const ALL_LANGUAGES: Record<string, LanguageInfo> = {
|
||||
displayName: '中文 (简体)',
|
||||
alternativeLanguageTag: 'zh-CN',
|
||||
aliases: ['zh-CHS', 'zh-CN', 'zh-SG'],
|
||||
textDirection: TextDirection.LTR,
|
||||
content: zhHans
|
||||
},
|
||||
'zh-Hant': {
|
||||
@@ -102,6 +115,7 @@ export const ALL_LANGUAGES: Record<string, LanguageInfo> = {
|
||||
displayName: '中文 (繁體)',
|
||||
alternativeLanguageTag: 'zh-TW',
|
||||
aliases: ['zh-CHT', 'zh-TW', 'zh-HK', 'zh-MO'],
|
||||
textDirection: TextDirection.LTR,
|
||||
content: zhHant
|
||||
},
|
||||
};
|
||||
|
||||
@@ -40,8 +40,8 @@ input[type=number] {
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.text-right-sm {
|
||||
text-align: right !important;
|
||||
.text-end-sm {
|
||||
text-align: end !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ input[type=number] {
|
||||
|
||||
.chart-pointer {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
margin-inline-end: 5px;
|
||||
border-radius: 10px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
@@ -142,7 +142,11 @@ input[type=number] {
|
||||
}
|
||||
|
||||
.bidirectional-switch.v-input--horizontal .v-input__prepend {
|
||||
margin-right: 10px; /* same as the padding-left of `.v-switch .v-label` */
|
||||
margin-inline-end: 10px; /* same as the padding-left of `.v-switch .v-label` */
|
||||
}
|
||||
|
||||
html[dir="rtl"] .bidirectional-switch {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.code-container {
|
||||
@@ -276,6 +280,20 @@ input[type=number] {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .v-btn.button-icon-with-direction > .v-btn__content > .v-icon > .v-icon__svg,
|
||||
html[dir="rtl"] .v-btn.button-icon-with-direction > .v-btn__prepend > .v-icon > .v-icon__svg,
|
||||
html[dir="rtl"] .v-btn.button-icon-with-direction > .v-btn__append > .v-icon > .v-icon__svg {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
html[dir="rtl"] .v-icon.icon-with-direction > .v-icon__svg {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
html[dir="rtl"] .v-img.img-with-direction > img {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
/** Common class for replacing the default style of Materio **/
|
||||
.v-application,
|
||||
.text-body-1,
|
||||
@@ -415,3 +433,7 @@ body .v-btn-group {
|
||||
.dp__main .dp__calendar .dp__calendar_item > .dp__cell_inner {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .dp__main .dp__btn.dp--arrow-btn-nav {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="d-flex align-center">
|
||||
<span>{{ tt('global.app.title') }}</span>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" @click="refreshBrowserCache"
|
||||
class="ms-2" :icon="true" @click="refreshBrowserCache"
|
||||
v-if="!clientVersionMatchServerVersion">
|
||||
<v-icon :icon="mdiWebRefresh" size="24" />
|
||||
<v-tooltip activator="parent">{{ tt('Refresh Browser Cache') }}</v-tooltip>
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<v-row no-gutters class="auth-wrapper">
|
||||
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
|
||||
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
|
||||
<v-img src="img/desktop/background.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
|
||||
</div>
|
||||
<div class="d-flex auth-img-footer" v-if="isDarkMode">
|
||||
<v-img src="img/desktop/background-dark.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
|
||||
</div>
|
||||
<div class="d-flex align-center justify-center w-100 pt-10">
|
||||
<v-img max-width="600px" src="img/desktop/people4.svg"/>
|
||||
<v-img class="img-with-direction" max-width="600px" src="img/desktop/people4.svg"/>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
|
||||
@@ -45,14 +45,14 @@
|
||||
<v-col cols="12">
|
||||
<v-btn block type="submit" :disabled="!email || requesting" @click="requestResetPassword">
|
||||
{{ tt('Send Reset Link') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="requesting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="requesting"></v-progress-circular>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<router-link class="d-flex align-center justify-center" to="/login"
|
||||
:class="{ 'disabled': requesting }">
|
||||
<v-icon :icon="mdiChevronLeft"/>
|
||||
<v-icon class="icon-with-direction" :icon="mdiChevronLeft"/>
|
||||
<span>{{ tt('Back to login page') }}</span>
|
||||
</router-link>
|
||||
</v-col>
|
||||
@@ -99,12 +99,13 @@ import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { useRootStore } from '@/stores/index.ts';
|
||||
|
||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||
|
||||
import { getClientDisplayVersion } from '@/lib/version.ts';
|
||||
|
||||
import {
|
||||
mdiChevronLeft,
|
||||
mdiChevronLeft
|
||||
} from '@mdi/js';
|
||||
|
||||
type SnackBarType = InstanceType<typeof SnackBar>;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<span style="font-size: 1rem">{{ tt('Expense') }}</span>
|
||||
</div>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loadingOverview" @click="reload(true)">
|
||||
class="ms-2" :icon="true" :loading="loadingOverview" @click="reload(true)">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
@@ -24,19 +24,21 @@
|
||||
<h4 class="text-2xl font-weight-medium text-primary">
|
||||
<span v-if="!loadingOverview || (transactionOverview && transactionOverview.thisMonth && transactionOverview.thisMonth.valid)">{{ transactionOverview && transactionOverview.thisMonth ? getDisplayExpenseAmount(transactionOverview.thisMonth) : '-' }}</span>
|
||||
<v-skeleton-loader class="d-inline-block skeleton-no-margin mt-3 pb-1" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!transactionOverview || !transactionOverview.thisMonth || !transactionOverview.thisMonth.valid)"></v-skeleton-loader>
|
||||
<v-btn class="ml-1" density="compact" color="default" variant="text"
|
||||
<v-btn class="ms-1" density="compact" color="default" variant="text"
|
||||
:icon="true" @click="showAmountInHomePage = !showAmountInHomePage">
|
||||
<v-icon :icon="showAmountInHomePage ? mdiEyeOffOutline : mdiEyeOutline" size="20" />
|
||||
</v-btn>
|
||||
</h4>
|
||||
<div class="mt-1 mb-3">
|
||||
<span class="mr-2">{{ tt('Monthly income') }}</span>
|
||||
<span class="me-2">{{ tt('Monthly income') }}</span>
|
||||
<span v-if="!loadingOverview || (transactionOverview && transactionOverview.thisMonth && transactionOverview.thisMonth.valid)">{{ transactionOverview && transactionOverview.thisMonth ? getDisplayIncomeAmount(transactionOverview.thisMonth) : '-' }}</span>
|
||||
<v-skeleton-loader class="d-inline-block skeleton-no-margin mt-2" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!transactionOverview || !transactionOverview.thisMonth || !transactionOverview.thisMonth.valid)"></v-skeleton-loader>
|
||||
</div>
|
||||
<v-btn size="small" to="/transaction/list?dateType=7">{{ tt('View Details') }}</v-btn>
|
||||
<v-img class="overview-card-background" src="img/desktop/card-background.png"/>
|
||||
<v-img class="overview-card-background-image" width="116px" src="img/desktop/document.svg"/>
|
||||
<v-img class="overview-card-background img-with-direction"
|
||||
src="img/desktop/card-background.png"/>
|
||||
<v-img class="overview-card-background-image img-with-direction"
|
||||
width="116px" src="img/desktop/document.svg"/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<v-row no-gutters class="auth-wrapper">
|
||||
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
|
||||
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
|
||||
<v-img src="img/desktop/background.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
|
||||
</div>
|
||||
<div class="d-flex auth-img-footer" v-if="isDarkMode">
|
||||
<v-img src="img/desktop/background-dark.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
|
||||
</div>
|
||||
<div class="d-flex align-center justify-center w-100 pt-10">
|
||||
<v-img max-width="600px" src="img/desktop/people1.svg"/>
|
||||
<v-img class="img-with-direction" max-width="600px" src="img/desktop/people1.svg"/>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
|
||||
@@ -102,12 +102,12 @@
|
||||
<v-btn block :disabled="inputIsEmpty || logining || verifying"
|
||||
@click="login" v-if="!show2faInput">
|
||||
{{ tt('Log In') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="logining"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="logining"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn block :disabled="twoFAInputIsEmpty || logining || verifying"
|
||||
@click="verify" v-else-if="show2faInput">
|
||||
{{ tt('Continue') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="verifying"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="verifying"></v-progress-circular>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
|
||||
@@ -165,9 +165,10 @@ import { useLoginPageBase } from '@/views/base/LoginPageBase.ts';
|
||||
|
||||
import { useRootStore } from '@/stores/index.ts';
|
||||
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||
import { KnownErrorCode } from '@/consts/api.ts';
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
|
||||
import { isUserRegistrationEnabled, isUserForgetPasswordEnabled, isUserVerifyEmailEnabled } from '@/lib/server_settings.ts';
|
||||
|
||||
import {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<v-icon class="nav-item-icon" :icon="mdiListBoxOutline"/>
|
||||
<span class="nav-item-title d-inline-block">{{ tt('Transaction Details') }}</span>
|
||||
<v-btn density="compact" color="secondary" variant="text" size="22"
|
||||
class="ml-1" :icon="true" v-if="showAddTransactionButtonInDesktopNavbar"
|
||||
class="ms-1" :icon="true" v-if="showAddTransactionButtonInDesktopNavbar"
|
||||
@click="showAddDialogInTransactionListPage">
|
||||
<v-icon :icon="mdiPlusCircle" size="22" />
|
||||
<v-tooltip activator="parent">{{ tt('Add Transaction') }}</v-tooltip>
|
||||
@@ -109,7 +109,7 @@
|
||||
<div class="layout-navbar navbar-blur">
|
||||
<div class="navbar-content-container">
|
||||
<div class="d-flex h-100 align-center">
|
||||
<v-btn class="ms-n3 mr-2 d-lg-none" color="default" variant="text"
|
||||
<v-btn class="ms-n3 me-2 d-lg-none" color="default" variant="text"
|
||||
:icon="true" @click="showVerticalOverlayMenu = true">
|
||||
<v-icon :icon="mdiMenu" size="24" />
|
||||
</v-btn>
|
||||
@@ -152,7 +152,7 @@
|
||||
</v-avatar>
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
<v-list-item-title class="ml-2 font-weight-semibold">
|
||||
<v-list-item-title class="ms-2 font-weight-semibold">
|
||||
{{ currentNickName }}
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<v-row no-gutters class="auth-wrapper">
|
||||
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
|
||||
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
|
||||
<v-img src="img/desktop/background.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
|
||||
</div>
|
||||
<div class="d-flex auth-img-footer" v-if="isDarkMode">
|
||||
<v-img src="img/desktop/background-dark.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
|
||||
</div>
|
||||
<div class="d-flex align-center justify-center w-100 pt-10">
|
||||
<v-img max-width="600px" src="img/desktop/people4.svg"/>
|
||||
<v-img class="img-with-direction" max-width="600px" src="img/desktop/people4.svg"/>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
|
||||
@@ -70,14 +70,14 @@
|
||||
<v-col cols="12">
|
||||
<v-btn block :disabled="!email || !newPassword || !confirmPassword || updating" @click="resetPassword">
|
||||
{{ tt('Update Password') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="updating"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="updating"></v-progress-circular>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<router-link class="d-flex align-center justify-center" to="/login"
|
||||
:class="{ 'disabled': updating }">
|
||||
<v-icon :icon="mdiChevronLeft"/>
|
||||
<v-icon class="icon-with-direction" :icon="mdiChevronLeft"/>
|
||||
<span>{{ tt('Back to login page') }}</span>
|
||||
</router-link>
|
||||
</v-col>
|
||||
@@ -128,8 +128,9 @@ import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { useRootStore } from '@/stores/index.ts';
|
||||
|
||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||
|
||||
import { getClientDisplayVersion } from '@/lib/version.ts';
|
||||
|
||||
import {
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<v-row no-gutters class="auth-wrapper">
|
||||
<v-col cols="12" md="4" class="d-none d-md-flex align-center justify-center position-relative">
|
||||
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
|
||||
<v-img src="img/desktop/background.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
|
||||
</div>
|
||||
<div class="d-flex auth-img-footer" v-if="isDarkMode">
|
||||
<v-img src="img/desktop/background-dark.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
|
||||
</div>
|
||||
<div class="d-flex align-center justify-center w-100 pt-10">
|
||||
<v-img max-width="320px" src="img/desktop/people2.svg"/>
|
||||
<v-img class="img-with-direction" max-width="320px" src="img/desktop/people2.svg"/>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col cols="12" md="8" class="auth-card d-flex align-center justify-center pa-10">
|
||||
@@ -28,7 +28,7 @@
|
||||
<h4 class="text-h4 mb-1">{{ tt('Basic Information') }}</h4>
|
||||
<p class="text-sm mt-2 mb-5">
|
||||
<span>{{ tt('Already have an account?') }}</span>
|
||||
<router-link class="ml-1" to="/login">{{ tt('Click here to log in') }}</router-link>
|
||||
<router-link class="ms-1" to="/login">{{ tt('Click here to log in') }}</router-link>
|
||||
</p>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
@@ -129,7 +129,7 @@
|
||||
:label="tt('Use Preset Transaction Categories')"
|
||||
v-model="usePresetCategories"/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="6" class="text-right-sm">
|
||||
<v-col cols="12" sm="6" class="text-end-sm">
|
||||
<language-select-button :disabled="submitting || navigateToHomePage"
|
||||
:use-model-value="true" v-model="currentLocale" />
|
||||
</v-col>
|
||||
@@ -144,7 +144,7 @@
|
||||
<v-expansion-panel :key="idx" v-for="(category, idx) in categories">
|
||||
<v-expansion-panel-title class="py-0">
|
||||
<ItemIcon icon-type="category" :icon-id="category.icon" :color="category.color"></ItemIcon>
|
||||
<span class="ml-3">{{ category.name }}</span>
|
||||
<span class="ms-3">{{ category.name }}</span>
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text v-if="category.subCategories.length">
|
||||
<v-list rounded density="comfortable" class="pa-0">
|
||||
@@ -154,7 +154,7 @@
|
||||
<template #prepend>
|
||||
<ItemIcon icon-type="category" :icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
|
||||
</template>
|
||||
<span class="ml-3">{{ subCategory.name }}</span>
|
||||
<span class="ms-3">{{ subCategory.name }}</span>
|
||||
</v-list-item>
|
||||
<v-divider v-if="subIdx !== category.subCategories.length - 1"/>
|
||||
</template>
|
||||
@@ -175,11 +175,12 @@
|
||||
</v-window>
|
||||
|
||||
<div class="d-flex justify-sm-space-between gap-4 flex-wrap justify-center mt-5">
|
||||
<v-btn :color="(currentStep === 'basicSetting' || currentStep === 'finalResult') ? 'default' : 'primary'"
|
||||
<v-btn class="button-icon-with-direction"
|
||||
:color="(currentStep === 'basicSetting' || currentStep === 'finalResult') ? 'default' : 'primary'"
|
||||
:disabled="currentStep === 'basicSetting' || currentStep === 'finalResult' || submitting || navigateToHomePage"
|
||||
:prepend-icon="mdiArrowLeft"
|
||||
@click="switchToPreviousTab">{{ tt('Previous') }}</v-btn>
|
||||
<v-btn color="primary"
|
||||
<v-btn class="button-icon-with-direction" color="primary"
|
||||
:disabled="submitting || navigateToHomePage"
|
||||
:append-icon="mdiArrowRight"
|
||||
@click="switchToNextTab"
|
||||
@@ -190,9 +191,10 @@
|
||||
@click="submit"
|
||||
v-if="currentStep === 'presetCategories'">
|
||||
{{ tt('Submit') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn :append-icon="mdiArrowRight"
|
||||
<v-btn class="button-icon-with-direction"
|
||||
:append-icon="mdiArrowRight"
|
||||
@click="navigateToLogin"
|
||||
v-if="currentStep === 'finalResult'">{{ tt('Continue') }}</v-btn>
|
||||
</div>
|
||||
@@ -385,6 +387,7 @@ function onSnackbarShowStateChanged(newValue: boolean): void {
|
||||
|
||||
<style>
|
||||
.signup-preset-categories .v-expansion-panel-text__wrapper {
|
||||
padding: 0 0 0 20px;
|
||||
padding: 0 0 0 0;
|
||||
padding-inline-start: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<v-row no-gutters class="auth-wrapper">
|
||||
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
|
||||
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
|
||||
<v-img src="img/desktop/background.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
|
||||
</div>
|
||||
<div class="d-flex auth-img-footer" v-if="isDarkMode">
|
||||
<v-img src="img/desktop/background-dark.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
|
||||
</div>
|
||||
<div class="d-flex align-center justify-center w-100 pt-10">
|
||||
<v-img max-width="600px" src="img/desktop/people3.svg"/>
|
||||
<v-img class="img-with-direction" max-width="600px" src="img/desktop/people3.svg"/>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
|
||||
@@ -47,7 +47,7 @@
|
||||
<v-btn block variant="tonal" :disabled="verifyingByWebAuthn"
|
||||
@click="unlockByWebAuthn">
|
||||
{{ tt('Unlock with WebAuthn') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="verifyingByWebAuthn"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="verifyingByWebAuthn"></v-progress-circular>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
|
||||
@@ -105,8 +105,9 @@ import { useUnlockPageBase } from '@/views/base/UnlockPageBase.ts';
|
||||
import { useSettingsStore } from '@/stores/setting.ts';
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
|
||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||
|
||||
import {
|
||||
isWebAuthnSupported,
|
||||
verifyWebAuthnCredential
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<v-row no-gutters class="auth-wrapper">
|
||||
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
|
||||
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
|
||||
<v-img src="img/desktop/background.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
|
||||
</div>
|
||||
<div class="d-flex auth-img-footer" v-if="isDarkMode">
|
||||
<v-img src="img/desktop/background-dark.svg"/>
|
||||
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
|
||||
</div>
|
||||
<div class="d-flex align-center justify-center w-100 pt-10">
|
||||
<v-img max-width="320px" src="img/desktop/people2.svg"/>
|
||||
<v-img class="img-with-direction" max-width="320px" src="img/desktop/people2.svg"/>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
|
||||
@@ -48,14 +48,14 @@
|
||||
<v-col cols="12" v-if="!loading && !token && email && isUserVerifyEmailEnabled()">
|
||||
<v-btn block type="submit" :disabled="loading || resending || !password" @click="resendEmail">
|
||||
{{ tt('Resend Validation Email') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="resending"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="resending"></v-progress-circular>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<router-link class="d-flex align-center justify-center" :to="verified ? '/' : '/login'"
|
||||
:class="{ 'disabled': loading || resending }">
|
||||
<v-icon :icon="mdiChevronLeft"/>
|
||||
<v-icon class="icon-with-direction" :icon="mdiChevronLeft"/>
|
||||
<span v-if="!verified">{{ tt('Back to login page') }}</span>
|
||||
<span v-else-if="verified">{{ tt('Back to home page') }}</span>
|
||||
</router-link>
|
||||
@@ -106,8 +106,9 @@ import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { useRootStore } from '@/stores/index.ts';
|
||||
|
||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||
|
||||
import { isUserVerifyEmailEnabled } from '@/lib/server_settings.ts';
|
||||
import { isUserLogined } from '@/lib/userstate.ts';
|
||||
import { getClientDisplayVersion } from '@/lib/version.ts';
|
||||
|
||||
@@ -33,13 +33,13 @@
|
||||
<v-tab class="tab-text-truncate" :key="accountCategory.type" :value="accountCategory.type"
|
||||
v-for="accountCategory in AccountCategory.values()">
|
||||
<ItemIcon icon-type="account" :icon-id="accountCategory.defaultAccountIconId" />
|
||||
<div class="d-flex flex-column text-truncate ml-2">
|
||||
<small class="text-truncate text-left smaller" v-if="!loading || allAccountCount > 0">{{ accountCategoryTotalBalance(accountCategory) }}</small>
|
||||
<small class="text-truncate text-left smaller my-1" v-else-if="loading && allAccountCount <= 0">
|
||||
<div class="d-flex flex-column text-truncate ms-2">
|
||||
<small class="text-truncate text-start smaller" v-if="!loading || allAccountCount > 0">{{ accountCategoryTotalBalance(accountCategory) }}</small>
|
||||
<small class="text-truncate text-start smaller my-1" v-else-if="loading && allAccountCount <= 0">
|
||||
<v-skeleton-loader class="skeleton-no-margin"
|
||||
width="100px" height="16" type="text" :loading="true"></v-skeleton-loader>
|
||||
</small>
|
||||
<span class="text-truncate text-left">{{ tt(accountCategory.name) }}</span>
|
||||
<span class="text-truncate text-start">{{ tt(accountCategory.name) }}</span>
|
||||
</div>
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
@@ -50,18 +50,18 @@
|
||||
<v-card variant="flat" min-height="780">
|
||||
<template #title>
|
||||
<div class="title-and-toolbar d-flex align-center">
|
||||
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
:ripple="false" :icon="true" @click="showNav = !showNav">
|
||||
<v-icon :icon="mdiMenu" size="24" />
|
||||
</v-btn>
|
||||
<span>{{ tt('Account List') }}</span>
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
:disabled="loading" @click="add">{{ tt('Add') }}</v-btn>
|
||||
<v-btn class="ml-3" color="primary" variant="tonal"
|
||||
<v-btn class="ms-3" color="primary" variant="tonal"
|
||||
:disabled="loading" @click="saveSortResult"
|
||||
v-if="displayOrderModified">{{ tt('Save Display Order') }}</v-btn>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loading" @click="reload(true)">
|
||||
class="ms-2" :icon="true" :loading="loading" @click="reload(true)">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
@@ -69,7 +69,7 @@
|
||||
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -92,9 +92,9 @@
|
||||
|
||||
<v-card-text class="accounts-overview-title text-truncate pt-0">
|
||||
<span class="accounts-overview-subtitle">{{ activeAccountCategory?.isLiability ? tt('Outstanding Balance') : tt('Balance') }}</span>
|
||||
<v-skeleton-loader class="skeleton-no-margin ml-3 mb-2" width="120px" type="text" :loading="true" v-if="loading && activeAccountCategory && !hasAccount(activeAccountCategory)"></v-skeleton-loader>
|
||||
<span class="accounts-overview-amount ml-3" v-else-if="!loading || !activeAccountCategory || hasAccount(activeAccountCategory)">{{ activeAccountCategoryTotalBalance }}</span>
|
||||
<v-btn class="ml-2" density="compact" color="default" variant="text"
|
||||
<v-skeleton-loader class="skeleton-no-margin ms-3 mb-2" width="120px" type="text" :loading="true" v-if="loading && activeAccountCategory && !hasAccount(activeAccountCategory)"></v-skeleton-loader>
|
||||
<span class="accounts-overview-amount ms-3" v-else-if="!loading || !activeAccountCategory || hasAccount(activeAccountCategory)">{{ activeAccountCategoryTotalBalance }}</span>
|
||||
<v-btn class="ms-2" density="compact" color="default" variant="text"
|
||||
:icon="true" :disabled="loading"
|
||||
@click="showAccountBalance = !showAccountBalance">
|
||||
<v-icon :icon="showAccountBalance ? mdiEyeOffOutline : mdiEyeOutline" size="20" />
|
||||
@@ -102,13 +102,13 @@
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
|
||||
<v-row class="pl-6 pr-6 pr-md-8" v-if="loading && activeAccountCategory && !hasAccount(activeAccountCategory)">
|
||||
<v-row class="ps-6 pe-6 pe-md-8" v-if="loading && activeAccountCategory && !hasAccount(activeAccountCategory)">
|
||||
<v-col cols="12">
|
||||
<v-card border class="card-title-with-bg account-card mb-8 h-auto">
|
||||
<template #title>
|
||||
<div class="account-title d-flex align-center">
|
||||
<v-icon class="disabled mr-0" size="28px" :icon="mdiSquareRounded" />
|
||||
<span class="account-name text-truncate ml-2">
|
||||
<v-icon class="disabled me-0" size="28px" :icon="mdiSquareRounded" />
|
||||
<span class="account-name text-truncate ms-2">
|
||||
<v-skeleton-loader class="skeleton-no-margin my-1"
|
||||
width="120px" type="text" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
@@ -126,7 +126,7 @@
|
||||
{{ tt('Transaction List') }}
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<span class="account-balance ml-2">
|
||||
<span class="account-balance ms-2">
|
||||
<v-skeleton-loader class="skeleton-no-margin"
|
||||
width="100px" type="text" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
@@ -136,13 +136,13 @@
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row class="pl-5 pr-2 pr-md-4" v-if="!loading && activeAccountCategory && !hasAccount(activeAccountCategory)">
|
||||
<v-row class="ps-5 pe-2 pe-md-4" v-if="!loading && activeAccountCategory && !hasAccount(activeAccountCategory)">
|
||||
<v-col cols="12">
|
||||
{{ tt('No available account') }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row class="pl-6 pr-6 pr-md-8">
|
||||
<v-row class="ps-6 pe-6 pe-md-8">
|
||||
<v-col cols="12">
|
||||
<draggable-list
|
||||
class="list-group"
|
||||
@@ -161,8 +161,8 @@
|
||||
<div class="account-title d-flex align-baseline">
|
||||
<ItemIcon size="1.5rem" icon-type="account" :icon-id="element.icon"
|
||||
:color="element.color" :hidden-status="element.hidden" />
|
||||
<span class="account-name text-truncate ml-2">{{ element.name }}</span>
|
||||
<small class="account-currency text-truncate ml-2">
|
||||
<span class="account-name text-truncate ms-2">{{ element.name }}</span>
|
||||
<small class="account-currency text-truncate ms-2">
|
||||
{{ accountCurrency(element) }}
|
||||
</small>
|
||||
<v-spacer/>
|
||||
@@ -192,7 +192,7 @@
|
||||
v-show="showHidden || !subAccount.hidden">
|
||||
<ItemIcon size="1.5rem" icon-type="account" :icon-id="subAccount.icon"
|
||||
:color="subAccount.color" :hidden-status="subAccount.hidden" />
|
||||
<span class="ml-2">{{ subAccount.name }}</span>
|
||||
<span class="ms-2">{{ subAccount.name }}</span>
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
</div>
|
||||
@@ -211,7 +211,7 @@
|
||||
:to="`/transaction/list?accountIds=${element.getAccountOrSubAccountId(activeSubAccount[element.id])}`">
|
||||
{{ tt('Transaction List') }}
|
||||
</v-btn>
|
||||
<v-btn class="px-2 ml-1" density="comfortable" color="default" variant="text"
|
||||
<v-btn class="px-2 ms-1" density="comfortable" color="default" variant="text"
|
||||
:disabled="loading" :prepend-icon="mdiInvoiceListOutline"
|
||||
@click="showReconciliationStatementCustomDateRangeDialog(element.getAccountOrSubAccount(activeSubAccount[element.id]))"
|
||||
v-if="element.type === AccountType.SingleAccount.type || element.getSubAccount(activeSubAccount[element.id])">
|
||||
@@ -225,7 +225,7 @@
|
||||
<v-list-item-title class="cursor-pointer"
|
||||
@click="showReconciliationStatementCustomDateRangeDialog(element.getAccountOrSubAccount(activeSubAccount[element.id]), dateRange.type)">
|
||||
<div class="d-flex align-center">
|
||||
<span class="text-sm ml-3">{{ dateRange.displayName }}</span>
|
||||
<span class="text-sm ms-3">{{ dateRange.displayName }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -233,7 +233,7 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn class="px-2 ml-1" density="comfortable" color="default" variant="text"
|
||||
<v-btn class="px-2 ms-1" density="comfortable" color="default" variant="text"
|
||||
:class="{ 'd-none': loading, 'hover-display': !loading }"
|
||||
:disabled="loading"
|
||||
:prepend-icon="element.isAccountOrSubAccountHidden(activeSubAccount[element.id]) ? mdiEyeOutline : mdiEyeOffOutline"
|
||||
@@ -241,14 +241,14 @@
|
||||
@click="hide(element, element.getAccountOrSubAccount(activeSubAccount[element.id]), !element.isAccountOrSubAccountHidden(activeSubAccount[element.id]))">
|
||||
{{ element.isAccountOrSubAccountHidden(activeSubAccount[element.id]) ? tt('Show') : tt('Hide') }}
|
||||
</v-btn>
|
||||
<v-btn class="px-2 ml-1" density="comfortable" color="default" variant="text"
|
||||
<v-btn class="px-2 ms-1" density="comfortable" color="default" variant="text"
|
||||
:class="{ 'd-none': loading, 'hover-display': !loading }"
|
||||
:disabled="loading" :prepend-icon="mdiPencilOutline"
|
||||
v-if="!activeSubAccount[element.id] || element.getSubAccount(activeSubAccount[element.id])"
|
||||
@click="edit(element)">
|
||||
{{ tt('Edit') }}
|
||||
</v-btn>
|
||||
<v-btn class="px-2 ml-1" density="comfortable" color="default" variant="text"
|
||||
<v-btn class="px-2 ms-1" density="comfortable" color="default" variant="text"
|
||||
:class="{ 'd-none': loading, 'hover-display': !loading }"
|
||||
:disabled="loading" :prepend-icon="mdiDeleteOutline"
|
||||
v-if="!activeSubAccount[element.id] || element.getSubAccount(activeSubAccount[element.id])"
|
||||
@@ -256,7 +256,7 @@
|
||||
{{ tt('Delete') }}
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<span class="account-balance ml-2">{{ accountBalance(element, activeSubAccount[element.id]) }}</span>
|
||||
<span class="account-balance ms-2">{{ accountBalance(element, activeSubAccount[element.id]) }}</span>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<div class="d-flex align-center justify-center">
|
||||
<div class="d-flex w-100 align-center justify-center">
|
||||
<h4 class="text-h4">{{ tt(title) }}</h4>
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="loading"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="loading"></v-progress-circular>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2" :icon="true"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2" :icon="true"
|
||||
:disabled="loading || submitting || account.type !== AccountType.MultiSubAccounts.type">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -29,7 +29,7 @@
|
||||
<template v-if="account.type === AccountType.MultiSubAccounts.type">
|
||||
<v-tab :key="idx" :value="idx" v-for="(subAccount, idx) in subAccounts">
|
||||
<span>{{ tt('Sub Account') + ' #' + (idx + 1) }}</span>
|
||||
<v-btn class="ml-2" color="error" size="24" variant="text"
|
||||
<v-btn class="ms-2" color="error" size="24" variant="text"
|
||||
:icon="mdiDeleteOutline"
|
||||
@click="removeSubAccount(subAccount)"></v-btn>
|
||||
</v-tab>
|
||||
@@ -38,7 +38,7 @@
|
||||
</div>
|
||||
|
||||
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container"
|
||||
:class="{ 'ml-md-5': account.type === AccountType.MultiSubAccounts.type }"
|
||||
:class="{ 'ms-md-5': account.type === AccountType.MultiSubAccounts.type }"
|
||||
v-model="activeTab">
|
||||
<v-window-item value="account">
|
||||
<v-form class="mt-2">
|
||||
@@ -63,7 +63,7 @@
|
||||
<ItemIcon icon-type="account"
|
||||
:icon-id="item.raw.defaultAccountIconId"
|
||||
v-if="item.raw" />
|
||||
<span class="ml-2">{{ item.title }}</span>
|
||||
<span class="ms-2">{{ item.title }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</template>
|
||||
@@ -174,7 +174,7 @@
|
||||
<div v-bind="props" class="d-inline-block">
|
||||
<v-btn :disabled="inputIsEmpty || loading || submitting" @click="save">
|
||||
{{ tt(saveButtonTitle) }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="d-flex w-100 align-center justify-center">
|
||||
<h4 class="text-h4">{{ tt('Reconciliation Statement') }}</h4>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loading" @click="reload(true)">
|
||||
class="ms-2" :icon="true" :loading="loading" @click="reload(true)">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
@@ -14,7 +14,7 @@
|
||||
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:icon="true" :disabled="loading"
|
||||
v-if="showAccountBalanceTrendsCharts">
|
||||
<v-icon :icon="mdiTuneVertical" />
|
||||
@@ -42,7 +42,7 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:icon="true" :disabled="loading">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -94,42 +94,42 @@
|
||||
|
||||
<div class="d-flex align-center mb-4">
|
||||
<div class="d-flex align-center text-body-1">
|
||||
<span class="ml-2">{{ tt('Opening Balance') }}</span>
|
||||
<span class="ms-2">{{ tt('Opening Balance') }}</span>
|
||||
<span class="text-primary" v-if="loading">
|
||||
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
<span class="text-primary ml-2" v-else-if="!loading">
|
||||
<span class="text-primary ms-2" v-else-if="!loading">
|
||||
{{ displayOpeningBalance }}
|
||||
</span>
|
||||
<span class="ml-3">{{ tt('Closing Balance') }}</span>
|
||||
<span class="ms-3">{{ tt('Closing Balance') }}</span>
|
||||
<span class="text-primary" v-if="loading">
|
||||
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
<span class="text-primary ml-2" v-else-if="!loading">
|
||||
<span class="text-primary ms-2" v-else-if="!loading">
|
||||
{{ displayClosingBalance }}
|
||||
</span>
|
||||
</div>
|
||||
<v-spacer/>
|
||||
<div class="d-flex align-center text-body-1">
|
||||
<span class="ml-2">{{ tt('Total Inflows') }}</span>
|
||||
<span class="ms-2">{{ tt('Total Inflows') }}</span>
|
||||
<span class="text-income" v-if="loading">
|
||||
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
<span class="text-income ml-2" v-else-if="!loading">
|
||||
<span class="text-income ms-2" v-else-if="!loading">
|
||||
{{ displayTotalInflows }}
|
||||
</span>
|
||||
<span class="ml-3">{{ tt('Total Outflows') }}</span>
|
||||
<span class="ms-3">{{ tt('Total Outflows') }}</span>
|
||||
<span class="text-expense" v-if="loading">
|
||||
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
<span class="text-expense ml-2" v-else-if="!loading">
|
||||
<span class="text-expense ms-2" v-else-if="!loading">
|
||||
{{ displayTotalOutflows }}
|
||||
</span>
|
||||
<span class="ml-3">{{ tt('Net Cash Flow') }}</span>
|
||||
<span class="ms-3">{{ tt('Net Cash Flow') }}</span>
|
||||
<span class="text-primary" v-if="loading">
|
||||
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
<span class="text-primary ml-2" v-else-if="!loading">
|
||||
<span class="text-primary ms-2" v-else-if="!loading">
|
||||
{{ displayTotalBalance }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -151,7 +151,7 @@
|
||||
>
|
||||
<template #item.time="{ item }">
|
||||
<span>{{ getDisplayDateTime(item) }}</span>
|
||||
<v-chip class="ml-1" variant="flat" color="secondary" size="x-small"
|
||||
<v-chip class="ms-1" variant="flat" color="secondary" size="x-small"
|
||||
v-if="item.utcOffset !== currentTimezoneOffsetMinutes">{{ getDisplayTimezone(item) }}</v-chip>
|
||||
</template>
|
||||
<template #item.type="{ item }">
|
||||
@@ -166,23 +166,23 @@
|
||||
:color="allCategoriesMap[item.categoryId].color"
|
||||
v-if="allCategoriesMap[item.categoryId] && allCategoriesMap[item.categoryId]?.color"></ItemIcon>
|
||||
<v-icon size="24" :icon="mdiPencilBoxOutline" v-else-if="!allCategoriesMap[item.categoryId] || !allCategoriesMap[item.categoryId]?.color" />
|
||||
<span class="ml-2" v-if="item.type === TransactionType.ModifyBalance">
|
||||
<span class="ms-2" v-if="item.type === TransactionType.ModifyBalance">
|
||||
{{ tt('Modify Balance') }}
|
||||
</span>
|
||||
<span class="ml-2" v-else-if="item.type !== TransactionType.ModifyBalance && allCategoriesMap[item.categoryId]">
|
||||
<span class="ms-2" v-else-if="item.type !== TransactionType.ModifyBalance && allCategoriesMap[item.categoryId]">
|
||||
{{ allCategoriesMap[item.categoryId].name }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #item.sourceAmount="{ item }">
|
||||
<span :class="{ 'text-expense': item.type === TransactionType.Expense, 'text-income': item.type === TransactionType.Income }">{{ getDisplaySourceAmount(item) }}</span>
|
||||
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId && getDisplaySourceAmount(item) !== getDisplayDestinationAmount(item)"></v-icon>
|
||||
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId && getDisplaySourceAmount(item) !== getDisplayDestinationAmount(item)"></v-icon>
|
||||
<span v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId && getDisplaySourceAmount(item) !== getDisplayDestinationAmount(item)">{{ getDisplayDestinationAmount(item) }}</span>
|
||||
</template>
|
||||
<template #item.sourceAccountId="{ item }">
|
||||
<div class="d-flex align-center">
|
||||
<span v-if="item.sourceAccountId && allAccountsMap[item.sourceAccountId]">{{ allAccountsMap[item.sourceAccountId].name }}</span>
|
||||
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
|
||||
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
|
||||
<span v-if="item.type === TransactionType.Transfer && item.destinationAccountId && allAccountsMap[item.destinationAccountId]">{{ allAccountsMap[item.destinationAccountId].name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -197,18 +197,18 @@
|
||||
</template>
|
||||
<template #bottom>
|
||||
<div class="title-and-toolbar d-flex align-center text-no-wrap mt-2" v-if="loading || (reconciliationStatements && reconciliationStatements.transactions && reconciliationStatements.transactions.length)">
|
||||
<span class="ml-2">{{ tt('Total Transactions') }}</span>
|
||||
<span class="ms-2">{{ tt('Total Transactions') }}</span>
|
||||
<span v-if="loading">
|
||||
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
<span class="ml-2" v-else-if="!loading">
|
||||
<span class="ms-2" v-else-if="!loading">
|
||||
{{ formatNumberToLocalizedNumerals(reconciliationStatements?.transactions.length ?? 0) }}
|
||||
</span>
|
||||
<v-spacer/>
|
||||
<span v-if="reconciliationStatements && reconciliationStatements.transactions && reconciliationStatements.transactions.length > 10">
|
||||
{{ tt('Transactions Per Page') }}
|
||||
</span>
|
||||
<v-select class="ml-2" density="compact" max-width="100"
|
||||
<v-select class="ms-2" density="compact" max-width="100"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
:disabled="loading"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<v-card>
|
||||
<template #title>
|
||||
<span>{{ tt('Settings Sync') }}</span>
|
||||
<v-progress-circular indeterminate size="20" class="ml-3" v-if="loading"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="20" class="ms-3" v-if="loading"></v-progress-circular>
|
||||
</template>
|
||||
|
||||
<v-card-text class="pb-0">
|
||||
@@ -28,7 +28,7 @@
|
||||
<div class="w-100">
|
||||
<span>{{ tt('Synchronized Settings') }}</span>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading || enabling || disabling" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
<v-divider/>
|
||||
|
||||
<v-list rounded density="comfortable" class="pa-0 ml-4">
|
||||
<v-list rounded density="comfortable" class="pa-0 ms-4">
|
||||
<template :key="settingItem.settingKey"
|
||||
v-for="(settingItem, itemIdx) in categorizedItems.items">
|
||||
<v-divider v-if="itemIdx > 0"/>
|
||||
@@ -85,8 +85,8 @@
|
||||
@update:model-value="enabledApplicationCloudSettings[settingItem.settingKey] = !!$event">
|
||||
<template #label>
|
||||
<span>{{ tt(settingItem.settingName) }}</span>
|
||||
<v-icon class="ml-2 mr-0" start size="16" :icon="mdiCellphone" v-if="settingItem.mobile"/>
|
||||
<v-icon class="ml-2 mr-0" start size="16" :icon="mdiMonitor" v-if="settingItem.desktop"/>
|
||||
<v-icon class="ms-2 me-0" start size="16" :icon="mdiCellphone" v-if="settingItem.mobile"/>
|
||||
<v-icon class="ms-2 me-0" start size="16" :icon="mdiMonitor" v-if="settingItem.desktop"/>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</template>
|
||||
@@ -105,15 +105,15 @@
|
||||
<v-col cols="12" class="d-flex flex-wrap gap-4">
|
||||
<v-btn :disabled="loading || enabling || disabling || !hasEnabledApplicationCloudSettings" v-if="!isEnableCloudSync" @click="enable(false)">
|
||||
{{ tt('Enable Settings Sync') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="enabling"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="enabling"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn :disabled="loading || enabling || disabling || !hasEnabledApplicationCloudSettings" v-if="isEnableCloudSync" @click="enable(true)">
|
||||
{{ tt('Update Synchronized Settings') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="enabling"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="enabling"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn :disabled="loading || enabling || disabling" v-if="isEnableCloudSync" @click="disable">
|
||||
{{ tt('Disable Settings Sync') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="disabling"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="disabling"></v-progress-circular>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
@@ -35,18 +35,18 @@
|
||||
<v-card variant="flat" :min-height="cardMinHeight">
|
||||
<template #title>
|
||||
<div class="title-and-toolbar d-flex align-center">
|
||||
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
:ripple="false" :icon="true" @click="showNav = !showNav">
|
||||
<v-icon :icon="mdiMenu" size="24" />
|
||||
</v-btn>
|
||||
<span>{{ tt('Transaction Categories') }}</span>
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
:disabled="loading || updating" @click="add">{{ tt('Add') }}</v-btn>
|
||||
<v-btn class="ml-3" color="primary" variant="tonal"
|
||||
<v-btn class="ms-3" color="primary" variant="tonal"
|
||||
:disabled="loading || updating" @click="saveSortResult"
|
||||
v-if="displayOrderModified">{{ tt('Save Display Order') }}</v-btn>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loading || updating" @click="reload(true)">
|
||||
class="ms-2" :icon="true" :loading="loading || updating" @click="reload(true)">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
@@ -54,7 +54,7 @@
|
||||
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading || updating" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -97,7 +97,7 @@
|
||||
<td>
|
||||
<div class="d-flex align-center">
|
||||
<span>{{ tt('No available category') }}</span>
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
@click="showPresetDialog = true"
|
||||
v-if="hasSubCategories && noCategory">
|
||||
{{ tt('Add Default Categories') }}
|
||||
@@ -124,14 +124,14 @@
|
||||
:icon-id="element.icon" :color="element.color"
|
||||
:hidden-status="element.hidden" />
|
||||
<div class="d-flex flex-column py-2">
|
||||
<span class="ml-2">{{ element.name }}</span>
|
||||
<span class="transaction-category-comment ml-2">{{ element.comment }}</span>
|
||||
<span class="ms-2">{{ element.name }}</span>
|
||||
<span class="transaction-category-comment ms-2">{{ element.comment }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-spacer/>
|
||||
|
||||
<v-btn class="px-2 ml-2" color="default"
|
||||
<v-btn class="px-2 ms-2" color="default"
|
||||
density="comfortable" variant="text"
|
||||
:class="{ 'd-none': loading, 'hover-display': !loading }"
|
||||
:prepend-icon="element.hidden ? mdiEyeOutline : mdiEyeOffOutline"
|
||||
@@ -163,7 +163,7 @@
|
||||
</template>
|
||||
{{ tt('Delete') }}
|
||||
</v-btn>
|
||||
<span class="ml-2">
|
||||
<span class="ms-2">
|
||||
<v-icon :class="!loading && !updating && availableCategoryCount > 1 ? 'drag-handle' : 'disabled'"
|
||||
:icon="mdiDrag"/>
|
||||
<v-tooltip activator="parent" v-if="!loading && !updating && availableCategoryCount > 1">{{ tt('Drag to Reorder') }}</v-tooltip>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<template #title>
|
||||
<div class="d-flex align-center justify-center">
|
||||
<h4 class="text-h4">{{ tt(title) }}</h4>
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="loading"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="loading"></v-progress-circular>
|
||||
</div>
|
||||
</template>
|
||||
<v-card-text class="pt-0">
|
||||
@@ -35,7 +35,7 @@
|
||||
<template #item="{ props, item }">
|
||||
<v-list-item v-bind="props">
|
||||
<template #prepend>
|
||||
<ItemIcon class="mr-2" icon-type="category"
|
||||
<ItemIcon class="me-2" icon-type="category"
|
||||
:icon-id="item.raw.icon" :color="item.raw.color"></ItemIcon>
|
||||
</template>
|
||||
<template #title>
|
||||
@@ -84,7 +84,7 @@
|
||||
<div v-bind="props" class="d-inline-block">
|
||||
<v-btn :disabled="inputIsEmpty || loading || submitting" @click="save">
|
||||
{{ tt(saveButtonTitle) }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<v-expansion-panel :key="idx" v-for="(category, idx) in categories">
|
||||
<v-expansion-panel-title class="py-0">
|
||||
<ItemIcon icon-type="category" :icon-id="category.icon" :color="category.color"></ItemIcon>
|
||||
<span class="ml-3">{{ category.name }}</span>
|
||||
<span class="ms-3">{{ category.name }}</span>
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text v-if="category.subCategories.length">
|
||||
<v-list rounded density="comfortable" class="pa-0">
|
||||
@@ -29,7 +29,7 @@
|
||||
<template #prepend>
|
||||
<ItemIcon icon-type="category" :icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
|
||||
</template>
|
||||
<span class="ml-3">{{ subCategory.name }}</span>
|
||||
<span class="ms-3">{{ subCategory.name }}</span>
|
||||
</v-list-item>
|
||||
<v-divider v-if="subIdx !== category.subCategories.length - 1"/>
|
||||
</template>
|
||||
@@ -43,7 +43,7 @@
|
||||
<div class="w-100 d-flex justify-center mt-2 mt-sm-4 mt-md-6 gap-4">
|
||||
<v-btn :disabled="submitting" @click="save">
|
||||
{{ tt('Save') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn color="secondary" density="default" variant="tonal"
|
||||
:disabled="submitting" @click="showState = false">{{ tt('Cancel') }}</v-btn>
|
||||
@@ -137,6 +137,7 @@ function save(): void {
|
||||
|
||||
<style>
|
||||
.preset-transaction-categories .v-expansion-panel-text__wrapper {
|
||||
padding: 0 0 0 20px;
|
||||
padding: 0 0 0 0;
|
||||
padding-inline-start: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="w-100 text-center">
|
||||
<h4 class="text-h4">{{ tt(title) }}</h4>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading || !hasAnyAvailableAccount" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -36,7 +36,7 @@
|
||||
<div class="d-flex align-center" v-else-if="!dialogMode">
|
||||
<span>{{ tt(title) }}</span>
|
||||
<v-spacer/>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -83,7 +83,7 @@
|
||||
v-for="accountCategory in allCategorizedAccounts"
|
||||
v-show="showHidden || accountCategory.allVisibleAccountCount > 0">
|
||||
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
|
||||
<span class="ml-3">{{ tt(accountCategory.name) }}</span>
|
||||
<span class="ms-3">{{ tt(accountCategory.name) }}</span>
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<v-list rounded density="comfortable" class="pa-0">
|
||||
@@ -99,7 +99,7 @@
|
||||
<template #label>
|
||||
<ItemIcon class="d-flex" icon-type="account" :icon-id="account.icon"
|
||||
:color="account.color" :hidden-status="account.hidden"></ItemIcon>
|
||||
<span class="ml-3">{{ account.name }}</span>
|
||||
<span class="ms-3">{{ account.name }}</span>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</template>
|
||||
@@ -107,7 +107,7 @@
|
||||
|
||||
<v-divider v-if="(showHidden || !account.hidden) && account.type === AccountType.MultiSubAccounts.type && ((showHidden && accountCategory.allSubAccounts[account.id]) || accountCategory.allVisibleSubAccountCounts[account.id])"/>
|
||||
|
||||
<v-list rounded density="comfortable" class="pa-0 ml-4"
|
||||
<v-list rounded density="comfortable" class="pa-0 ms-4"
|
||||
v-if="(showHidden || !account.hidden) && account.type === AccountType.MultiSubAccounts.type && ((showHidden && accountCategory.allSubAccounts[account.id]) || accountCategory.allVisibleSubAccountCounts[account.id])">
|
||||
<template :key="subAccount.id"
|
||||
v-for="(subAccount, subIdx) in accountCategory.allSubAccounts[account.id]">
|
||||
@@ -120,7 +120,7 @@
|
||||
<template #label>
|
||||
<ItemIcon class="d-flex" icon-type="account" :icon-id="subAccount.icon"
|
||||
:color="subAccount.color" :hidden-status="subAccount.hidden"></ItemIcon>
|
||||
<span class="ml-3">{{ subAccount.name }}</span>
|
||||
<span class="ms-3">{{ subAccount.name }}</span>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</template>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="w-100 text-center">
|
||||
<h4 class="text-h4">{{ tt(title) }}</h4>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading || !hasAnyAvailableCategory" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -36,7 +36,7 @@
|
||||
<div class="d-flex align-center" v-else-if="!dialogMode">
|
||||
<span>{{ tt(title) }}</span>
|
||||
<v-spacer/>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -78,7 +78,7 @@
|
||||
class="border"
|
||||
v-for="transactionType in allTransactionCategories">
|
||||
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
|
||||
<span class="ml-3">{{ getCategoryTypeName(transactionType.type) }}</span>
|
||||
<span class="ms-3">{{ getCategoryTypeName(transactionType.type) }}</span>
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<v-list rounded density="comfortable" class="pa-0">
|
||||
@@ -96,7 +96,7 @@
|
||||
<template #label>
|
||||
<ItemIcon class="d-flex" icon-type="category" :icon-id="category.icon"
|
||||
:color="category.color" :hidden-status="category.hidden"></ItemIcon>
|
||||
<span class="ml-3">{{ category.name }}</span>
|
||||
<span class="ms-3">{{ category.name }}</span>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</template>
|
||||
@@ -104,7 +104,7 @@
|
||||
|
||||
<v-divider v-if="(showHidden || !category.hidden) && ((showHidden && transactionType.allSubCategories[category.id]) || transactionType.allVisibleSubCategoryCounts[category.id])"/>
|
||||
|
||||
<v-list rounded density="comfortable" class="pa-0 ml-4"
|
||||
<v-list rounded density="comfortable" class="pa-0 ms-4"
|
||||
v-if="(showHidden || !category.hidden) && ((showHidden && transactionType.allSubCategories[category.id]) || transactionType.allVisibleSubCategoryCounts[category.id])">
|
||||
<template :key="subCategory.id"
|
||||
v-for="(subCategory, subIdx) in transactionType.allSubCategories[category.id]">
|
||||
@@ -117,7 +117,7 @@
|
||||
<template #label>
|
||||
<ItemIcon class="d-flex" icon-type="category" :icon-id="subCategory.icon"
|
||||
:color="subCategory.color" :hidden-status="subCategory.hidden"></ItemIcon>
|
||||
<span class="ml-3">{{ subCategory.name }}</span>
|
||||
<span class="ms-3">{{ subCategory.name }}</span>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</template>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="w-100 text-center">
|
||||
<h4 class="text-h4">{{ tt(title) }}</h4>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading || !hasAnyAvailableTag" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -36,7 +36,7 @@
|
||||
<div class="d-flex align-center" v-else-if="!dialogMode">
|
||||
<span>{{ tt(title) }}</span>
|
||||
<v-spacer/>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -90,7 +90,7 @@
|
||||
<v-expansion-panels class="tag-categories" multiple v-model="expandTagCategories">
|
||||
<v-expansion-panel class="border" key="default" value="default">
|
||||
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
|
||||
<span class="ml-3">{{ tt('Tags') }}</span>
|
||||
<span class="ms-3">{{ tt('Tags') }}</span>
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<v-list rounded density="comfortable" class="pa-0">
|
||||
@@ -107,7 +107,7 @@
|
||||
<v-icon size="24" :icon="mdiPound"/>
|
||||
</v-badge>
|
||||
<v-icon size="24" :icon="mdiPound" v-else-if="!transactionTag.hidden"/>
|
||||
<span class="ml-3">{{ transactionTag.name }}</span>
|
||||
<span class="ms-3">{{ transactionTag.name }}</span>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</template>
|
||||
@@ -269,7 +269,8 @@ init();
|
||||
}
|
||||
|
||||
.tag-categories .v-expansion-panel-text__wrapper {
|
||||
padding: 0 0 0 20px;
|
||||
padding: 0 0 0 0;
|
||||
padding-inline-start: 20px;
|
||||
}
|
||||
|
||||
.tag-categories .v-expansion-panel--active:not(:first-child),
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
v-if="exchangeRatesData && exchangeRatesData.exchangeRates && exchangeRatesData.exchangeRates.length">
|
||||
<v-tab class="tab-text-truncate" :key="exchangeRate.currencyCode" :value="exchangeRate.currencyCode"
|
||||
v-for="exchangeRate in availableExchangeRates">
|
||||
<div class="text-truncate">
|
||||
<span>{{ exchangeRate.currencyDisplayName }}</span>
|
||||
<small class="smaller ml-1">{{ exchangeRate.currencyCode }}</small>
|
||||
<div class="d-flex w-100">
|
||||
<span class="d-block text-truncate">{{ exchangeRate.currencyDisplayName }}</span>
|
||||
<small class="smaller ms-1">{{ exchangeRate.currencyCode }}</small>
|
||||
</div>
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
@@ -61,16 +61,16 @@
|
||||
<v-card variant="flat" min-height="680">
|
||||
<template #title>
|
||||
<div class="title-and-toolbar d-flex align-center">
|
||||
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
:ripple="false" :icon="true" @click="showNav = !showNav">
|
||||
<v-icon :icon="mdiMenu" size="24" />
|
||||
</v-btn>
|
||||
<span>{{ tt('Exchange Rates Data') }}</span>
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
:disabled="loading" @click="update"
|
||||
v-if="isUserCustomExchangeRates">{{ tt('Update') }}</v-btn>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loading" @click="reload(true)">
|
||||
class="ms-2" :icon="true" :loading="loading" @click="reload(true)">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
@@ -110,11 +110,11 @@
|
||||
<td>
|
||||
<div class="d-flex align-center">
|
||||
<span class="text-sm">{{ exchangeRate.currencyDisplayName }}</span>
|
||||
<span class="text-caption ml-1">{{ exchangeRate.currencyCode }}</span>
|
||||
<span class="text-caption ms-1">{{ exchangeRate.currencyCode }}</span>
|
||||
|
||||
<v-spacer/>
|
||||
|
||||
<v-btn class="px-2 ml-2" color="default"
|
||||
<v-btn class="px-2 ms-2" color="default"
|
||||
density="comfortable" variant="text"
|
||||
:class="{ 'd-none': loading, 'hover-display': !loading }"
|
||||
v-if="exchangeRate.currencyCode !== baseCurrency"
|
||||
@@ -134,7 +134,7 @@
|
||||
</template>
|
||||
{{ tt('Delete') }}
|
||||
</v-btn>
|
||||
<span class="ml-3">{{ getFinalConvertedAmount(exchangeRate, true) }}</span>
|
||||
<span class="ms-3">{{ getFinalConvertedAmount(exchangeRate, true) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<div class="w-100 d-flex justify-center gap-4">
|
||||
<v-btn :disabled="submitting || !defaultCurrencyAmount || !currency || !targetCurrencyAmount" @click="confirm">
|
||||
{{ tt('OK') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn color="secondary" variant="tonal" :disabled="submitting" @click="cancel">{{ tt('Cancel') }}</v-btn>
|
||||
</div>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<v-avatar color="secondary" size="38">
|
||||
<v-icon size="24" :icon="icon" />
|
||||
</v-avatar>
|
||||
<span class="font-weight-bold ml-3">{{ title }}</span>
|
||||
<span class="font-weight-bold ms-3">{{ title }}</span>
|
||||
<v-spacer/>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2" :icon="true">
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
<v-list>
|
||||
|
||||
@@ -34,6 +34,7 @@ import { useI18n } from '@/locales/helpers.ts';
|
||||
import { useSettingsStore } from '@/stores/setting.ts';
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
|
||||
import { TextDirection } from '@/core/text.ts';
|
||||
import type { HiddenAmount } from '@/core/numeral.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
|
||||
@@ -63,11 +64,12 @@ const emit = defineEmits<{
|
||||
(e: 'click', event: MonthlyIncomeAndExpenseCardClickEvent): void;
|
||||
}>();
|
||||
|
||||
const { tt, getMonthShortName, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
const { tt, getCurrentLanguageTextDirection, getMonthShortName, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
||||
const showAmountInHomePage = computed<boolean>(() => settingsStore.appSettings.showAmountInHomePage);
|
||||
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
||||
const hasAnyData = computed<boolean>(() => {
|
||||
@@ -157,21 +159,21 @@ const chartOptions = computed<object>(() => {
|
||||
return `<table>` +
|
||||
`<thead>` +
|
||||
`<tr>` +
|
||||
`<td colspan="2" class="text-left">${params[0].name}</td>` +
|
||||
`<td colspan="2" class="text-start">${params[0].name}</td>` +
|
||||
`</tr>` +
|
||||
`</thead>` +
|
||||
`<tbody>` +
|
||||
(
|
||||
incomeAmount !== null ?
|
||||
`<tr>` +
|
||||
`<td><span class="overview-monthly-chart-tooltip-indicator bg-income mr-1"></span><span class="mr-4">${tt('Income')}</span></td>` +
|
||||
`<td><span class="overview-monthly-chart-tooltip-indicator bg-income me-1"></span><span class="me-4">${tt('Income')}</span></td>` +
|
||||
`<td><strong>${incomeAmount}</strong></td>` +
|
||||
`</tr>` : ''
|
||||
)+
|
||||
(
|
||||
expenseAmount !== null ?
|
||||
`<tr>` +
|
||||
`<td><span class="overview-monthly-chart-tooltip-indicator bg-expense mr-1"></span><span class="mr-4">${tt('Expense')}</span></td>` +
|
||||
`<td><span class="overview-monthly-chart-tooltip-indicator bg-expense me-1"></span><span class="me-4">${tt('Expense')}</span></td>` +
|
||||
`<td><strong>${expenseAmount}</strong></td>` +
|
||||
`</tr>` : ''
|
||||
) +
|
||||
@@ -199,6 +201,7 @@ const chartOptions = computed<object>(() => {
|
||||
{
|
||||
type: 'category',
|
||||
data: monthNames,
|
||||
inverse: textDirection.value === TextDirection.RTL,
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
|
||||
@@ -51,13 +51,13 @@
|
||||
<v-card variant="flat" min-height="680">
|
||||
<template #title>
|
||||
<div class="title-and-toolbar d-flex align-center">
|
||||
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
:ripple="false" :icon="true" @click="showNav = !showNav">
|
||||
<v-icon :icon="mdiMenu" size="24" />
|
||||
</v-btn>
|
||||
<span>{{ tt('Statistics & Analysis') }}</span>
|
||||
<v-btn-group class="ml-4" color="default" density="comfortable" variant="outlined" divided>
|
||||
<v-btn :icon="mdiArrowLeft"
|
||||
<v-btn-group class="ms-4" color="default" density="comfortable" variant="outlined" divided>
|
||||
<v-btn class="button-icon-with-direction" :icon="mdiArrowLeft"
|
||||
:disabled="loading || !canShiftDateRange"
|
||||
@click="shiftDateRange(-1)"/>
|
||||
<v-menu location="bottom">
|
||||
@@ -83,14 +83,14 @@
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-btn :icon="mdiArrowRight"
|
||||
<v-btn class="button-icon-with-direction" :icon="mdiArrowRight"
|
||||
:disabled="loading || !canShiftDateRange"
|
||||
@click="shiftDateRange(1)"/>
|
||||
</v-btn-group>
|
||||
|
||||
<v-menu location="bottom" v-if="queryAnalysisType === StatisticsAnalysisType.TrendAnalysis">
|
||||
<template #activator="{ props }">
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
:prepend-icon="mdiCalendarRangeOutline" :disabled="loading"
|
||||
v-bind="props">{{ queryTrendDateAggregationTypeName }}</v-btn>
|
||||
</template>
|
||||
@@ -105,7 +105,7 @@
|
||||
</v-menu>
|
||||
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loading" @click="reload(true)">
|
||||
class="ms-2" :icon="true" :loading="loading" @click="reload(true)">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
@@ -113,7 +113,7 @@
|
||||
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<div class="transaction-keyword-filter ml-2">
|
||||
<div class="transaction-keyword-filter ms-2">
|
||||
<v-text-field density="compact" :disabled="loading"
|
||||
:prepend-inner-icon="mdiMagnify"
|
||||
:append-inner-icon="filterKeyword !== query.keyword ? mdiCheck : undefined"
|
||||
@@ -123,7 +123,7 @@
|
||||
@keyup.enter="setKeywordFilter(filterKeyword)"
|
||||
/>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -155,12 +155,12 @@
|
||||
<v-card-text class="statistics-overview-title pt-0" :class="{ 'disabled': loading }"
|
||||
v-if="queryAnalysisType === StatisticsAnalysisType.CategoricalAnalysis && (initing || (categoricalAnalysisData && categoricalAnalysisData.items && categoricalAnalysisData.items.length))">
|
||||
<span class="statistics-subtitle">{{ totalAmountName }}</span>
|
||||
<span class="statistics-overview-amount ml-3"
|
||||
<span class="statistics-overview-amount ms-3"
|
||||
:class="statisticsTextColor"
|
||||
v-if="!initing && categoricalAnalysisData && categoricalAnalysisData.items && categoricalAnalysisData.items.length">
|
||||
{{ getDisplayAmount(categoricalAnalysisData.totalAmount, defaultCurrency) }}
|
||||
</span>
|
||||
<v-skeleton-loader class="skeleton-no-margin ml-3 mb-2"
|
||||
<v-skeleton-loader class="skeleton-no-margin ms-3 mb-2"
|
||||
width="120px" type="text" :loading="true"
|
||||
v-else-if="initing"></v-skeleton-loader>
|
||||
</v-card-text>
|
||||
@@ -204,13 +204,13 @@
|
||||
<v-card-text :class="{ 'readonly': loading }" v-if="queryAnalysisType === StatisticsAnalysisType.CategoricalAnalysis && query.categoricalChartType === CategoricalChartType.Bar.type">
|
||||
<v-list rounded lines="two" v-if="initing">
|
||||
<template :key="itemIdx" v-for="itemIdx in [ 1, 2, 3 ]">
|
||||
<v-list-item class="pl-0">
|
||||
<v-list-item class="ps-0">
|
||||
<template #prepend>
|
||||
<div>
|
||||
<v-icon class="disabled mr-0" size="34" :icon="mdiSquareRounded" />
|
||||
<v-icon class="disabled me-0" size="34" :icon="mdiSquareRounded" />
|
||||
</div>
|
||||
</template>
|
||||
<div class="d-flex flex-column ml-2">
|
||||
<div class="d-flex flex-column ms-2">
|
||||
<div class="d-flex">
|
||||
<v-skeleton-loader class="skeleton-no-margin my-2"
|
||||
width="120px" type="text" :loading="true"></v-skeleton-loader>
|
||||
@@ -226,7 +226,7 @@
|
||||
<v-list class="py-0" rounded lines="two" v-else-if="!initing && categoricalAnalysisData && categoricalAnalysisData.items && categoricalAnalysisData.items.length">
|
||||
<template :key="idx"
|
||||
v-for="(item, idx) in categoricalAnalysisData.items">
|
||||
<v-list-item class="pl-0" v-if="!item.hidden">
|
||||
<v-list-item class="ps-0" v-if="!item.hidden">
|
||||
<template #prepend>
|
||||
<router-link class="statistics-list-item" :to="getTransactionItemLinkUrl(item.id)">
|
||||
<ItemIcon :icon-type="queryChartDataCategory" size="34px"
|
||||
@@ -235,7 +235,7 @@
|
||||
</router-link>
|
||||
</template>
|
||||
<router-link class="statistics-list-item" :to="getTransactionItemLinkUrl(item.id)">
|
||||
<div class="d-flex flex-column ml-2">
|
||||
<div class="d-flex flex-column ms-2">
|
||||
<div class="d-flex">
|
||||
<span>{{ item.name }}</span>
|
||||
<small class="statistics-percent" v-if="item.percent >= 0">{{ formatPercentToLocalizedNumerals(item.percent, 2, '<0.01') }}</small>
|
||||
@@ -1058,7 +1058,7 @@ init(props);
|
||||
.statistics-list-item .statistics-percent {
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.7;
|
||||
margin-left: 6px;
|
||||
margin-inline-start: 6px;
|
||||
}
|
||||
|
||||
.statistics-list-item .statistics-amount {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="d-flex w-100 align-center justify-center">
|
||||
<h4 class="text-h4">{{ tt('Export Results') }}</h4>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2" :icon="true">
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
<v-list>
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
<template #title>
|
||||
<div class="title-and-toolbar d-flex align-center">
|
||||
<span>{{ tt('Transaction Tags') }}</span>
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
:disabled="loading || updating || hasEditingTag" @click="add">{{ tt('Add') }}</v-btn>
|
||||
<v-btn class="ml-3" color="primary" variant="tonal"
|
||||
<v-btn class="ms-3" color="primary" variant="tonal"
|
||||
:disabled="loading || updating || hasEditingTag" @click="saveSortResult"
|
||||
v-if="displayOrderModified">{{ tt('Save Display Order') }}</v-btn>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :disabled="loading || updating || hasEditingTag"
|
||||
class="ms-2" :icon="true" :disabled="loading || updating || hasEditingTag"
|
||||
:loading="loading" @click="reload">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
@@ -20,7 +20,7 @@
|
||||
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading || updating || hasEditingTag" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -86,7 +86,7 @@
|
||||
<span class="transaction-tag-name">{{ element.name }}</span>
|
||||
</div>
|
||||
|
||||
<v-text-field class="w-100 mr-2" type="text"
|
||||
<v-text-field class="w-100 me-2" type="text"
|
||||
density="compact" variant="underlined"
|
||||
:disabled="loading || updating"
|
||||
:placeholder="tt('Tag Title')"
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
<v-spacer/>
|
||||
|
||||
<v-btn class="px-2 ml-2" color="default"
|
||||
<v-btn class="px-2 ms-2" color="default"
|
||||
density="comfortable" variant="text"
|
||||
:class="{ 'd-none': loading, 'hover-display': !loading }"
|
||||
:prepend-icon="element.hidden ? mdiEyeOutline : mdiEyeOffOutline"
|
||||
@@ -163,7 +163,7 @@
|
||||
v-if="editingTag.id === element.id" @click="cancelSave(editingTag)">
|
||||
{{ tt('Cancel') }}
|
||||
</v-btn>
|
||||
<span class="ml-2">
|
||||
<span class="ms-2">
|
||||
<v-icon :class="!loading && !updating && !hasEditingTag && availableTagCount > 1 ? 'drag-handle' : 'disabled'"
|
||||
:icon="mdiDrag"/>
|
||||
<v-tooltip activator="parent" v-if="!loading && !updating && !hasEditingTag && availableTagCount > 1">{{ tt('Drag to Reorder') }}</v-tooltip>
|
||||
@@ -178,7 +178,7 @@
|
||||
<tr class="text-sm" :class="{ 'even-row': (availableTagCount & 1) === 1}">
|
||||
<td>
|
||||
<div class="d-flex align-center">
|
||||
<v-text-field class="w-100 mr-2" type="text" color="primary"
|
||||
<v-text-field class="w-100 me-2" type="text" color="primary"
|
||||
density="compact" variant="underlined"
|
||||
:disabled="loading || updating" :placeholder="tt('Tag Title')"
|
||||
v-model="newTag.name" @keyup.enter="save(newTag)">
|
||||
@@ -206,7 +206,7 @@
|
||||
@click="cancelSave(newTag)">
|
||||
{{ tt('Cancel') }}
|
||||
</v-btn>
|
||||
<span class="ml-2">
|
||||
<span class="ms-2">
|
||||
<v-icon class="disabled" :icon="mdiDrag"/>
|
||||
</span>
|
||||
</div>
|
||||
@@ -474,7 +474,7 @@ transactionTagsStore.loadAllTags({
|
||||
}
|
||||
|
||||
.transaction-tags-table .v-text-field .v-input__prepend {
|
||||
margin-right: 0;
|
||||
margin-inline-end: 0;
|
||||
color: rgba(var(--v-theme-on-surface));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
<template #title>
|
||||
<div class="title-and-toolbar d-flex align-center">
|
||||
<span>{{ templateType === TemplateType.Schedule.type ? tt('Scheduled Transactions') : tt('Transaction Templates') }}</span>
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
:disabled="loading || updating" @click="add">{{ tt('Add') }}</v-btn>
|
||||
<v-btn class="ml-3" color="primary" variant="tonal"
|
||||
<v-btn class="ms-3" color="primary" variant="tonal"
|
||||
:disabled="loading || updating" @click="saveSortResult"
|
||||
v-if="displayOrderModified">{{ tt('Save Display Order') }}</v-btn>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :disabled="loading || updating"
|
||||
class="ms-2" :icon="true" :disabled="loading || updating"
|
||||
:loading="loading" @click="reload">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
@@ -20,7 +20,7 @@
|
||||
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="loading || updating" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
<v-spacer/>
|
||||
|
||||
<v-btn class="px-2 ml-2" color="default"
|
||||
<v-btn class="px-2 ms-2" color="default"
|
||||
density="comfortable" variant="text"
|
||||
:class="{ 'd-none': loading, 'hover-display': !loading }"
|
||||
:prepend-icon="element.hidden ? mdiEyeOutline : mdiEyeOffOutline"
|
||||
@@ -124,7 +124,7 @@
|
||||
</template>
|
||||
{{ tt('Delete') }}
|
||||
</v-btn>
|
||||
<span class="ml-2">
|
||||
<span class="ms-2">
|
||||
<v-icon :class="!loading && !updating && availableTemplateCount > 1 ? 'drag-handle' : 'disabled'"
|
||||
:icon="mdiDrag"/>
|
||||
<v-tooltip activator="parent" v-if="!loading && !updating && availableTemplateCount > 1">{{ tt('Drag to Reorder') }}</v-tooltip>
|
||||
@@ -387,7 +387,7 @@ init();
|
||||
}
|
||||
|
||||
.transaction-templates-table .v-text-field .v-input__prepend {
|
||||
margin-right: 0;
|
||||
margin-inline-end: 0;
|
||||
color: rgba(var(--v-theme-on-surface));
|
||||
}
|
||||
|
||||
|
||||
@@ -52,12 +52,12 @@
|
||||
<v-card variant="flat" min-height="920">
|
||||
<template #title>
|
||||
<div class="title-and-toolbar d-flex align-center text-no-wrap">
|
||||
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
|
||||
:ripple="false" :icon="true" @click="showNav = !showNav">
|
||||
<v-icon :icon="mdiMenu" size="24" />
|
||||
</v-btn>
|
||||
<span>{{ tt('Transaction List') }}</span>
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
:disabled="loading || !canAddTransaction" @click="add()">
|
||||
{{ tt('Add') }}
|
||||
<v-menu activator="parent" :open-on-hover="true" v-if="allTransactionTemplates && allTransactionTemplates.length">
|
||||
@@ -70,7 +70,7 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
:disabled="loading" @click="importTransaction"
|
||||
v-if="isDataImportingEnabled()">
|
||||
{{ tt('Import') }}
|
||||
@@ -87,7 +87,7 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" color="default" variant="outlined"
|
||||
:disabled="loading || exportingData || !transactions || !transactions.length || transactions.length < 1" v-if="!isDataImportingEnabled() && isDataExportingEnabled()">
|
||||
{{ tt('Export') }}
|
||||
<v-menu activator="parent">
|
||||
@@ -104,7 +104,7 @@
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loading" @click="reload(true, false)">
|
||||
class="ms-2" :icon="true" :loading="loading" @click="reload(true, false)">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
@@ -112,7 +112,7 @@
|
||||
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<div class="transaction-keyword-filter ml-2">
|
||||
<div class="transaction-keyword-filter ms-2">
|
||||
<v-text-field density="compact" :disabled="loading"
|
||||
:prepend-inner-icon="mdiMagnify"
|
||||
:append-inner-icon="searchKeyword !== query.keyword ? mdiCheck : undefined"
|
||||
@@ -128,36 +128,36 @@
|
||||
<v-card-text class="pt-0">
|
||||
<div class="transaction-list-datetime-range d-flex align-center">
|
||||
<span class="text-body-1">{{ tt('Date Range') }}</span>
|
||||
<span class="text-body-1 transaction-list-datetime-range-text ml-2"
|
||||
<span class="text-body-1 transaction-list-datetime-range-text ms-2"
|
||||
v-if="!query.minTime && !query.maxTime">
|
||||
<span class="text-sm">{{ tt('All') }}</span>
|
||||
</span>
|
||||
<span class="text-body-1 transaction-list-datetime-range-text ml-2"
|
||||
<span class="text-body-1 transaction-list-datetime-range-text ms-2"
|
||||
v-else-if="query.minTime || query.maxTime">
|
||||
<v-btn class="mr-1" size="x-small"
|
||||
<v-btn class="button-icon-with-direction me-1" size="x-small"
|
||||
density="compact" color="default" variant="outlined"
|
||||
:icon="mdiArrowLeft" :disabled="loading"
|
||||
@click="shiftDateRange(query.minTime, query.maxTime, -1)"/>
|
||||
<span class="text-sm">{{ `${queryMinTime} - ${queryMaxTime}` }}</span>
|
||||
<v-btn class="ml-1" size="x-small"
|
||||
<v-btn class="button-icon-with-direction ms-1" size="x-small"
|
||||
density="compact" color="default" variant="outlined"
|
||||
:icon="mdiArrowRight" :disabled="loading"
|
||||
@click="shiftDateRange(query.minTime, query.maxTime, 1)"/>
|
||||
</span>
|
||||
<v-spacer/>
|
||||
<div class="skeleton-no-margin d-flex align-center" v-if="showTotalAmountInTransactionListPage && currentMonthTotalAmount">
|
||||
<span class="ml-2 text-subtitle-1">{{ queryAllFilterAccountIdsCount ? tt('Total Inflows') : tt('Total Income') }}</span>
|
||||
<span class="text-income ml-2" v-if="loading">
|
||||
<span class="ms-2 text-subtitle-1">{{ queryAllFilterAccountIdsCount ? tt('Total Inflows') : tt('Total Income') }}</span>
|
||||
<span class="text-income ms-2" v-if="loading">
|
||||
<v-skeleton-loader type="text" style="width: 60px" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
<span class="text-income ml-2" v-else-if="!loading">
|
||||
<span class="text-income ms-2" v-else-if="!loading">
|
||||
{{ currentMonthTotalAmount.income }}
|
||||
</span>
|
||||
<span class="text-subtitle-1 ml-3">{{ queryAllFilterAccountIdsCount ? tt('Total Outflows') : tt('Total Expense') }}</span>
|
||||
<span class="text-expense ml-2" v-if="loading">
|
||||
<span class="text-subtitle-1 ms-3">{{ queryAllFilterAccountIdsCount ? tt('Total Outflows') : tt('Total Expense') }}</span>
|
||||
<span class="text-expense ms-2" v-if="loading">
|
||||
<v-skeleton-loader type="text" style="width: 60px" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
<span class="text-expense ml-2" v-else-if="!loading">
|
||||
<span class="text-expense ms-2" v-else-if="!loading">
|
||||
{{ currentMonthTotalAmount.expense }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -217,10 +217,10 @@
|
||||
<v-list-item-title class="cursor-pointer"
|
||||
@click="changeDateFilter(dateRange.type)">
|
||||
<div class="d-flex align-center">
|
||||
<span class="text-sm ml-3">{{ dateRange.displayName }}</span>
|
||||
<span class="text-sm ms-3">{{ dateRange.displayName }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
<div class="ml-3 smaller" v-if="((dateRange.isBillingCycle || dateRange.type === DateRange.Custom.type) && query.dateType === dateRange.type) && query.minTime && query.maxTime">
|
||||
<div class="ms-3 smaller" v-if="((dateRange.isBillingCycle || dateRange.type === DateRange.Custom.type) && query.dateType === dateRange.type) && query.minTime && query.maxTime">
|
||||
<span>{{ queryMinTime }}</span>
|
||||
<span> - </span>
|
||||
<br/>
|
||||
@@ -253,7 +253,7 @@
|
||||
@click="changeCategoryFilter('')">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon :icon="mdiViewGridOutline" />
|
||||
<span class="text-sm ml-3">{{ tt('All') }}</span>
|
||||
<span class="text-sm ms-3">{{ tt('All') }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -265,7 +265,7 @@
|
||||
@click="showFilterCategoryDialog = true">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon :icon="mdiVectorArrangeBelow" />
|
||||
<span class="text-sm ml-3">{{ tt('Multiple Categories') }}</span>
|
||||
<span class="text-sm ms-3">{{ tt('Multiple Categories') }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -287,7 +287,7 @@
|
||||
<v-list-item-title>
|
||||
<div class="d-flex align-center">
|
||||
<ItemIcon icon-type="category" size="24px" :icon-id="category.icon" :color="category.color"></ItemIcon>
|
||||
<span class="text-sm ml-3">{{ category.name }}</span>
|
||||
<span class="text-sm ms-3">{{ category.name }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -302,7 +302,7 @@
|
||||
@click="changeCategoryFilter(category.id)">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon :icon="mdiViewGridOutline" />
|
||||
<span class="text-sm ml-3">{{ tt('All') }}</span>
|
||||
<span class="text-sm ms-3">{{ tt('All') }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -319,7 +319,7 @@
|
||||
@click="changeCategoryFilter(subCategory.id)">
|
||||
<div class="d-flex align-center">
|
||||
<ItemIcon icon-type="category" size="24px" :icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
|
||||
<span class="text-sm ml-3">{{ subCategory.name }}</span>
|
||||
<span class="text-sm ms-3">{{ subCategory.name }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -349,7 +349,7 @@
|
||||
<v-list-item-title class="cursor-pointer"
|
||||
@click="changeAmountFilter('')">
|
||||
<div class="d-flex align-center">
|
||||
<span class="text-sm ml-3">{{ tt('All') }}</span>
|
||||
<span class="text-sm ms-3">{{ tt('All') }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -362,18 +362,18 @@
|
||||
<v-list-item-title class="cursor-pointer"
|
||||
@click="currentAmountFilterType = filterType.type">
|
||||
<div class="d-flex align-center">
|
||||
<span class="text-sm ml-3">{{ tt(filterType.name) }}</span>
|
||||
<span class="text-sm ml-4" v-if="query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`) && currentAmountFilterType !== filterType.type">{{ queryAmount }}</span>
|
||||
<amount-input class="transaction-amount-filter-value ml-4" density="compact"
|
||||
<span class="text-sm ms-3">{{ tt(filterType.name) }}</span>
|
||||
<span class="text-sm ms-4" v-if="query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`) && currentAmountFilterType !== filterType.type">{{ queryAmount }}</span>
|
||||
<amount-input class="transaction-amount-filter-value ms-4" density="compact"
|
||||
:currency="defaultCurrency"
|
||||
v-model="currentAmountFilterValue1"
|
||||
v-if="currentAmountFilterType === filterType.type"/>
|
||||
<span class="ml-2 mr-2" v-if="currentAmountFilterType === filterType.type && filterType.paramCount === 2">~</span>
|
||||
<span class="ms-2 me-2" v-if="currentAmountFilterType === filterType.type && filterType.paramCount === 2">~</span>
|
||||
<amount-input class="transaction-amount-filter-value" density="compact"
|
||||
:currency="defaultCurrency"
|
||||
v-model="currentAmountFilterValue2"
|
||||
v-if="currentAmountFilterType === filterType.type && filterType.paramCount === 2"/>
|
||||
<v-btn class="ml-2" density="compact" color="primary" variant="tonal"
|
||||
<v-btn class="ms-2" density="compact" color="primary" variant="tonal"
|
||||
@click="changeAmountFilter(filterType.type)"
|
||||
v-if="currentAmountFilterType === filterType.type">{{ tt('Apply') }}</v-btn>
|
||||
</div>
|
||||
@@ -402,7 +402,7 @@
|
||||
@click="changeAccountFilter('')">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon :icon="mdiViewGridOutline" />
|
||||
<span class="text-sm ml-3">{{ tt('All') }}</span>
|
||||
<span class="text-sm ms-3">{{ tt('All') }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -414,7 +414,7 @@
|
||||
@click="showFilterAccountDialog = true">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon :icon="mdiVectorArrangeBelow" />
|
||||
<span class="text-sm ml-3">{{ tt('Multiple Accounts') }}</span>
|
||||
<span class="text-sm ms-3">{{ tt('Multiple Accounts') }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -430,7 +430,7 @@
|
||||
@click="changeAccountFilter(account.id)">
|
||||
<div class="d-flex align-center">
|
||||
<ItemIcon icon-type="account" size="24px" :icon-id="account.icon" :color="account.color"></ItemIcon>
|
||||
<span class="text-sm ml-3">{{ account.name }}</span>
|
||||
<span class="text-sm ms-3">{{ account.name }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -457,7 +457,7 @@
|
||||
@click="changeTagFilter('')">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon :icon="mdiViewGridOutline" />
|
||||
<span class="text-sm ml-3">{{ tt('All') }}</span>
|
||||
<span class="text-sm ms-3">{{ tt('All') }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -468,7 +468,7 @@
|
||||
@click="changeTagFilter('none')">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon :icon="mdiBorderNoneVariant" />
|
||||
<span class="text-sm ml-3">{{ tt('Without Tags') }}</span>
|
||||
<span class="text-sm ms-3">{{ tt('Without Tags') }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -480,7 +480,7 @@
|
||||
@click="showFilterTagDialog = true">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon :icon="mdiVectorArrangeBelow" />
|
||||
<span class="text-sm ml-3">{{ tt('Multiple Tags') }}</span>
|
||||
<span class="text-sm ms-3">{{ tt('Multiple Tags') }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -497,7 +497,7 @@
|
||||
@click="changeTagFilterType(filterType.type)">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon size="24" :icon="filterType.icon"/>
|
||||
<span class="text-sm ml-3">{{ filterType.displayName }}</span>
|
||||
<span class="text-sm ms-3">{{ filterType.displayName }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -515,7 +515,7 @@
|
||||
@click="changeTagFilter(transactionTag.id)">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon size="24" :icon="mdiPound"/>
|
||||
<span class="text-sm ml-3">{{ transactionTag.name }}</span>
|
||||
<span class="text-sm ms-3">{{ transactionTag.name }}</span>
|
||||
</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -549,7 +549,7 @@
|
||||
<td :colspan="showTagInTransactionListPage ? 6 : 5" class="font-weight-bold">
|
||||
<div class="d-flex align-center">
|
||||
<span>{{ getDisplayLongDate(transaction) }}</span>
|
||||
<v-chip class="ml-1" color="default" size="x-small"
|
||||
<v-chip class="ms-1" color="default" size="x-small"
|
||||
v-if="transaction.dayOfWeek">
|
||||
{{ getWeekdayLongName(transaction.dayOfWeek) }}
|
||||
</v-chip>
|
||||
@@ -572,13 +572,13 @@
|
||||
:color="transaction.category.color"
|
||||
v-if="transaction.category && transaction.category.color"></ItemIcon>
|
||||
<v-icon size="24" :icon="mdiPencilBoxOutline" v-else-if="!transaction.category || !transaction.category.color" />
|
||||
<span class="ml-2" v-if="transaction.type === TransactionType.ModifyBalance">
|
||||
<span class="ms-2" v-if="transaction.type === TransactionType.ModifyBalance">
|
||||
{{ tt('Modify Balance') }}
|
||||
</span>
|
||||
<span class="ml-2" v-else-if="transaction.type !== TransactionType.ModifyBalance && transaction.category">
|
||||
<span class="ms-2" v-else-if="transaction.type !== TransactionType.ModifyBalance && transaction.category">
|
||||
{{ transaction.category.name }}
|
||||
</span>
|
||||
<span class="ml-2" v-else-if="transaction.type !== TransactionType.ModifyBalance && !transaction.category">
|
||||
<span class="ms-2" v-else-if="transaction.type !== TransactionType.ModifyBalance && !transaction.category">
|
||||
{{ getTransactionTypeName(transaction.type, 'Transaction') }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -591,7 +591,7 @@
|
||||
<td class="transaction-table-column-account">
|
||||
<div class="d-flex align-center">
|
||||
<span v-if="transaction.sourceAccount">{{ transaction.sourceAccount.name }}</span>
|
||||
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="transaction.sourceAccount && transaction.type === TransactionType.Transfer && transaction.destinationAccount && transaction.sourceAccount.id !== transaction.destinationAccount.id"></v-icon>
|
||||
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="transaction.sourceAccount && transaction.type === TransactionType.Transfer && transaction.destinationAccount && transaction.sourceAccount.id !== transaction.destinationAccount.id"></v-icon>
|
||||
<span v-if="transaction.sourceAccount && transaction.type === TransactionType.Transfer && transaction.destinationAccount && transaction.sourceAccount.id !== transaction.destinationAccount.id">{{ transaction.destinationAccount.name }}</span>
|
||||
</div>
|
||||
</td>
|
||||
@@ -1828,11 +1828,11 @@ init(props);
|
||||
|
||||
.transaction-table .transaction-table-column-category .v-btn .v-btn__append,
|
||||
.transaction-table .transaction-table-column-account .v-btn .v-btn__append {
|
||||
margin-left: 0in;
|
||||
margin-inline-start: 0in;
|
||||
}
|
||||
|
||||
.transaction-table .transaction-table-column-tags .v-chip.transaction-tag {
|
||||
margin-right: 4px;
|
||||
margin-inline-end: 4px;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<div class="d-flex align-center justify-center">
|
||||
<div class="d-flex w-100 align-center justify-center">
|
||||
<h4 class="text-h4">{{ tt('Import Transactions') }}</h4>
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="loading"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="loading"></v-progress-circular>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:icon="true" :disabled="loading || submitting"
|
||||
v-if="currentStep === 'defineColumn'">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
@@ -22,7 +22,7 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:icon="true" :disabled="loading || submitting"
|
||||
v-if="currentStep === 'checkData'">
|
||||
<v-icon :icon="mdiFilterOutline" />
|
||||
@@ -110,7 +110,7 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:icon="true" :disabled="loading || submitting"
|
||||
v-if="currentStep === 'checkData'">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
@@ -281,9 +281,9 @@
|
||||
<v-col cols="12" md="12" class="mb-0 pb-0" v-if="exportFileGuideDocumentUrl">
|
||||
<a :href="exportFileGuideDocumentUrl" :class="{ 'disabled': submitting }" target="_blank">
|
||||
<v-icon :icon="mdiHelpCircleOutline" size="16" />
|
||||
<span class="ml-1" v-if="fileType === 'dsv' || fileType === 'dsv_data'">{{ tt('How to import this file?') }}</span>
|
||||
<span class="ml-1" v-if="fileType !== 'dsv' && fileType !== 'dsv_data'">{{ tt('How to export this file?') }}</span>
|
||||
<span class="ml-1" v-if="exportFileGuideDocumentLanguageName">[{{ exportFileGuideDocumentLanguageName }}]</span>
|
||||
<span class="ms-1" v-if="fileType === 'dsv' || fileType === 'dsv_data'">{{ tt('How to import this file?') }}</span>
|
||||
<span class="ms-1" v-if="fileType !== 'dsv' && fileType !== 'dsv_data'">{{ tt('How to export this file?') }}</span>
|
||||
<span class="ms-1" v-if="exportFileGuideDocumentLanguageName">[{{ exportFileGuideDocumentLanguageName }}]</span>
|
||||
</a>
|
||||
</v-col>
|
||||
</v-row>
|
||||
@@ -332,10 +332,10 @@
|
||||
<v-btn color="secondary" density="compact" variant="outlined"
|
||||
:append-icon="parsedFileDataColumnMapping.includeHeader ? mdiCheck : mdiClose"
|
||||
@click="parsedFileDataColumnMapping.toggleIncludeHeader()">{{ tt('Include Header Line') }}</v-btn>
|
||||
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
|
||||
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
|
||||
:disabled="!parsedFileDataColumnMapping || !parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionType) || !parsedFileAllTransactionTypes">
|
||||
<span>{{ tt('Transaction Type Mapping') }}</span>
|
||||
<span class="ml-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionType) && parsedFileAllTransactionTypes">({{ getObjectOwnFieldCount(parsedFileValidMappedTransactionTypes) || tt('None') }})</span>
|
||||
<span class="ms-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionType) && parsedFileAllTransactionTypes">({{ getObjectOwnFieldCount(parsedFileValidMappedTransactionTypes) || tt('None') }})</span>
|
||||
<v-menu eager activator="parent" location="bottom" max-height="500"
|
||||
:close-on-content-click="false">
|
||||
<v-list class="pa-0">
|
||||
@@ -363,10 +363,10 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
|
||||
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
|
||||
:disabled="!parsedFileDataColumnMapping || !parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTime)">
|
||||
<span>{{ tt('Time Format') }}</span>
|
||||
<span class="ml-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTime)">({{ parsedFileDataColumnMapping.timeFormat || parsedFileAutoDetectedTimeFormat || tt('Unknown') }})</span>
|
||||
<span class="ms-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTime)">({{ parsedFileDataColumnMapping.timeFormat || parsedFileAutoDetectedTimeFormat || tt('Unknown') }})</span>
|
||||
<v-menu eager activator="parent" location="bottom" max-height="500">
|
||||
<v-list>
|
||||
<v-list-item key="auto"
|
||||
@@ -374,8 +374,8 @@
|
||||
@click="parsedFileDataColumnMapping.timeFormat = ''">
|
||||
<v-list-item-title class="cursor-pointer">
|
||||
<span>{{ tt('Auto detect') }}</span>
|
||||
<span class="ml-1" v-if="parsedFileAutoDetectedTimeFormat">({{ parsedFileAutoDetectedTimeFormat }})</span>
|
||||
<span class="ml-1" v-if="!parsedFileAutoDetectedTimeFormat">({{ tt('Unknown') }})</span>
|
||||
<span class="ms-1" v-if="parsedFileAutoDetectedTimeFormat">({{ parsedFileAutoDetectedTimeFormat }})</span>
|
||||
<span class="ms-1" v-if="!parsedFileAutoDetectedTimeFormat">({{ tt('Unknown') }})</span>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item :key="dateTimeFormat.format"
|
||||
@@ -389,10 +389,10 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
|
||||
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
|
||||
v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTimezone)">
|
||||
<span>{{ tt('Timezone Format') }}</span>
|
||||
<span class="ml-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTimezone)">({{ KnownDateTimezoneFormat.valueOf(parsedFileDataColumnMapping.timezoneFormat || parsedFileAutoDetectedTimezoneFormat || '')?.name || tt('Unknown') }})</span>
|
||||
<span class="ms-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTimezone)">({{ KnownDateTimezoneFormat.valueOf(parsedFileDataColumnMapping.timezoneFormat || parsedFileAutoDetectedTimezoneFormat || '')?.name || tt('Unknown') }})</span>
|
||||
<v-menu eager activator="parent" location="bottom" max-height="500">
|
||||
<v-list>
|
||||
<v-list-item key="auto"
|
||||
@@ -400,8 +400,8 @@
|
||||
@click="parsedFileDataColumnMapping.timezoneFormat = ''">
|
||||
<v-list-item-title class="cursor-pointer">
|
||||
<span>{{ tt('Auto detect') }}</span>
|
||||
<span class="ml-1" v-if="parsedFileAutoDetectedTimezoneFormat && KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')">({{ KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')?.name }})</span>
|
||||
<span class="ml-1" v-if="!parsedFileAutoDetectedTimezoneFormat || !KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')">({{ tt('Unknown') }})</span>
|
||||
<span class="ms-1" v-if="parsedFileAutoDetectedTimezoneFormat && KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')">({{ KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')?.name }})</span>
|
||||
<span class="ms-1" v-if="!parsedFileAutoDetectedTimezoneFormat || !KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')">({{ tt('Unknown') }})</span>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item :key="timezoneFormat.value"
|
||||
@@ -415,10 +415,10 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
|
||||
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
|
||||
:disabled="!parsedFileDataColumnMapping || !parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.Amount)">
|
||||
<span>{{ tt('Amount Format') }}</span>
|
||||
<span class="ml-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.Amount)">({{ KnownAmountFormat.valueOf(parsedFileDataColumnMapping.amountFormat || parsedFileAutoDetectedAmountFormat || '')?.format || tt('Unknown') }})</span>
|
||||
<span class="ms-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.Amount)">({{ KnownAmountFormat.valueOf(parsedFileDataColumnMapping.amountFormat || parsedFileAutoDetectedAmountFormat || '')?.format || tt('Unknown') }})</span>
|
||||
<v-menu eager activator="parent" location="bottom" max-height="500">
|
||||
<v-list>
|
||||
<v-list-item key="auto"
|
||||
@@ -426,8 +426,8 @@
|
||||
@click="parsedFileDataColumnMapping.amountFormat = ''">
|
||||
<v-list-item-title class="cursor-pointer">
|
||||
<span>{{ tt('Auto detect') }}</span>
|
||||
<span class="ml-1" v-if="parsedFileAutoDetectedAmountFormat && KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')">({{ KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')?.format }})</span>
|
||||
<span class="ml-1" v-if="!parsedFileAutoDetectedAmountFormat || !KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')">({{ tt('Unknown') }})</span>
|
||||
<span class="ms-1" v-if="parsedFileAutoDetectedAmountFormat && KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')">({{ KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')?.format }})</span>
|
||||
<span class="ms-1" v-if="!parsedFileAutoDetectedAmountFormat || !KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')">({{ tt('Unknown') }})</span>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item :key="amountFormat.type"
|
||||
@@ -441,10 +441,10 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
|
||||
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
|
||||
v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.GeographicLocation)">
|
||||
<span>{{ tt('Geographic Location Separator') }}</span>
|
||||
<span class="ml-1" v-if="parsedFileDataColumnMapping.geoLocationOrder">({{ parsedFileDataColumnMapping.formatGeoLocation(tt('Latitude'), tt('Longitude')) }})</span>
|
||||
<span class="ms-1" v-if="parsedFileDataColumnMapping.geoLocationOrder">({{ parsedFileDataColumnMapping.formatGeoLocation(tt('Latitude'), tt('Longitude')) }})</span>
|
||||
<v-menu eager activator="parent" location="bottom" max-height="500"
|
||||
:close-on-content-click="false">
|
||||
<v-list class="pa-0">
|
||||
@@ -475,10 +475,10 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
|
||||
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
|
||||
v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.Tags)">
|
||||
<span>{{ tt('Transaction Tags Separator') }}</span>
|
||||
<span class="ml-1" v-if="parsedFileDataColumnMapping.tagSeparator">({{ parsedFileDataColumnMapping.tagSeparator }})</span>
|
||||
<span class="ms-1" v-if="parsedFileDataColumnMapping.tagSeparator">({{ parsedFileDataColumnMapping.tagSeparator }})</span>
|
||||
<v-menu eager activator="parent" location="bottom" max-height="500">
|
||||
<v-list>
|
||||
<v-list-item :key="separator.value"
|
||||
@@ -494,7 +494,7 @@
|
||||
</v-btn>
|
||||
<v-spacer/>
|
||||
<span>{{ tt('Lines Per Page') }}</span>
|
||||
<v-select class="ml-2" density="compact" max-width="100"
|
||||
<v-select class="ms-2" density="compact" max-width="100"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
:disabled="loading || submitting"
|
||||
@@ -590,7 +590,7 @@
|
||||
</template>
|
||||
<template #item.time="{ item }">
|
||||
<span>{{ getDisplayDateTime(item) }}</span>
|
||||
<v-chip class="ml-1" variant="flat" color="secondary" size="x-small"
|
||||
<v-chip class="ms-1" variant="flat" color="secondary" size="x-small"
|
||||
v-if="item.utcOffset !== currentTimezoneOffsetMinutes">{{ getDisplayTimezone(item) }}</v-chip>
|
||||
</template>
|
||||
<template #item.type="{ value }">
|
||||
@@ -607,11 +607,11 @@
|
||||
:icon-id="allCategoriesMap[item.categoryId].icon"
|
||||
:color="allCategoriesMap[item.categoryId].color"
|
||||
v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]"></ItemIcon>
|
||||
<span class="ml-2" v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]">
|
||||
<span class="ms-2" v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]">
|
||||
{{ allCategoriesMap[item.categoryId].name }}
|
||||
</span>
|
||||
<div class="text-error font-italic" v-else-if="item.type !== TransactionType.ModifyBalance && (!item.categoryId || item.categoryId === '0' || !allCategoriesMap[item.categoryId])">
|
||||
<v-icon class="mr-1" :icon="mdiAlertOutline"/>
|
||||
<v-icon class="me-1" :icon="mdiAlertOutline"/>
|
||||
<span>{{ item.originalCategoryName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -672,20 +672,20 @@
|
||||
</template>
|
||||
<template #item.sourceAmount="{ item }">
|
||||
<span>{{ getTransactionDisplayAmount(item) }}</span>
|
||||
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId"></v-icon>
|
||||
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId"></v-icon>
|
||||
<span v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId">{{ getTransactionDisplayDestinationAmount(item) }}</span>
|
||||
</template>
|
||||
<template #item.actualSourceAccountName="{ item }">
|
||||
<div class="d-flex align-center" v-if="editingTransaction !== item">
|
||||
<span v-if="item.sourceAccountId && item.sourceAccountId !== '0' && allAccountsMap[item.sourceAccountId]">{{ allAccountsMap[item.sourceAccountId].name }}</span>
|
||||
<div class="text-error font-italic" v-else>
|
||||
<v-icon class="mr-1" :icon="mdiAlertOutline"/>
|
||||
<v-icon class="me-1" :icon="mdiAlertOutline"/>
|
||||
<span>{{ item.originalSourceAccountName }}</span>
|
||||
</div>
|
||||
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
|
||||
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
|
||||
<span v-if="item.type === TransactionType.Transfer && item.destinationAccountId && item.destinationAccountId !== '0' && allAccountsMap[item.destinationAccountId]">{{allAccountsMap[item.destinationAccountId].name }}</span>
|
||||
<div class="text-error font-italic" v-else-if="item.type === TransactionType.Transfer && (!item.destinationAccountId || item.destinationAccountId === '0' || !allAccountsMap[item.destinationAccountId])">
|
||||
<v-icon class="mr-1" :icon="mdiAlertOutline"/>
|
||||
<v-icon class="me-1" :icon="mdiAlertOutline"/>
|
||||
<span>{{ item.originalDestinationAccountName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -706,7 +706,7 @@
|
||||
:items="allVisibleCategorizedAccounts"
|
||||
v-model="item.sourceAccountId">
|
||||
</two-column-select>
|
||||
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
|
||||
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
|
||||
<two-column-select density="compact" variant="plain"
|
||||
primary-key-field="id" primary-value-field="category"
|
||||
primary-title-field="name" primary-footer-field="displayBalance"
|
||||
@@ -790,7 +790,7 @@
|
||||
</span>
|
||||
<v-spacer/>
|
||||
<span>{{ tt('Transactions Per Page') }}</span>
|
||||
<v-select class="ml-2" density="compact" max-width="100"
|
||||
<v-select class="ms-2" density="compact" max-width="100"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
:disabled="loading || submitting"
|
||||
@@ -815,17 +815,19 @@
|
||||
<v-btn color="secondary" variant="tonal" :disabled="loading || submitting"
|
||||
:prepend-icon="mdiClose" @click="close(false)"
|
||||
v-if="currentStep !== 'finalResult'">{{ tt('Cancel') }}</v-btn>
|
||||
<v-btn color="primary" :disabled="loading || submitting || (!isImportDataFromTextbox && !importFile) || (isImportDataFromTextbox && !importData)"
|
||||
<v-btn class="button-icon-with-direction" color="primary"
|
||||
:disabled="loading || submitting || (!isImportDataFromTextbox && !importFile) || (isImportDataFromTextbox && !importData)"
|
||||
:append-icon="!submitting ? mdiArrowRight : undefined" @click="parseData"
|
||||
v-if="currentStep === 'defineColumn' || currentStep === 'uploadFile'">
|
||||
{{ tt('Next') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn color="teal" :disabled="submitting || !!editingTransaction || selectedImportTransactionCount < 1 || selectedInvalidTransactionCount > 0"
|
||||
<v-btn class="button-icon-with-direction" color="teal"
|
||||
:disabled="submitting || !!editingTransaction || selectedImportTransactionCount < 1 || selectedInvalidTransactionCount > 0"
|
||||
:append-icon="!submitting ? mdiArrowRight : undefined" @click="submit"
|
||||
v-if="currentStep === 'checkData'">
|
||||
{{ (submitting && importProcess > 0 ? tt('format.misc.importingTransactions', { process: formatNumberToLocalizedNumerals(importProcess, 2) }) : tt('Import')) }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn color="secondary" variant="tonal"
|
||||
:append-icon="mdiCheck"
|
||||
@@ -2748,7 +2750,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
.import-transaction-table .v-chip.transaction-tag {
|
||||
margin-right: 4px;
|
||||
margin-inline-end: 4px;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<h4 class="text-h4" v-if="type === 'transferCategory'">{{ tt('Create Nonexistent Transfer Categories') }}</h4>
|
||||
<h4 class="text-h4" v-if="type === 'tag'">{{ tt('Create Nonexistent Transaction Tags') }}</h4>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:disabled="submitting || !invalidItems || !invalidItems.length" :icon="true">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -53,7 +53,7 @@
|
||||
<div class="w-100 d-flex justify-center gap-4">
|
||||
<v-btn :disabled="submitting || !selectedNames || !selectedNames.length" @click="confirm">
|
||||
{{ tt('OK') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn color="secondary" variant="tonal" :disabled="submitting" @click="cancel">{{ tt('Cancel') }}</v-btn>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="d-flex w-100 align-center justify-center">
|
||||
<h4 class="text-h4">{{ tt('Batch Replace Categories / Accounts / Tags') }}</h4>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :disabled="loading"
|
||||
class="ms-2" :icon="true" :disabled="loading"
|
||||
:loading="loading" @click="reload">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
@@ -15,7 +15,7 @@
|
||||
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:icon="true" :disabled="loading">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent" max-height="500">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<h4 class="text-h4" v-if="mode === 'replaceInvalidItems' && type === 'account'">{{ tt('Replace Invalid Accounts') }}</h4>
|
||||
<h4 class="text-h4" v-if="mode === 'replaceInvalidItems' && type === 'tag'">{{ tt('Replace Invalid Transaction Tags') }}</h4>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :disabled="loading"
|
||||
class="ms-2" :icon="true" :disabled="loading"
|
||||
:loading="loading" @click="reload">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<div class="d-flex align-center justify-center">
|
||||
<div class="d-flex w-100 align-center justify-center">
|
||||
<h4 class="text-h4">{{ tt(title) }}</h4>
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="loading"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="loading"></v-progress-circular>
|
||||
</div>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ml-2" :icon="true"
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2" :icon="true"
|
||||
:disabled="loading || submitting" v-if="mode !== TransactionEditPageMode.View && (activeTab === 'basicInfo' || (activeTab === 'map' && isSupportGetGeoLocationByClick()))">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
@@ -80,7 +80,7 @@
|
||||
</v-tabs>
|
||||
</div>
|
||||
|
||||
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container ml-md-5"
|
||||
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container ms-md-5"
|
||||
v-model="activeTab">
|
||||
<v-window-item value="basicInfo">
|
||||
<v-form class="mt-2">
|
||||
@@ -454,7 +454,7 @@
|
||||
<v-btn :disabled="inputIsEmpty || loading || submitting"
|
||||
v-if="mode !== TransactionEditPageMode.View" @click="save">
|
||||
{{ tt(saveButtonTitle) }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
@@ -485,7 +485,7 @@
|
||||
<v-btn color="error" variant="tonal" :disabled="loading || submitting"
|
||||
v-if="mode === TransactionEditPageMode.View && originalTransactionEditable" @click="remove">
|
||||
{{ tt('Delete') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn color="secondary" variant="tonal" :disabled="loading || submitting"
|
||||
@click="cancel">{{ tt(cancelButtonTitle) }}</v-btn>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<div ref="buttonContainer" class="w-100 d-flex justify-center gap-4">
|
||||
<v-btn :disabled="generating || !currentPassword" @click="generateToken" v-if="!generatedToken">
|
||||
{{ tt('Generate') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="generating"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="generating"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn color="secondary" variant="tonal" :disabled="generating"
|
||||
@click="cancel" v-if="!generatedToken">{{ tt('Cancel') }}</v-btn>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<v-card :class="{ 'disabled': loading || saving }">
|
||||
<template #title>
|
||||
<span>{{ tt('Basic Settings') }}</span>
|
||||
<v-progress-circular indeterminate size="20" class="ml-3" v-if="loading"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="20" class="ms-3" v-if="loading"></v-progress-circular>
|
||||
</template>
|
||||
|
||||
<v-card-text class="d-flex">
|
||||
@@ -38,10 +38,10 @@
|
||||
<div class="d-flex text-body-1 align-center" style="height: 40px;">
|
||||
<span v-if="!loading && emailVerified">{{ tt('Email address is verified') }}</span>
|
||||
<span v-if="!loading && !emailVerified">{{ tt('Email address is not verified') }}</span>
|
||||
<v-btn class="ml-2 px-2" size="small" variant="text" :disabled="loading || resending"
|
||||
<v-btn class="ms-2 px-2" size="small" variant="text" :disabled="loading || resending"
|
||||
@click="resendVerifyEmail" v-if="isUserVerifyEmailEnabled() && !loading && !emailVerified">
|
||||
{{ tt('Resend Validation Email') }}
|
||||
<v-progress-circular indeterminate size="18" class="ml-2" v-if="resending"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="18" class="ms-2" v-if="resending"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-skeleton-loader class="skeleton-no-margin mt-2 mb-1" type="text" style="width: 160px" :loading="true" v-if="loading"></v-skeleton-loader>
|
||||
</div>
|
||||
@@ -351,7 +351,7 @@
|
||||
<v-card-text class="d-flex flex-wrap gap-4">
|
||||
<v-btn :disabled="inputIsNotChanged || inputIsInvalid || saving" @click="save">
|
||||
{{ tt('Save Changes') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="saving"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="saving"></v-progress-circular>
|
||||
</v-btn>
|
||||
|
||||
<v-btn color="default" variant="tonal" @click="reset">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="d-flex align-center">
|
||||
<span>{{ tt('Data Management') }}</span>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loadingDataStatistics" @click="reloadUserDataStatistics(true)">
|
||||
class="ms-2" :icon="true" :loading="loadingDataStatistics" @click="reloadUserDataStatistics(true)">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
@@ -91,7 +91,7 @@
|
||||
<v-btn-group variant="elevated" density="comfortable" color="primary">
|
||||
<v-btn :disabled="loadingDataStatistics || exportingData || !dataStatistics || !dataStatistics.totalTransactionCount || dataStatistics.totalTransactionCount === '0'">
|
||||
{{ tt('Export Data') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="exportingData"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="exportingData"></v-progress-circular>
|
||||
<v-menu activator="parent">
|
||||
<v-list :disabled="loadingDataStatistics || exportingData || !dataStatistics || !dataStatistics.totalTransactionCount || dataStatistics.totalTransactionCount === '0'">
|
||||
<v-list-item @click="exportData('csv')">
|
||||
@@ -143,7 +143,7 @@
|
||||
<v-card-text class="d-flex flex-wrap gap-4">
|
||||
<v-btn color="error" :disabled="loadingDataStatistics || !currentPasswordForClearData || clearingData" @click="clearData">
|
||||
{{ tt('Clear User Data') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="clearingData"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="clearingData"></v-progress-circular>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-form>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<v-card-text class="d-flex flex-wrap gap-4">
|
||||
<v-btn :disabled="!currentPassword || !newPassword || !confirmPassword || updatingPassword" @click="updatePassword">
|
||||
{{ tt('Save Changes') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="updatingPassword"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="updatingPassword"></v-progress-circular>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-form>
|
||||
@@ -68,10 +68,10 @@
|
||||
<template #title>
|
||||
<div class="d-flex align-center">
|
||||
<span>{{ tt('Device & Sessions') }}</span>
|
||||
<v-btn class="ml-3" density="compact" color="default" variant="outlined"
|
||||
<v-btn class="ms-3" density="compact" color="default" variant="outlined"
|
||||
@click="generateMCPToken" v-if="isMCPServerEnabled()">{{ tt('Generate MCP token') }}</v-btn>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loadingSession" @click="reloadSessions(false)">
|
||||
class="ms-2" :icon="true" :loading="loadingSession" @click="reloadSessions(false)">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<v-card :class="{ 'disabled': loading }">
|
||||
<template #title>
|
||||
<span>{{ tt('Two-Factor Authentication') }}</span>
|
||||
<v-progress-circular indeterminate size="20" class="ml-3" v-if="loading"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="20" class="ms-3" v-if="loading"></v-progress-circular>
|
||||
</template>
|
||||
|
||||
<v-card-text class="pb-0">
|
||||
@@ -57,19 +57,19 @@
|
||||
<v-col cols="12" class="d-flex flex-wrap gap-4">
|
||||
<v-btn :disabled="!currentPassword || loading || disabling " v-if="status === true" @click="disable">
|
||||
{{ tt('Disable Two-Factor Authentication') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="disabling"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="disabling"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn :disabled="!currentPassword || loading || regenerating" v-if="status === true" @click="regenerateBackupCode()">
|
||||
{{ tt('Regenerate Backup Codes') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="regenerating"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="regenerating"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn :disabled="loading || enabling" v-if="status === false && !new2FAQRCode" @click="enable">
|
||||
{{ tt('Enable Two-Factor Authentication') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="enabling"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="enabling"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn :disabled="!currentPasscode || loading || enableConfirming" v-if="status === false && new2FAQRCode" @click="enableConfirm">
|
||||
{{ tt('Continue') }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="enableConfirming"></v-progress-circular>
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="enableConfirming"></v-progress-circular>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
@@ -82,7 +82,7 @@
|
||||
<template #title>
|
||||
<span>{{ tt('Backup Code') }}</span>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" @click="copyBackupCodes">
|
||||
class="ms-2" :icon="true" @click="copyBackupCodes">
|
||||
<v-icon :icon="mdiContentCopy" size="20" />
|
||||
<v-tooltip activator="parent">{{ tt('Copy') }}</v-tooltip>
|
||||
</v-btn>
|
||||
|
||||
Reference in New Issue
Block a user