Current state

This commit is contained in:
Leon Meier 2023-05-15 00:21:53 +02:00
parent 6344134a9e
commit 1f2eb78333
14 changed files with 124 additions and 72 deletions

View File

@ -25,7 +25,7 @@ generator dbml {
projectName = "AssetFlow" projectName = "AssetFlow"
} }
enum Status { enum itemStatus {
normal normal
borrowed borrowed
stolen stolen
@ -37,12 +37,12 @@ model Item {
SKU String? @unique SKU String? @unique
amount Int @default(1) amount Int @default(1)
name String name String
Comment String? comment String?
status Status @default(normal) /// TODO: Would it be better to create a separate model for this as well instead of providing several static statuses to choose from(enum)? status itemStatus @default(normal) /// TODO: Would it be better to create a separate model for this as well instead of providing several static statuses to choose from(enum)?
manufacturer String /// TODO: Do we need this as a mandatory field? Probably we can add another model for manufacturer. manufacturer String
category Category @relation(fields: [categoryId], references: [id]) category itemCategory @relation(fields: [categoryId], references: [id])
categoryId Int categoryId Int
items Item[] @relation("items") /// Item beinhaltet.. items Item[] @relation("items") /// Item beinhaltet..
@ -68,15 +68,14 @@ model StorageLocation {
model StorageUnit { model StorageUnit {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
name String name String
street String
houseNumber String contactInfo contactInfo? @relation(fields: [contactInfoId], references: [id])
zipCode String contactInfoId Int?
city String
country String
StorageLocation StorageLocation[] StorageLocation StorageLocation[]
} }
model Category { model itemCategory {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
name String @unique name String @unique
description String? description String?
@ -84,20 +83,24 @@ model Category {
} }
/// TODO: Add relationship to StorageUnit, Item and if necessary to StorageLocation. /// TODO: Add relationship to StorageUnit, Item and if necessary to StorageLocation.
model Owner { model contactInfo {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
type OwnerType @default(person) type contactType @default(person)
name String name String?
lastName String? lastName String?
street String street String
houseNumber String houseNumber String
zipCode String zipCode String
city String city String
country String country String
StorageUnit StorageUnit[]
} }
enum OwnerType { enum contactType {
person person
customer customer
company company
partner
enemy
} }

View File

@ -1,5 +1,5 @@
<%~ E.includeFile("../../partials/head.eta.html", {"title": "Importer - CSV" }) %> <%~ E.includeFile("../../partials/head.eta.html", {"title": "Importer - CSV" }) %>
<%~ E.includeFile("../../partials/controls.eta.html", {"active": "SETT_CSV_IMPORT" }) %> <%~ E.includeFile("../../partials/controls.eta.html", {"active": "SETT_IMPORT_CSV" }) %>
<h1>Import A CSV File</h1> <h1>Import A CSV File</h1>
Upload a CSV file to import into the database. The CSV file must have the following columns: Upload a CSV file to import into the database. The CSV file must have the following columns:

View File

@ -0,0 +1,27 @@
<%~ E.includeFile("../partials/head.eta.html", {"title": "Settings"}) %> <%~ E.includeFile("../partials/controls.eta.html", {"active": "SETT"}) %>
<h1>Manage your AssetFlow instance</h1>
<div class="container text-center">
<div class="row">
<a class="card col m-2" href="/manage/categories">
<div class="card-body">
<h1 class="card-title"><i class="bi bi-tag"></i></h1>
<p class="card-text">Manage categories</p>
</div>
</a>
<a class="card col m-2" href="/manage/storages">
<div class="card-body">
<h1 class="card-title"><i class="bi bi-box-seam"></i></h1>
<p class="card-text">Manage storages</p>
</div>
</a><a class="card col m-2" href="/manage/import/csv">
<div class="card-body">
<h1 class="card-title"><i class="bi bi-filetype-csv"></i></h1>
<p class="card-text">Import data via CSV</p>
</div>
</a>
</div>
</div>
<%~ E.includeFile("../partials/controlsFoot.eta.html") %> <%~ E.includeFile("../partials/foot.eta.html") %>

View File

@ -1,5 +1,5 @@
<header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow"> <header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
<a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 test-white-50" href="#">AssetFlow</a> <a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 test-white-50" href="https://shattereddisk.github.io/rickroll/rickroll.mp4">AssetFlow</a>
<button <button
class="navbar-toggler position-absolute d-md-none collapsed" class="navbar-toggler position-absolute d-md-none collapsed"
type="button" type="button"
@ -78,7 +78,7 @@
</ul> </ul>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted"> <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Settings</span> <a href="/manage/" class="nav-link">Settings</a>
</h6> </h6>
<ul class="nav flex-column mb-2"> <ul class="nav flex-column mb-2">
@ -92,7 +92,9 @@
data-bs-target="#collapseSettingsStorages" data-bs-target="#collapseSettingsStorages"
aria-expanded="<%= it.active == 'SETT_STORE' ? 'true' : 'false'%>" aria-expanded="<%= it.active == 'SETT_STORE' ? 'true' : 'false'%>"
aria-controls="collapseSettingsStorages"> aria-controls="collapseSettingsStorages">
<i class="bi bi-caret-down-fill"></i> <span class="dropdownIndicator" data-ref-target="#collapseSettingsStorages">
<i class="bi bi-caret-left-fill" ></i>
</span>
<!-- TODO: This little triangle does not care if it is collapsed or not. But it should so --> <!-- TODO: This little triangle does not care if it is collapsed or not. But it should so -->
</span> </span>
</a> </a>
@ -106,12 +108,25 @@
<a class="nav-link <%= it.active == 'SETT_CAT' ? 'active' : ''%>" href="/manage/categories"><i class="bi bi-tag"></i> Manage categories </a> <a class="nav-link <%= it.active == 'SETT_CAT' ? 'active' : ''%>" href="/manage/categories"><i class="bi bi-tag"></i> Manage categories </a>
</li> </li>
<li class="nav-item"> <a class="nav-link">
<a class="nav-link <%= it.active == 'SETT_CSV_IMPORT' ? 'active' : ''%>" href="/manage/import/csv"><i class="bi bi-filetype-csv"></i> CSV Import </a> <span
</li> class="<%= it.active == 'SETT_IMPORT' ? 'active' : ''%>"
<li class="nav-item"> type="button"
<a class="nav-link <%= it.active == 'SETT_JSON_IMPORT' ? 'active' : ''%>" href="/manage/import/json"> <i class="bi bi-filetype-json"></i> JSON Import</a> onclick="return false"
</li> data-bs-toggle="collapse"
data-bs-target="#collapseSettingsImport"
aria-expanded="<%= it.active.includes('SETT_IMPORT') ? 'true' : 'false'%>"
aria-controls="collapseSettingsImport">
<i class="bi bi-box-seam"></i> Import
<i class="bi bi-caret-left-fill dropdownIndicator" data-ref-target="#collapseSettingsImport"></i>
<!-- TODO: This little triangle does not care if it is collapsed or not. But it should so -->
</span>
</a>
<div class="collapse <%= it.active.includes('SETT_IMPORT') ? 'show' : ''%>" id="collapseSettingsImport">
<a class="nav-link ms-4 <%= it.active == 'SETT_IMPORT_CSV' ? 'active' : ''%>" href="/manage/import/csv"><i class="bi bi-filetype-csv"></i> CSV Import </a>
<a class="nav-link ms-4 <%= it.active == 'SETT_IMPORT_JSON' ? 'active' : ''%>" href="/manage/import/json"> <i class="bi bi-filetype-json"></i> JSON Import</a>
</div>
</ul> </ul>
</div> </div>
</nav> </nav>

View File

@ -2,3 +2,4 @@
</div> </div>
</div> </div>
<script src="/js/searchBox.js"></script> <script src="/js/searchBox.js"></script>
<script src="/js/handleSidebarTriangles.js"></script>

View File

@ -3,7 +3,6 @@ import ConfigHandler from './assets/configHandler';
import express, { Request, Response } from 'express'; import express, { Request, Response } from 'express';
import fileUpload from 'express-fileupload'; import fileUpload from 'express-fileupload';
import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
import { Status, Category } from '@prisma/client';
import * as eta from 'eta'; import * as eta from 'eta';
import bodyParser from 'body-parser'; import bodyParser from 'body-parser';

View File

@ -1,11 +1,11 @@
import express from 'express'; import express from 'express';
// Route imports // Route imports
import setDemoData from './setDemoData.js'; // import setDemoData from './setDemoData.js';
// Router base is '/dev' // Router base is '/dev'
const Router = express.Router(); const Router = express.Router();
Router.use("/setDemoData", setDemoData) // Router.use("/setDemoData", setDemoData)
export default Router; export default Router;

View File

@ -1,27 +0,0 @@
import { Request, Response } from 'express';
import { prisma } from '../../index.js';
import { Status, Category } from '@prisma/client';
export default (req: Request, res: Response) => {
// fill database with demo data
/*
prisma.item
.create({
data: {
SKU: 'ee189749',
Amount: 1,
name: 'Test Item',
manufacturer: 'Test Manufacturer',
category: Category.Other,
status: Status.normal
}
})
.then(() => {
res.send('Demo data added');
})
.catch((err) => {
res.send('Error adding demo data: ' + err);
});*/
res.send('No data was added');
};

View File

@ -5,7 +5,7 @@ export default (req: Request, res: Response) => {
// If method is get, render the page // If method is get, render the page
if (req.method === 'GET') { if (req.method === 'GET') {
// Render the page // Render the page
prisma.category prisma.itemCategory
.findMany({}) .findMany({})
.then((items) => { .then((items) => {
// Count amount of total items // Count amount of total items
@ -26,7 +26,7 @@ export default (req: Request, res: Response) => {
if(!req.body.editCategoryModalIsEdit) { if(!req.body.editCategoryModalIsEdit) {
console.log('is not edit'); console.log('is not edit');
// Save data to category table // Save data to category table
prisma.category.create({ prisma.itemCategory.create({
data: { data: {
name: req.body.name, name: req.body.name,
description: req.body.description, description: req.body.description,
@ -42,7 +42,7 @@ export default (req: Request, res: Response) => {
}); });
} else { } else {
// Save data to category table // Save data to category table
prisma.category.update({ prisma.itemCategory.update({
where: { where: {
id: parseInt(req.body.editCategoryModalId) id: parseInt(req.body.editCategoryModalId)
}, },

View File

@ -2,7 +2,7 @@ import express, { Request, Response } from 'express';
import { prisma, __path, log } from '../../../../index.js'; import { prisma, __path, log } from '../../../../index.js';
import { UploadedFile } from 'express-fileupload'; import { UploadedFile } from 'express-fileupload';
import { parse, transform } from 'csv'; import { parse, transform } from 'csv';
import { Status, Category, PrismaPromise } from '@prisma/client'; import { itemStatus, itemCategory, PrismaPromise } from '@prisma/client';
export default (req: Request, res: Response) => { export default (req: Request, res: Response) => {
// Decide wether its post or get // Decide wether its post or get
@ -25,8 +25,9 @@ export default (req: Request, res: Response) => {
records.forEach((record: any) => { records.forEach((record: any) => {
categories.add(record.category); categories.add(record.category);
}); });
log.db.debug(categories);
// Remove categories that already exists in the database // Remove categories that already exists in the database
prisma.category.findMany({ prisma.itemCategory.findMany({
where: { where: {
name: { name: {
in: Array.from(categories) in: Array.from(categories)
@ -36,10 +37,10 @@ export default (req: Request, res: Response) => {
values.forEach((value) => { values.forEach((value) => {
categories.delete(value.name); categories.delete(value.name);
}); });
log.db.debug(categories);
const categoryPromises: PrismaPromise<Category>[] = []; const categoryPromises: PrismaPromise<itemCategory>[] = [];
categories.forEach((category: string) => { categories.forEach((category: string) => {
const promise = prisma.category.create({ const promise = prisma.itemCategory.create({
data: { data: {
name: category name: category
} }
@ -56,7 +57,7 @@ export default (req: Request, res: Response) => {
data: { data: {
name: record.name, name: record.name,
amount: parseInt(record.amount), amount: parseInt(record.amount),
Comment: record.comment, comment: record.comment,
category: { category: {
connect: { connect: {
name: record.category name: record.category
@ -64,8 +65,8 @@ export default (req: Request, res: Response) => {
}, },
SKU: record.sku, SKU: record.sku,
manufacturer: record.manufacturer, manufacturer: record.manufacturer,
status: Status.normal, status: itemStatus.normal,
importedBy: "CSV Import" importedBy: "CSV_IMPORT"
} }
}); });
listOfPromises.push(promise); listOfPromises.push(promise);

View File

@ -5,13 +5,16 @@ import testRoute from './test.js';
import csvImportRoute from './import/csvImport.js'; import csvImportRoute from './import/csvImport.js';
import categoryManager from './categoryManager.js'; import categoryManager from './categoryManager.js';
import storageManager from './storageManager.js'; import storageManager from './storageManager.js';
import startpageRoute from './startpage.js';
// Router base is '/manage' // Router base is '/manage'
const Router = express.Router({ strict: false }); const Router = express.Router({ strict: false });
Router.use('/test', testRoute); Router.use('/test', testRoute);
Router.use('/categories', categoryManager) Router.use('/categories', categoryManager)
Router.use('/storages', storageManager) Router.use('/storages', storageManager)
Router.use('/import/csv', csvImportRoute); Router.use('/import/csv', csvImportRoute);
Router.use('/', startpageRoute);
export default Router; export default Router;

View File

@ -0,0 +1,7 @@
import express, { Request, Response } from 'express';
import { prisma, __path } from '../../../index.js';
export default (req: Request, res: Response) => {
res.render(__path + '/src/frontend/manage/startpage.eta.html'); //, { items: items });
};

View File

@ -99,3 +99,9 @@ body {
left: 0; left: 0;
right: 0; right: 0;
} }
.rotate {
transform: rotate(90deg);
color: red;
transition: 1s;
}

View File

@ -0,0 +1,17 @@
const trinagles = $('.dropdownIndicator');
//const containers = $('');
trinagles.each(function () {
var target = $(this.dataset.refTarget);
target.on('show.bs.collapse', function () {
//$(this).parent.addClass('rotate');
// $(this).parent().find('.dropdownIndicator').addClass('rotate');
console.log('show');
});
target.on('hide.bs.collapse', function () {
//$(this).parent.removeClass('rotate');
// $(this).parent().find('.dropdownIndicator').removeClass('rotate');
console.log('hide');
});
// bootstrap.Collapse.getOrCreateInstance(document.querySelector(this.dataset.refTarget))
});