Implement accounts combobox

This commit is contained in:
RunasSudo 2024-11-22 19:19:55 +11:00
parent 40945def3e
commit 071d7c8988
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
5 changed files with 105 additions and 13 deletions

View File

@ -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,

View File

@ -0,0 +1,53 @@
<!--
DrCr: Web-based double-entry bookkeeping framework
Copyright (C) 20222024 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>

View File

@ -0,0 +1,46 @@
<!--
DrCr: Web-based double-entry bookkeeping framework
Copyright (C) 20222024 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>

View File

@ -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,

View File

@ -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';