v1.6.5: fix attendance unique constraint, schema sync, seed script

- Change attendance idx_attendance_user_date from unique to index (allow multiple shifts per day)
- Reset migrations to single baseline init migration
- Add seed script with admin user (admin/admin)
- Update CLAUDE.md with migration workflow documentation
- Various frontend fixes (queries, pages, hooks)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-05-17 16:21:34 +02:00
parent 1db5060c42
commit cd6d3daf43
75 changed files with 1748 additions and 1169 deletions

View File

@@ -8,29 +8,17 @@ import ConfirmModal from "../components/ConfirmModal";
import FormField from "../components/FormField";
import Forbidden from "../components/Forbidden";
import useModalLock from "../hooks/useModalLock";
import { userListOptions, roleListOptions } from "../lib/queries/users";
import {
userListOptions,
roleListOptions,
type User,
type Role,
} from "../lib/queries/users";
import UsersFixture from "../fixtures/UsersFixture";
import apiFetch from "../utils/api";
const API_BASE = "/api/admin";
interface User {
id: number;
username: string;
email: string;
first_name: string;
last_name: string;
role_id: number;
roles?: { id: number; name: string; display_name: string } | null;
is_active: boolean;
}
interface Role {
id: number;
name: string;
display_name: string;
}
interface FormData {
username: string;
email: string;
@@ -46,10 +34,8 @@ export default function Users() {
const alert = useAlert();
const queryClient = useQueryClient();
const { data: usersData, isPending } = useQuery(userListOptions());
const users = ((usersData as Record<string, unknown>)?.items ??
usersData ??
[]) as User[];
const { data: roles = [] } = useQuery(roleListOptions()) as { data: Role[] };
const users = usersData ?? [];
const { data: roles = [] } = useQuery(roleListOptions());
const [showModal, setShowModal] = useState(false);
const [editingUser, setEditingUser] = useState<User | null>(null);
const [deleteModal, setDeleteModal] = useState<{
@@ -144,6 +130,11 @@ export default function Users() {
wasEditing ? "Uživatel byl upraven" : "Uživatel byl vytvořen",
);
queryClient.invalidateQueries({ queryKey: ["users"] });
queryClient.invalidateQueries({ queryKey: ["trips"] });
queryClient.invalidateQueries({ queryKey: ["attendance"] });
queryClient.invalidateQueries({ queryKey: ["leave-requests"] });
queryClient.invalidateQueries({ queryKey: ["leave"] });
queryClient.invalidateQueries({ queryKey: ["projects"] });
} else {
alert.error(data.error || "Nepodařilo se uložit uživatele");
}
@@ -177,6 +168,11 @@ export default function Users() {
if (data.success) {
closeDeleteModal();
queryClient.invalidateQueries({ queryKey: ["users"] });
queryClient.invalidateQueries({ queryKey: ["trips"] });
queryClient.invalidateQueries({ queryKey: ["attendance"] });
queryClient.invalidateQueries({ queryKey: ["leave-requests"] });
queryClient.invalidateQueries({ queryKey: ["leave"] });
queryClient.invalidateQueries({ queryKey: ["projects"] });
alert.success("Uživatel byl smazán");
} else {
alert.error(data.error || "Nepodařilo se smazat uživatele");
@@ -202,6 +198,11 @@ export default function Users() {
if (data.success) {
queryClient.invalidateQueries({ queryKey: ["users"] });
queryClient.invalidateQueries({ queryKey: ["trips"] });
queryClient.invalidateQueries({ queryKey: ["attendance"] });
queryClient.invalidateQueries({ queryKey: ["leave-requests"] });
queryClient.invalidateQueries({ queryKey: ["leave"] });
queryClient.invalidateQueries({ queryKey: ["projects"] });
alert.success(
user.is_active
? "Uživatel byl deaktivován"