Implement accounts combobox
This commit is contained in:
parent
40945def3e
commit
071d7c8988
@ -27,10 +27,7 @@
|
|||||||
<input type="text" class="bordered-field" id="description" v-model="assertion.description" placeholder=" ">
|
<input type="text" class="bordered-field" id="description" v-model="assertion.description" placeholder=" ">
|
||||||
</div>
|
</div>
|
||||||
<label for="account" class="block text-gray-900 pr-4">Account</label>
|
<label for="account" class="block text-gray-900 pr-4">Account</label>
|
||||||
<div class="relative combobox">
|
<ComboBoxAccounts v-model="assertion.account" />
|
||||||
<input type="text" class="bordered-field peer" id="account" v-model="assertion.account" placeholder=" " autocomplete="off">
|
|
||||||
<!--{% include 'components/accounts_combobox_inner.html' %}-->
|
|
||||||
</div>
|
|
||||||
<label for="amount" class="block text-gray-900 pr-4">Balance</label>
|
<label for="amount" class="block text-gray-900 pr-4">Balance</label>
|
||||||
<div class="relative shadow-sm">
|
<div class="relative shadow-sm">
|
||||||
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
||||||
@ -61,6 +58,7 @@
|
|||||||
import { defineProps } from 'vue';
|
import { defineProps } from 'vue';
|
||||||
|
|
||||||
import { DT_FORMAT, db, deserialiseAmount } from '../db.ts';
|
import { DT_FORMAT, db, deserialiseAmount } from '../db.ts';
|
||||||
|
import ComboBoxAccounts from './ComboBoxAccounts.vue';
|
||||||
|
|
||||||
export interface EditingAssertion {
|
export interface EditingAssertion {
|
||||||
id: number | null,
|
id: number | null,
|
||||||
|
53
src/components/ComboBox.vue
Normal file
53
src/components/ComboBox.vue
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<!--
|
||||||
|
DrCr: Web-based double-entry bookkeeping framework
|
||||||
|
Copyright (C) 2022–2024 Lee Yingtong Li (RunasSudo)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="relative">
|
||||||
|
<!-- WebKit bug: Does not align baseline correctly unless some text or placeholder is present -->
|
||||||
|
<input type="text" class="bordered-field peer" :class="inputClass" id="account" v-model="selectedValue" placeholder=" " autocomplete="off" ref="inputField">
|
||||||
|
<button type="button" class="absolute inset-y-0 right-0 flex items-center px-2 focus:outline-none" @click="inputField!.focus()">
|
||||||
|
<ChevronUpDownIcon class="h-5 w-5 text-gray-400" />
|
||||||
|
</button>
|
||||||
|
<ul class="hidden peer-focus:block absolute z-20 mt-1 max-h-60 w-full overflow-auto bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm" v-if="values.length > 0">
|
||||||
|
<li
|
||||||
|
v-for="value in values"
|
||||||
|
v-show="value.toLowerCase().startsWith(selectedValue.toLowerCase())"
|
||||||
|
class="group relative cursor-default select-none py-1 pl-3 pr-9 text-gray-900 hover:text-white hover:bg-emerald-600 wk-aa"
|
||||||
|
:data-selected="value === selectedValue ? 'selected': ''"
|
||||||
|
@mousedown="selectedValue = value"
|
||||||
|
>
|
||||||
|
<span class="block truncate group-data-[selected=selected]:font-semibold">{{ value }}</span>
|
||||||
|
<span class="hidden group-data-[selected=selected]:flex absolute inset-y-0 right-0 items-center pr-4 text-emerald-600 group-hover:text-white">
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ChevronUpDownIcon } from '@heroicons/vue/24/outline';
|
||||||
|
import { defineModel, defineProps, useTemplateRef } from 'vue';
|
||||||
|
|
||||||
|
const { values, inputClass } = defineProps<{ values: string[], inputClass?: string }>();
|
||||||
|
const inputField = useTemplateRef('inputField');
|
||||||
|
|
||||||
|
const selectedValue = defineModel({ default: '' });
|
||||||
|
</script>
|
46
src/components/ComboBoxAccounts.vue
Normal file
46
src/components/ComboBoxAccounts.vue
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<!--
|
||||||
|
DrCr: Web-based double-entry bookkeeping framework
|
||||||
|
Copyright (C) 2022–2024 Lee Yingtong Li (RunasSudo)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ComboBox :values="accounts" :inputClass="inputClass" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineProps, ref } from 'vue';
|
||||||
|
|
||||||
|
import { db } from '../db.ts';
|
||||||
|
import ComboBox from './ComboBox.vue';
|
||||||
|
|
||||||
|
const { inputClass } = defineProps<{ inputClass?: string }>();
|
||||||
|
|
||||||
|
const accounts = ref([] as string[]);
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
// Load account names
|
||||||
|
const session = await db.load();
|
||||||
|
|
||||||
|
const rawAccounts: {account: string}[] = await session.select(
|
||||||
|
`SELECT DISTINCT account
|
||||||
|
FROM postings
|
||||||
|
ORDER BY account`
|
||||||
|
);
|
||||||
|
|
||||||
|
accounts.value = rawAccounts.map((a) => a.account);
|
||||||
|
}
|
||||||
|
load();
|
||||||
|
</script>
|
@ -49,10 +49,7 @@
|
|||||||
<option value="cr">Cr</option>
|
<option value="cr">Cr</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative combobox w-full">
|
<ComboBoxAccounts v-model="posting.account" class="w-full" inputClass="pl-16" />
|
||||||
<input type="text" class="bordered-field pl-16 peer" v-model="posting.account">
|
|
||||||
<!-- TODO: Accounts combobox -->
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="relative -ml-px px-2 py-2 text-gray-500 hover:text-gray-700" @click="addPosting(posting)">
|
<button class="relative -ml-px px-2 py-2 text-gray-500 hover:text-gray-700" @click="addPosting(posting)">
|
||||||
<PlusIcon class="w-4 h-4" />
|
<PlusIcon class="w-4 h-4" />
|
||||||
@ -112,6 +109,7 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
import { DT_FORMAT, Transaction, db, deserialiseAmount } from '../db.ts';
|
import { DT_FORMAT, Transaction, db, deserialiseAmount } from '../db.ts';
|
||||||
|
import ComboBoxAccounts from './ComboBoxAccounts.vue';
|
||||||
|
|
||||||
interface EditingPosting {
|
interface EditingPosting {
|
||||||
id: number | null,
|
id: number | null,
|
||||||
|
@ -30,11 +30,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<label for="account" class="block text-gray-900 pr-4">Source account</label>
|
<label for="account" class="block text-gray-900 pr-4">Source account</label>
|
||||||
<div class="relative combobox">
|
<ComboBoxAccounts v-model="sourceAccount" />
|
||||||
<!-- WebKit bug: Does not align baseline correctly unless some text or placeholder is present -->
|
|
||||||
<input type="text" class="bordered-field peer" id="account" placeholder=" " autocomplete="off" v-model="sourceAccount">
|
|
||||||
<!--{% include 'components/accounts_combobox_inner.html' %}-->
|
|
||||||
</div>
|
|
||||||
<label for="file" class="block text-gray-900 pr-4">File</label>
|
<label for="file" class="block text-gray-900 pr-4">File</label>
|
||||||
<div class="flex grow">
|
<div class="flex grow">
|
||||||
<!-- WebKit: file:hidden hides the filename as well so we have a dummy text input -->
|
<!-- WebKit: file:hidden hides the filename as well so we have a dummy text input -->
|
||||||
@ -87,6 +83,7 @@
|
|||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { StatementLine, db } from '../db.ts';
|
import { StatementLine, db } from '../db.ts';
|
||||||
|
import ComboBoxAccounts from '../components/ComboBoxAccounts.vue';
|
||||||
import { ppWithCommodity } from '../display.ts';
|
import { ppWithCommodity } from '../display.ts';
|
||||||
import import_ofx2 from '../importers/ofx2.ts';
|
import import_ofx2 from '../importers/ofx2.ts';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user