Compare commits
4 Commits
sync
...
dba38f71b1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dba38f71b1 | ||
| 0e0b0bf8a2 | |||
| 20458288c2 | |||
| 7bb363d790 |
@@ -50,14 +50,13 @@ wails3 generate bindings -ts
|
|||||||
Для финальной сборки запустите эту команду в директории проекта:
|
Для финальной сборки запустите эту команду в директории проекта:
|
||||||
|
|
||||||
```
|
```
|
||||||
go env -w CGO_ENABLED=1
|
PRODUCTION=true wails3 build
|
||||||
wails3 build -clean -upx -v 2 -webview2 embed
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Перед релизом не забыть**:
|
**Перед релизом не забыть**:
|
||||||
|
- убедиться, что дефолтные данные правильные
|
||||||
- поместить все нужные asset'ы в папку assets
|
- убедиться, что приложение запускается
|
||||||
- изменить версию схемы БД (пока не нужно)
|
- (опционально) поместить все нужные asset'ы в папку assets
|
||||||
- приложить сопроводительную записку.
|
- приложить сопроводительную записку.
|
||||||
|
|
||||||
## Работа без GitHub
|
## Работа без GitHub
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ tasks:
|
|||||||
cmds:
|
cmds:
|
||||||
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
|
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
|
||||||
vars:
|
vars:
|
||||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -ldflags="-w -s"{{else}}-gcflags=all="-l"{{end}}'
|
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags "production sqlite_icu" -trimpath -ldflags="-w -s"{{else}}-gcflags=all="-l" -tags "sqlite_icu"{{end}}'
|
||||||
env:
|
env:
|
||||||
GOOS: darwin
|
GOOS: darwin
|
||||||
CGO_ENABLED: 1
|
CGO_ENABLED: 1
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ tasks:
|
|||||||
cmds:
|
cmds:
|
||||||
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
|
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
|
||||||
vars:
|
vars:
|
||||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -ldflags="-w -s"{{else}}-gcflags=all="-l"{{end}}'
|
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags "production sqlite_icu" -trimpath -ldflags="-w -s"{{else}}-gcflags=all="-l" -tags "sqlite_icu" {{end}}'
|
||||||
env:
|
env:
|
||||||
GOOS: linux
|
GOOS: linux
|
||||||
CGO_ENABLED: 1
|
CGO_ENABLED: 1
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ tasks:
|
|||||||
- cmd: rm -f *.syso
|
- cmd: rm -f *.syso
|
||||||
platforms: [linux, darwin]
|
platforms: [linux, darwin]
|
||||||
vars:
|
vars:
|
||||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -ldflags="-w -s -H windowsgui"{{else}}-gcflags=all="-l"{{end}}'
|
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags "production sqlite_icu" -trimpath -ldflags="-w -s -H windowsgui"{{else}}-gcflags=all="-l" -tags "sqlite_icu"{{end}}'
|
||||||
env:
|
env:
|
||||||
GOOS: windows
|
GOOS: windows
|
||||||
CGO_ENABLED: 1
|
CGO_ENABLED: 1
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ const load = async () => {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await load();
|
await load();
|
||||||
console.log(await SortedByOrder({"Comments": "DESC"}))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const scheme: Scheme<Author> = reactive({
|
const scheme: Scheme<Author> = reactive({
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ const pushOrRemove = (option: T) => {
|
|||||||
} else {
|
} else {
|
||||||
selected.value.push(option)
|
selected.value.push(option)
|
||||||
}
|
}
|
||||||
//setNullIds()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const setNullIds = () => {
|
const setNullIds = () => {
|
||||||
@@ -27,12 +26,11 @@ const setNullIds = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//onMounted(setNullIds)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="">
|
<div class="">
|
||||||
<ul class="max-h-48 h-auto overflow-y-auto background rounded-md p-3 w-full border-gray-500 border">
|
<ul class="max-h-48 h-auto overflow-y-auto background rounded-md p-3 w-full native-border">
|
||||||
<li v-for="option in options" :key="option.Id" class="flex items-center gap-2">
|
<li v-for="option in options" :key="option.Id" class="flex items-center gap-2">
|
||||||
<Checkbox :checked="selected.some(item => item.Id == option.Id)" @click="pushOrRemove(option)" />
|
<Checkbox :checked="selected.some(item => item.Id == option.Id)" @click="pushOrRemove(option)" />
|
||||||
<label :for="option.Id.toString()">{{ structView(option, path) }}</label>
|
<label :for="option.Id.toString()">{{ structView(option, path) }}</label>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Table from "../table/Table.vue";
|
import Table from "../table/Table.vue";
|
||||||
import { onMounted, reactive } from "vue";
|
import {onMounted, reactive, watch} from "vue";
|
||||||
import { getDefaultValues } from "../utils/structs/defaults.util";
|
import { getDefaultValues } from "../utils/structs/defaults.util";
|
||||||
import Service from "./post.service.ts";
|
import Service from "./post.service.ts";
|
||||||
import type { Scheme } from "../types/scheme.type";
|
import type { Scheme } from "../types/scheme.type";
|
||||||
@@ -16,7 +16,7 @@ const posttypeService = new PosttypeService();
|
|||||||
|
|
||||||
import CommentService from "../comment/comment.service.ts";
|
import CommentService from "../comment/comment.service.ts";
|
||||||
import { SortedByOrder } from "../../bindings/app/internal/services/postservice.ts";
|
import { SortedByOrder } from "../../bindings/app/internal/services/postservice.ts";
|
||||||
import type { Search } from "../types/search.type.ts";
|
import {getDefaultSortOptions} from "../utils/structs/default-sort-options.util.ts";
|
||||||
|
|
||||||
const commentService = new CommentService();
|
const commentService = new CommentService();
|
||||||
|
|
||||||
@@ -33,13 +33,12 @@ const load = async () => {
|
|||||||
(scheme as any).Comments.type!.nested!.values =
|
(scheme as any).Comments.type!.nested!.values =
|
||||||
await commentService.readAll();
|
await commentService.readAll();
|
||||||
|
|
||||||
items.value = await service.readAll();
|
items.value = await service.sort(sortOptions.value) ;
|
||||||
return items.value;
|
return items.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await load();
|
await load();
|
||||||
console.log(await SortedByOrder({ "Author": "DESC", "Text": "ASC" }));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const scheme: Scheme<Post> = reactive({
|
const scheme: Scheme<Post> = reactive({
|
||||||
@@ -117,9 +116,6 @@ const scheme: Scheme<Post> = reactive({
|
|||||||
values: [],
|
values: [],
|
||||||
field: ["Text"],
|
field: ["Text"],
|
||||||
},
|
},
|
||||||
},
|
|
||||||
customWindow: {
|
|
||||||
create: true,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -134,15 +130,15 @@ const validate: Validate<Post> = (entity) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const search: Search<Post> = (input) => {
|
const search = async (input: string) => {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sortOptions = ref(getDefaultSortOptions(scheme))
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Table :scheme :service :get-defaults :load :items :validate @on-search="search">
|
<Table :scheme :service :get-defaults :load :items :validate @on-search="search" v-model:sort-options="sortOptions"></Table>
|
||||||
<template #CommentsCreate="{ data }">
|
|
||||||
<p>{{ data }}</p>
|
|
||||||
</template>
|
|
||||||
</Table>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import {
|
|||||||
Delete,
|
Delete,
|
||||||
GetById,
|
GetById,
|
||||||
Update,
|
Update,
|
||||||
Count,
|
Count, SortedByOrder,
|
||||||
} from "../../bindings/app/internal/services/postservice.ts";
|
} from "../../bindings/app/internal/services/postservice.ts";
|
||||||
import type { Post } from "../../bindings/app/internal/services";
|
import type { Post } from "../../bindings/app/internal/services";
|
||||||
import type { IService } from "../types/service.type.ts";
|
import type { IService } from "../types/service.type.ts";
|
||||||
|
import type {SortOptions} from "../types/sort-options.type.ts";
|
||||||
|
|
||||||
export default class PostService implements IService<Post> {
|
export default class PostService implements IService<Post> {
|
||||||
async read(id: number) {
|
async read(id: number) {
|
||||||
@@ -33,4 +34,8 @@ export default class PostService implements IService<Post> {
|
|||||||
async count() {
|
async count() {
|
||||||
return await Count();
|
return await Count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sort(options: SortOptions<Post>) {
|
||||||
|
return await SortedByOrder(options) as Post[]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,25 @@
|
|||||||
|
|
||||||
html, body, .background {
|
html, body, .background {
|
||||||
background: white;
|
background: white;
|
||||||
|
color: rgb(51, 65, 85);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary-background {
|
||||||
|
background: var(--p-content-background)
|
||||||
|
}
|
||||||
|
|
||||||
|
.native-border {
|
||||||
|
border: 1px solid var(--p-select-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
html, body, .background {
|
html, body, .background {
|
||||||
background: #121212;
|
background: #121212;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.native-border {
|
||||||
|
border: 1px solid rgb(100, 100, 109);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ async function handleSave() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Dialog v-model:visible="showCreate">
|
<Dialog v-model:visible="showCreate" class="w-[500px]">
|
||||||
<template #header>
|
<template #header>
|
||||||
<h1>{{ props.updateMode ? 'Изменить' : 'Создать' }} {{ props.name?.toLowerCase() }}</h1>
|
<h1>{{ props.updateMode ? 'Изменить' : 'Создать' }} {{ props.name?.toLowerCase() }}</h1>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
25
frontend/src/table/SortingOptions.vue
Normal file
25
frontend/src/table/SortingOptions.vue
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<script setup lang="ts" generic="T extends IEntity">
|
||||||
|
import type {IEntity} from "../types/entity.type.ts";
|
||||||
|
import type {SortOptions} from "../types/sort-options.type.ts";
|
||||||
|
import type {Scheme} from "../types/scheme.type.ts";
|
||||||
|
import {Select} from 'primevue'
|
||||||
|
import {watch} from "vue";
|
||||||
|
|
||||||
|
|
||||||
|
const options = defineModel<SortOptions<T>>()
|
||||||
|
const optionsKeys = Object.keys(options.value as T) as (keyof T)[]
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
scheme: Scheme<T>
|
||||||
|
load: () => Promise<T[]>
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ul class="flex flex-col gap-2 native-border secondary-background p-3 rounded-md">
|
||||||
|
<li v-for="optionKey in optionsKeys" class="flex items-center justify-between w-full">
|
||||||
|
<h1>{{ scheme[optionKey].russian }}</h1>
|
||||||
|
<Select size="small" class="w-24" :options="['ASC', 'DESC']" v-model="options![optionKey]" @value-change="load"></Select>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
@@ -1,20 +1,18 @@
|
|||||||
<script setup lang="ts" generic="T extends IEntity">
|
<script setup lang="ts" generic="T extends IEntity">
|
||||||
import { onMounted, ref, watch, type UnwrapRef } from "vue";
|
import {onMounted, ref, watch, type UnwrapRef} from "vue";
|
||||||
import type { TableProps } from "../types/table-props.type";
|
import type {TableProps} from "../types/table-props.type";
|
||||||
import { DataTable, Column, Button, InputText } from "primevue";
|
import {DataTable, Column, Button, InputText} from "primevue";
|
||||||
import { manyStructsView } from "../utils/structs/structs-view.util";
|
import {manyStructsView} from "../utils/structs/structs-view.util";
|
||||||
import type { TableEmits } from "../types/table-emits.type";
|
import type {TableEmits} from "../types/table-emits.type";
|
||||||
import FloatingButton from "../components/buttons/FloatingButton.vue";
|
import FloatingButton from "../components/buttons/FloatingButton.vue";
|
||||||
import type { IEntity } from "../types/entity.type";
|
import type {IEntity} from "../types/entity.type";
|
||||||
import DialogWindow from "./DialogWindow.vue";
|
import DialogWindow from "./DialogWindow.vue";
|
||||||
import { viewDate } from "../utils/date/view.util";
|
import {viewDate} from "../utils/date/view.util";
|
||||||
|
import SortingOptions from "./SortingOptions.vue";
|
||||||
|
import type {SortOptions} from "../types/sort-options.type.ts";
|
||||||
|
|
||||||
const props = defineProps<TableProps<T>>();
|
const props = defineProps<TableProps<T>>();
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
props.load();
|
|
||||||
});
|
|
||||||
|
|
||||||
type Key = keyof T;
|
type Key = keyof T;
|
||||||
const keys = Object.keys(props.scheme) as Key[];
|
const keys = Object.keys(props.scheme) as Key[];
|
||||||
const emits = defineEmits<TableEmits>();
|
const emits = defineEmits<TableEmits>();
|
||||||
@@ -56,8 +54,8 @@ watch(createItem, (value) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleFloatingButtonClick = () => {
|
const handleFloatingButtonClick = () => {
|
||||||
emits("onCreateOpen");
|
emits('onCreateOpen')
|
||||||
emits("onOpen");
|
emits('onOpen')
|
||||||
showCreate.value = true;
|
showCreate.value = true;
|
||||||
};
|
};
|
||||||
const slots = defineSlots();
|
const slots = defineSlots();
|
||||||
@@ -65,70 +63,60 @@ const slots = defineSlots();
|
|||||||
const createSlotName = (key: any) => key + "Create";
|
const createSlotName = (key: any) => key + "Create";
|
||||||
const updateSlotName = (key: any) => key + "Update";
|
const updateSlotName = (key: any) => key + "Update";
|
||||||
|
|
||||||
watch(
|
watch(() => props.items, () => {
|
||||||
() => props.items,
|
|
||||||
() => {
|
|
||||||
if (props.colorize) {
|
if (props.colorize) {
|
||||||
const trs = document.querySelectorAll("tr");
|
const trs = document.querySelectorAll("tr");
|
||||||
props.items.forEach((item) => {
|
props.items.forEach(item => {
|
||||||
const tr = trs[item.Id];
|
const tr = trs[item.Id];
|
||||||
if (tr) {
|
if (tr) {
|
||||||
tr.style.backgroundColor = props.colorize!(item);
|
tr.style.backgroundColor = props.colorize!(item);
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
);
|
|
||||||
|
const input = ref('')
|
||||||
|
const sortOptions = defineModel<SortOptions<T>>('sort-options');
|
||||||
|
const showSortOptions = ref(false)
|
||||||
|
|
||||||
const input = defineModel<string>("search", { default: "" });
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex h-10 justify-center m-4 gap-2">
|
<div class="m-2 flex flex-col items-center gap-2">
|
||||||
<InputText v-model="input" placeholder="Поиск" class="h-full w-64" />
|
<div class="flex flex-col gap-2 relative">
|
||||||
<Button class="h-full aspect-square" severity="secondary">
|
<div class="flex items-center justify-center gap-2 h-10">
|
||||||
|
<Button severity="secondary" class="h-full aspect-square" @click="showSortOptions = !showSortOptions">
|
||||||
|
<span class="pi pi-sort"></span>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<InputText class="h-full w-64" v-model="input"/>
|
||||||
|
<Button severity="secondary" class="h-full aspect-square" @click="emits('onSearch', input)">
|
||||||
<span class="pi pi-search"></span>
|
<span class="pi pi-search"></span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<DialogWindow
|
<SortingOptions v-model="sortOptions as SortOptions<T>" :scheme v-if="showSortOptions"
|
||||||
:name
|
class="absolute z-10 w-full top-full translate-y-2" :load="props.load"></SortingOptions>
|
||||||
:load
|
</div>
|
||||||
:items
|
|
||||||
:validate
|
</div>
|
||||||
:scheme
|
<DialogWindow :name :load :items :validate :scheme :service :get-defaults v-model:item="<T>createItem"
|
||||||
:service
|
v-model:show="showCreate" @on-save="data => emits('onSave', data)"
|
||||||
:get-defaults
|
@on-save-create="data => emits('onSaveCreate', data)">
|
||||||
v-model:item="<T>createItem"
|
|
||||||
v-model:show="showCreate"
|
|
||||||
@on-save="(data) => emits('onSave', data)"
|
|
||||||
@on-save-create="(data) => emits('onSaveCreate', data)"
|
|
||||||
>
|
|
||||||
<template v-for="key in keys" #[key]="{ data }">
|
<template v-for="key in keys" #[key]="{ data }">
|
||||||
<slot :name="<string>key" :data></slot>
|
<slot :name="<string>key" :data="data"></slot>
|
||||||
</template>
|
</template>
|
||||||
<template v-for="key in keys" #[createSlotName(key)]="{ data }">
|
<template v-for="key in keys" #[createSlotName(key)]="{ data }">
|
||||||
<slot :name="createSlotName(key)" :data></slot>
|
<slot :name="createSlotName(key)" :data="data"></slot>
|
||||||
</template>
|
</template>
|
||||||
</DialogWindow>
|
</DialogWindow>
|
||||||
<DialogWindow
|
<DialogWindow :name :load :items :validate :scheme update-mode :service :get-defaults v-model:item="<T>updateItem"
|
||||||
:name
|
v-model:show="showUpdate" @on-save="data => emits('onSave', data)"
|
||||||
:load
|
@on-save-update="data => emits('onSaveUpdate', data)">
|
||||||
:items
|
|
||||||
:validate
|
|
||||||
:scheme
|
|
||||||
update-mode
|
|
||||||
:service
|
|
||||||
:get-defaults
|
|
||||||
v-model:item="<T>updateItem"
|
|
||||||
v-model:show="showUpdate"
|
|
||||||
@on-save="(data) => emits('onSave', data)"
|
|
||||||
@on-save-update="(data) => emits('onSaveUpdate', data)"
|
|
||||||
>
|
|
||||||
<template v-for="key in keys" #[key]="{ data }">
|
<template v-for="key in keys" #[key]="{ data }">
|
||||||
<slot :name="<string>key" :data></slot>
|
<slot :name="<string>key" :data="data"></slot>
|
||||||
</template>
|
</template>
|
||||||
<template v-for="key in keys" #[updateSlotName(key)]="{ data }">
|
<template v-for="key in keys" #[updateSlotName(key)]="{ data }">
|
||||||
<slot :name="updateSlotName(key)" :data></slot>
|
<slot :name="updateSlotName(key)" :data="data"></slot>
|
||||||
</template>
|
</template>
|
||||||
</DialogWindow>
|
</DialogWindow>
|
||||||
<div>
|
<div>
|
||||||
@@ -137,31 +125,17 @@ const input = defineModel<string>("search", { default: "" });
|
|||||||
<p>{{ props.name }}</p>
|
<p>{{ props.name }}</p>
|
||||||
</template>
|
</template>
|
||||||
<template v-for="key in keys">
|
<template v-for="key in keys">
|
||||||
<Column
|
<Column :header="props.scheme[key]?.russian" v-if="!props.scheme[key].hidden">
|
||||||
:header="props.scheme[key]?.russian"
|
|
||||||
v-if="!props.scheme[key].hidden"
|
|
||||||
>
|
|
||||||
<template #body="{ data }">
|
<template #body="{ data }">
|
||||||
<p
|
<p class="truncate max-w-56" v-tooltip="viewDate(manyStructsView(
|
||||||
class="truncate max-w-56"
|
|
||||||
v-tooltip="
|
|
||||||
viewDate(
|
|
||||||
manyStructsView(
|
|
||||||
data[key],
|
data[key],
|
||||||
props.scheme[key]?.type?.nested?.field,
|
props.scheme[key]?.type?.nested?.field,
|
||||||
),
|
), scheme[key]?.type?.primitive)">
|
||||||
scheme[key]?.type?.primitive,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{
|
{{
|
||||||
viewDate(
|
viewDate(manyStructsView(
|
||||||
manyStructsView(
|
|
||||||
data[key],
|
data[key],
|
||||||
props.scheme[key]?.type?.nested?.field,
|
props.scheme[key]?.type?.nested?.field,
|
||||||
),
|
), scheme[key]?.type?.primitive)
|
||||||
scheme[key]?.type?.primitive,
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
@@ -170,32 +144,28 @@ const input = defineModel<string>("search", { default: "" });
|
|||||||
<Column header="Действия">
|
<Column header="Действия">
|
||||||
<template #body="{ data }">
|
<template #body="{ data }">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Button
|
<Button severity="secondary" icon="pi pi-pencil" @click="async () => {
|
||||||
severity="secondary"
|
await emits('onUpdateOpen')
|
||||||
icon="pi pi-pencil"
|
await emits('onOpen')
|
||||||
@click="
|
updateItem = data
|
||||||
async () => {
|
}"></Button>
|
||||||
await emits('onUpdateOpen');
|
<Button severity="danger" icon="pi pi-trash" @click="async () => {
|
||||||
await emits('onOpen');
|
await emits('onDelete', data)
|
||||||
updateItem = data;
|
await props.service.delete(data.Id)
|
||||||
}
|
await load()
|
||||||
"
|
}"></Button>
|
||||||
></Button>
|
|
||||||
<Button
|
|
||||||
severity="danger"
|
|
||||||
icon="pi pi-trash"
|
|
||||||
@click="
|
|
||||||
async () => {
|
|
||||||
await emits('onDelete', data);
|
|
||||||
await props.service.delete(data.Id);
|
|
||||||
await load();
|
|
||||||
}
|
|
||||||
"
|
|
||||||
></Button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
|
<template #paginatorstart>
|
||||||
|
<Button severity="secondary" @click="props.load">
|
||||||
|
<span class="pi pi-refresh"></span>
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
<template #paginatorend>
|
||||||
|
<span></span>
|
||||||
|
</template>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
<FloatingButton @click="handleFloatingButtonClick" />
|
<FloatingButton @click="handleFloatingButtonClick"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
import type { IEntity } from "./entity.type";
|
|
||||||
|
|
||||||
export type Search<T extends IEntity> = (input: string) => T[]
|
|
||||||
6
frontend/src/types/sort-options.type.ts
Normal file
6
frontend/src/types/sort-options.type.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import type { IEntity } from "./entity.type";
|
||||||
|
import type { Sorting } from "./sorting.type";
|
||||||
|
|
||||||
|
export type SortOptions<T extends IEntity> = {
|
||||||
|
[key in keyof Partial<T>]: Sorting
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import type { IEntity } from "./entity.type";
|
|
||||||
|
|
||||||
export type SortOptions<T extends IEntity> = {
|
|
||||||
[key in keyof T]: "ASC" | "DESC"
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Sort<T extends IEntity> = (options: SortOptions<T>) => T[]
|
|
||||||
1
frontend/src/types/sorting.type.ts
Normal file
1
frontend/src/types/sorting.type.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export type Sorting = "DESC" | "ASC"
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import type { IEntity } from "./entity.type";
|
import type { IEntity } from "./entity.type";
|
||||||
import type { Scheme } from "./scheme.type";
|
import type { Scheme } from "./scheme.type";
|
||||||
import type { Search } from "./search.type";
|
|
||||||
import type { IService } from "./service.type";
|
import type { IService } from "./service.type";
|
||||||
import type { Sort } from "./sort.type";
|
|
||||||
import type { Validate } from "./validate.type";
|
import type { Validate } from "./validate.type";
|
||||||
|
|
||||||
export interface TableProps<T extends IEntity> {
|
export interface TableProps<T extends IEntity> {
|
||||||
|
|||||||
16
frontend/src/utils/structs/default-sort-options.util.ts
Normal file
16
frontend/src/utils/structs/default-sort-options.util.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import type { IEntity } from "../../types/entity.type";
|
||||||
|
import type { Scheme } from "../../types/scheme.type";
|
||||||
|
import type { SortOptions } from "../../types/sort-options.type";
|
||||||
|
|
||||||
|
export const getDefaultSortOptions = <T extends IEntity>(scheme: Scheme<T>): SortOptions<T> => {
|
||||||
|
const keys = Object.keys(scheme) as (keyof T)[]
|
||||||
|
const result: Partial<SortOptions<T>> = {}
|
||||||
|
|
||||||
|
keys.forEach(key => {
|
||||||
|
if (!scheme[key].hidden && key !== 'entityId' && !scheme[key].many) {
|
||||||
|
result[key] = 'ASC'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return result as SortOptions<T>
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import type { IEntity } from "../../types/entity.type";
|
|
||||||
import type { Scheme } from "../../types/scheme.type";
|
|
||||||
|
|
||||||
export const defaultSort = <T extends IEntity>(scheme: Scheme<T>) => {
|
|
||||||
|
|
||||||
}
|
|
||||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "boilerplate",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"dependencies": {
|
|
||||||
"@wailsio/runtime": "3.0.0-alpha.66"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@wailsio/runtime": {
|
|
||||||
"version": "3.0.0-alpha.66",
|
|
||||||
"resolved": "https://registry.npmjs.org/@wailsio/runtime/-/runtime-3.0.0-alpha.66.tgz",
|
|
||||||
"integrity": "sha512-ENLu8rn1griL1gFHJqkq1i+BVxrrA0JPJHYneUJYuf/s54kjuQViW0RKDEe/WTDo56ABpfykrd/T8OYpPUyXUw==",
|
|
||||||
"license": "MIT"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"@wailsio/runtime": "3.0.0-alpha.66"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
@@ -1,22 +0,0 @@
|
|||||||
lockfileVersion: '9.0'
|
|
||||||
|
|
||||||
settings:
|
|
||||||
autoInstallPeers: true
|
|
||||||
excludeLinksFromLockfile: false
|
|
||||||
|
|
||||||
importers:
|
|
||||||
|
|
||||||
.:
|
|
||||||
dependencies:
|
|
||||||
'@wailsio/runtime':
|
|
||||||
specifier: 3.0.0-alpha.66
|
|
||||||
version: 3.0.0-alpha.66
|
|
||||||
|
|
||||||
packages:
|
|
||||||
|
|
||||||
'@wailsio/runtime@3.0.0-alpha.66':
|
|
||||||
resolution: {integrity: sha512-ENLu8rn1griL1gFHJqkq1i+BVxrrA0JPJHYneUJYuf/s54kjuQViW0RKDEe/WTDo56ABpfykrd/T8OYpPUyXUw==}
|
|
||||||
|
|
||||||
snapshots:
|
|
||||||
|
|
||||||
'@wailsio/runtime@3.0.0-alpha.66': {}
|
|
||||||
Reference in New Issue
Block a user