Current state
This commit is contained in:
parent
6344134a9e
commit
1f2eb78333
@ -25,7 +25,7 @@ generator dbml {
|
|||||||
projectName = "AssetFlow"
|
projectName = "AssetFlow"
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Status {
|
enum itemStatus {
|
||||||
normal
|
normal
|
||||||
borrowed
|
borrowed
|
||||||
stolen
|
stolen
|
||||||
@ -33,16 +33,16 @@ enum Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model Item {
|
model Item {
|
||||||
id Int @id @unique @default(autoincrement())
|
id Int @id @unique @default(autoincrement())
|
||||||
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..
|
||||||
@ -66,17 +66,16 @@ model StorageLocation {
|
|||||||
|
|
||||||
/// A StorageUnit is the base and can hold multiple StorageLocations.
|
/// A StorageUnit is the base and can hold multiple StorageLocations.
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
|
27
src/frontend/manage/startpage.eta.html
Normal file
27
src/frontend/manage/startpage.eta.html
Normal 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") %>
|
@ -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>
|
||||||
|
@ -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>
|
@ -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';
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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');
|
|
||||||
};
|
|
@ -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)
|
||||||
},
|
},
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
7
src/routes/frontend/manage/startpage.ts
Normal file
7
src/routes/frontend/manage/startpage.ts
Normal 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 });
|
||||||
|
|
||||||
|
};
|
@ -99,3 +99,9 @@ body {
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rotate {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
color: red;
|
||||||
|
transition: 1s;
|
||||||
|
}
|
||||||
|
17
static/js/handleSidebarTriangles.js
Normal file
17
static/js/handleSidebarTriangles.js
Normal 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))
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user