Add paginated users/roles, user status, frontend permissions, profile pictures, identifier file storage
- Users page: paginated, searchable, sortable with inline roles (no N+1) - Roles page: paginated, searchable, sortable + /roles/all for dropdowns - User is_active field with migration, PATCH toggle, auth check (disabled=401) - Frontend permission checks: auth store loads permissions, sidebar/buttons conditional - Profile pictures via file storage for users and members, avatar component - Identifier images use file storage API instead of base64 - Fix TypeScript errors across admin UI - 64 API tests passing (10 new)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { eq, and, count } from 'drizzle-orm'
|
||||
import { eq, and, count, type Column } from 'drizzle-orm'
|
||||
import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'
|
||||
import { products, inventoryUnits, priceHistory } from '../db/schema/inventory.js'
|
||||
import { ValidationError } from '../lib/errors.js'
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
import { UnitStatusService, ItemConditionService } from './lookup.service.js'
|
||||
|
||||
export const ProductService = {
|
||||
async create(db: PostgresJsDatabase, companyId: string, input: ProductCreateInput) {
|
||||
async create(db: PostgresJsDatabase<any>, companyId: string, input: ProductCreateInput) {
|
||||
const [product] = await db
|
||||
.insert(products)
|
||||
.values({
|
||||
@@ -32,7 +32,7 @@ export const ProductService = {
|
||||
return product
|
||||
},
|
||||
|
||||
async getById(db: PostgresJsDatabase, companyId: string, id: string) {
|
||||
async getById(db: PostgresJsDatabase<any>, companyId: string, id: string) {
|
||||
const [product] = await db
|
||||
.select()
|
||||
.from(products)
|
||||
@@ -41,7 +41,7 @@ export const ProductService = {
|
||||
return product ?? null
|
||||
},
|
||||
|
||||
async list(db: PostgresJsDatabase, companyId: string, params: PaginationInput) {
|
||||
async list(db: PostgresJsDatabase<any>, companyId: string, params: PaginationInput) {
|
||||
const baseWhere = and(eq(products.companyId, companyId), eq(products.isActive, true))
|
||||
|
||||
const searchCondition = params.q
|
||||
@@ -50,7 +50,7 @@ export const ProductService = {
|
||||
|
||||
const where = searchCondition ? and(baseWhere, searchCondition) : baseWhere
|
||||
|
||||
const sortableColumns: Record<string, typeof products.name> = {
|
||||
const sortableColumns: Record<string, Column> = {
|
||||
name: products.name,
|
||||
sku: products.sku,
|
||||
brand: products.brand,
|
||||
@@ -71,7 +71,7 @@ export const ProductService = {
|
||||
},
|
||||
|
||||
async update(
|
||||
db: PostgresJsDatabase,
|
||||
db: PostgresJsDatabase<any>,
|
||||
companyId: string,
|
||||
id: string,
|
||||
input: ProductUpdateInput,
|
||||
@@ -106,7 +106,7 @@ export const ProductService = {
|
||||
return product ?? null
|
||||
},
|
||||
|
||||
async softDelete(db: PostgresJsDatabase, companyId: string, id: string) {
|
||||
async softDelete(db: PostgresJsDatabase<any>, companyId: string, id: string) {
|
||||
const [product] = await db
|
||||
.update(products)
|
||||
.set({ isActive: false, updatedAt: new Date() })
|
||||
@@ -117,7 +117,7 @@ export const ProductService = {
|
||||
}
|
||||
|
||||
export const InventoryUnitService = {
|
||||
async create(db: PostgresJsDatabase, companyId: string, input: InventoryUnitCreateInput) {
|
||||
async create(db: PostgresJsDatabase<any>, companyId: string, input: InventoryUnitCreateInput) {
|
||||
if (input.condition) {
|
||||
const valid = await ItemConditionService.validateSlug(db, companyId, input.condition)
|
||||
if (!valid) throw new ValidationError(`Invalid condition: "${input.condition}"`)
|
||||
@@ -144,7 +144,7 @@ export const InventoryUnitService = {
|
||||
return unit
|
||||
},
|
||||
|
||||
async getById(db: PostgresJsDatabase, companyId: string, id: string) {
|
||||
async getById(db: PostgresJsDatabase<any>, companyId: string, id: string) {
|
||||
const [unit] = await db
|
||||
.select()
|
||||
.from(inventoryUnits)
|
||||
@@ -154,7 +154,7 @@ export const InventoryUnitService = {
|
||||
},
|
||||
|
||||
async listByProduct(
|
||||
db: PostgresJsDatabase,
|
||||
db: PostgresJsDatabase<any>,
|
||||
companyId: string,
|
||||
productId: string,
|
||||
params: PaginationInput,
|
||||
@@ -164,7 +164,7 @@ export const InventoryUnitService = {
|
||||
eq(inventoryUnits.productId, productId),
|
||||
)
|
||||
|
||||
const sortableColumns: Record<string, typeof inventoryUnits.serialNumber> = {
|
||||
const sortableColumns: Record<string, Column> = {
|
||||
serial_number: inventoryUnits.serialNumber,
|
||||
status: inventoryUnits.status,
|
||||
condition: inventoryUnits.condition,
|
||||
@@ -184,7 +184,7 @@ export const InventoryUnitService = {
|
||||
},
|
||||
|
||||
async update(
|
||||
db: PostgresJsDatabase,
|
||||
db: PostgresJsDatabase<any>,
|
||||
companyId: string,
|
||||
id: string,
|
||||
input: InventoryUnitUpdateInput,
|
||||
|
||||
Reference in New Issue
Block a user