Compare commits
3 Commits
9124e66e28
...
cb5616c81f
| Author | SHA1 | Date |
|---|---|---|
|
|
cb5616c81f | 11 months ago |
|
|
d219c136c0 | 11 months ago |
|
|
d3364af395 | 11 months ago |
@ -1,5 +1,9 @@
|
|||||||
/target
|
/target
|
||||||
|
/resources
|
||||||
/.env
|
/.env
|
||||||
/*.db
|
/*.db
|
||||||
/*.db-shm
|
/*.db-shm
|
||||||
/*.db-wal
|
/*.db-wal
|
||||||
|
|
||||||
|
/node_modules
|
||||||
|
/*.lockb
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaScriptLibraryMappings">
|
|
||||||
<file url="file://$PROJECT_DIR$" libraries="{alpinejs}" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["prettier-plugin-tailwindcss"]
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
# inventory-app
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. Rust & Cargo
|
||||||
|
1. [bun.sh](https://bun.sh/)
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
To install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run index.ts
|
||||||
|
```
|
||||||
|
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,42 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=templates");
|
||||||
|
println!("cargo:rerun-if-changed=assets");
|
||||||
|
println!("cargo:rerun-if-changed=tailwind.config.js");
|
||||||
|
|
||||||
|
std::fs::remove_dir_all("resources").unwrap_or_default();
|
||||||
|
|
||||||
|
Command::new("bun")
|
||||||
|
.args([
|
||||||
|
"run",
|
||||||
|
"tailwindcss",
|
||||||
|
"-c",
|
||||||
|
"tailwind.config.js",
|
||||||
|
"-i",
|
||||||
|
"assets/public/css/tailwind.css",
|
||||||
|
"-o",
|
||||||
|
"resources/main.css",
|
||||||
|
"--minify",
|
||||||
|
])
|
||||||
|
.status()
|
||||||
|
.expect("failed to run tailwindcss");
|
||||||
|
|
||||||
|
copy_files("assets/static");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_files(dir: &str) {
|
||||||
|
for entry in std::fs::read_dir(dir).expect("failed to read dir `public`") {
|
||||||
|
let entry = entry.expect("failed to read entry");
|
||||||
|
|
||||||
|
if entry.file_type().unwrap().is_dir() {
|
||||||
|
copy_files(entry.path().to_str().unwrap());
|
||||||
|
} else {
|
||||||
|
let path = entry.path();
|
||||||
|
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||||
|
let dest = format!("resources/{}", filename);
|
||||||
|
|
||||||
|
std::fs::copy(path, dest).expect("failed to copy file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "inventory-app",
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"prettier": "^3.4.2",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
|
"tailwindcss": "^3.4.17"
|
||||||
|
},
|
||||||
|
"type": "module"
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,19 @@
|
|||||||
|
export const content = ["./templates/**/*.html"]
|
||||||
|
export const theme = {
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Graphik', 'sans-serif'],
|
||||||
|
serif: ['Merriweather', 'serif'],
|
||||||
|
},
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
'space-cadet':'#1f2041ff',
|
||||||
|
'english-violet':'#4b3f72ff',
|
||||||
|
'sunglow':'#ffc857ff',
|
||||||
|
'dark-cyan':'#119da4ff',
|
||||||
|
'paynes-gray':'#19647eff',
|
||||||
|
'cerise': '#da4167ff',
|
||||||
|
'orchid-pink': '#f0bcd4ff'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
@ -1,10 +1,6 @@
|
|||||||
{% extends "problem.html" %}
|
{% extends "problem.html" %} {% block content %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>Error</h1>
|
<h1>Error</h1>
|
||||||
<p>
|
<p>Oops, something went wrong. Press the back button to try again.</p>
|
||||||
Oops, something went wrong. Press the back button to try again.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,27 +1,50 @@
|
|||||||
{% extends "main.html" %}
|
{% extends "main.html" %} {% block title %} Items {% endblock %} {% block
|
||||||
|
content %}
|
||||||
|
|
||||||
{% block title %} Items {% endblock %}
|
<div class="mx-auto mb-4 px-4">
|
||||||
|
<label
|
||||||
{% block content %}
|
for="item-filter"
|
||||||
|
class="sr-only mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||||
<div class="container">
|
>Search</label
|
||||||
<p class="container d-flex justify-content-center">
|
>
|
||||||
<input id="search" class="form-control"
|
<div class="relative mb-4 max-w-56 content-center">
|
||||||
type="search" name="q"
|
<div
|
||||||
placeholder="Filter"
|
class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3"
|
||||||
aria-label="Search"
|
>
|
||||||
value='{{ query.search.as_deref().unwrap_or("") }}'
|
<svg
|
||||||
hx-get="/items"
|
class="h-4 w-4 text-gray-500 dark:text-gray-400"
|
||||||
hx-trigger="search, keyup delay:500ms changed"
|
aria-hidden="true"
|
||||||
hx-target="#items"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
hx-push-url="true"
|
fill="none"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"
|
||||||
/>
|
/>
|
||||||
</p>
|
</svg>
|
||||||
|
|
||||||
<div id="items" class="container">
|
|
||||||
{% include "catalog_item_fragment.html" %}
|
|
||||||
</div>
|
</div>
|
||||||
|
<input
|
||||||
|
id="item-filter"
|
||||||
|
class="block w-full rounded-lg border border-gray-300 bg-slate-100 p-4 ps-10 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:bg-neutral-900 dark:text-slate-100"
|
||||||
|
type="search"
|
||||||
|
name="q"
|
||||||
|
placeholder="Filter"
|
||||||
|
aria-label="Filter"
|
||||||
|
value='{{ query.search.as_deref().unwrap_or("") }}'
|
||||||
|
hx-get="/items"
|
||||||
|
hx-trigger="search, keyup delay:500ms changed"
|
||||||
|
hx-target="#items"
|
||||||
|
hx-push-url="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="items" class="container">
|
||||||
|
{% include "catalog_item_fragment.html" %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
<div class="card">
|
<div class="mx-auto">
|
||||||
<ul class="list-group list-group-flush">
|
<div class="flex flex-col">
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
<li id="item-{{item.id}}-entry" class="list-group-item">
|
<div class="mx-1 mb-4 flex flex-row">
|
||||||
<div class="row">
|
<div class="basis-1/2">
|
||||||
<div class="col-6"><a href="/item/{{item.id}}/" hx-push-url="true">{{ item.name }}</a></div>
|
<a
|
||||||
|
class="font-medium text-paynes-gray hover:underline dark:text-paynes-gray"
|
||||||
|
href="/item/{{item.id}}/"
|
||||||
|
hx-push-url="true"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
{% extends "problem.html" %}
|
{% extends "problem.html" %} {% block content %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>Forbidden</h1>
|
<h1>Forbidden</h1>
|
||||||
<p>
|
<p>
|
||||||
You are forbidden from accessing this resource. Please contact your supervisor or <a href="/auth/logout">logout</a>
|
You are forbidden from accessing this resource. Please contact your supervisor
|
||||||
and log back in with a different user.
|
or <a href="/auth/logout">logout</a>
|
||||||
|
and log back in with a different user.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,38 +1,64 @@
|
|||||||
{% extends "main.html" %}
|
{% extends "main.html" %} {% block title %} Audit Log {% endblock %} {% block
|
||||||
|
content %}
|
||||||
|
|
||||||
{% block title %} Audit Log {% endblock %}
|
<h1 class="mb-4 text-4xl font-extrabold uppercase">Audit Log (Coming soon)</h1>
|
||||||
|
|
||||||
{% block content %}
|
<section class="mb-4">
|
||||||
|
<form
|
||||||
<h1>Audit Log (Coming soon)</h1>
|
action="/history"
|
||||||
|
hx-get="/history"
|
||||||
<section class="container mb-4">
|
hx-trigger="change"
|
||||||
<form action="/history" hx-get="/history" hx-trigger="change" hx-target="#items">
|
hx-target="#items"
|
||||||
<div class="row">
|
>
|
||||||
<div class="col-sm-2">
|
<div class="flex between">
|
||||||
<label for="start-date" class="form-label">Start Date</label>
|
<div class="px-2">
|
||||||
<input type="date" id="start-date" name="start-date" value="{{ start_date }}" class="form-control" />
|
<label for="start-date" class="block">Start Date</label>
|
||||||
</div>
|
<input
|
||||||
<div class="col-sm-2">
|
type="date"
|
||||||
<label for="start-time" class="form-label">Start Time</label>
|
id="start-date"
|
||||||
<input type="time" id="start-time" name="start-time" value="{{ start_time }}" class="form-control"/>
|
name="start-date"
|
||||||
<small class="form-text">Timezone {{ time_zone }}</small>
|
value="{{ start_date }}"
|
||||||
</div>
|
class="block"
|
||||||
<div class="col-sm-2">
|
/>
|
||||||
<label for="end-date" class="form-label">End Date</label>
|
</div>
|
||||||
<input type="date" id="end-date" name="end-date" value="{{ end_date }}" class="form-control"/>
|
<div class="px-2">
|
||||||
</div>
|
<label for="start-time" class="block">Start Time</label>
|
||||||
<div class="col-sm-2">
|
<input
|
||||||
<label for="end-time" class="form-label">End Time</label>
|
type="time"
|
||||||
<input type="time" id="end-time" name="end-time" value="{{ end_time }}" class="form-control"/>
|
id="start-time"
|
||||||
<small class="form-text">Timezone {{ time_zone }}</small>
|
name="start-time"
|
||||||
</div>
|
value="{{ start_time }}"
|
||||||
</div>
|
class="block"
|
||||||
</form>
|
/>
|
||||||
|
<small class="block text-sm">Timezone {{ time_zone }}</small>
|
||||||
|
</div>
|
||||||
|
<div class="px-2">
|
||||||
|
<label for="end-date" class="block">End Date</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
id="end-date"
|
||||||
|
name="end-date"
|
||||||
|
value="{{ end_date }}"
|
||||||
|
class="block"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="px-2">
|
||||||
|
<label for="end-time" class="form-label">End Time</label>
|
||||||
|
<input
|
||||||
|
type="time"
|
||||||
|
id="end-time"
|
||||||
|
name="end-time"
|
||||||
|
value="{{ end_time }}"
|
||||||
|
class="block"
|
||||||
|
/>
|
||||||
|
<small class="text-sm block">Timezone {{ time_zone }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="items" class="container">
|
<section id="items" class="mb-4">
|
||||||
{% include "history_item_fragment.html" %}
|
{% include "history_item_fragment.html" %}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,22 +1,29 @@
|
|||||||
|
<table class="table-auto">
|
||||||
<div class="card">
|
<thead>
|
||||||
<ul class="list-group list-group-flush">
|
<tr class="mb-2">
|
||||||
{% for item in items %}
|
<th>Date</th>
|
||||||
<li class="list-group-item">
|
<th>Item</th>
|
||||||
<div class="row">
|
<th>User</th>
|
||||||
<p class="col">{{ item.create_date }}</p>
|
<th>Desc</th>
|
||||||
<p class="col">{{ item.item_name }}</p>
|
</tr>
|
||||||
<p class="col">{{ item.user_name }}</p>
|
</thead>
|
||||||
<p class="col">
|
<tbody>
|
||||||
{% match item.item_type %}
|
{% for item in items %}
|
||||||
{% when HistoryItemEntry::PositiveAdjustment with (entry) %}
|
<tr class="mb-2">
|
||||||
{{ entry.amount }} @ {{ entry.unit_value }}
|
<td class="px-2">{{ item.create_date }}</td>
|
||||||
{% when HistoryItemEntry::NegativeAdjustment with (entry) %}
|
<td class="px-2">{{ item.item_name }}</td>
|
||||||
{{ entry.amount }} {{ entry.reason }}
|
<td class="px-2">{{ item.user_name }}</td>
|
||||||
{% endmatch %}
|
<td class="px-2">
|
||||||
</p>
|
{% match item.item_type %}
|
||||||
</div>
|
{% when HistoryItemEntry::PositiveAdjustment with (entry) %}
|
||||||
</li>
|
{{ entry.amount }} @ {{ entry.unit_value }}
|
||||||
|
{% when HistoryItemEntry::NegativeAdjustment with (entry) %}
|
||||||
|
{{ entry.amount }} {{ entry.reason }}
|
||||||
|
{% endmatch %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
|
||||||
</div>
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|||||||
@ -1,27 +1,50 @@
|
|||||||
{% extends "main.html" %}
|
{% extends "main.html" %} {% block title %} Home {% endblock %} {% block content
|
||||||
|
%}
|
||||||
|
|
||||||
{% block title %} Home {% endblock %}
|
<div class="mx-auto mb-4 px-4">
|
||||||
|
<label
|
||||||
{% block content %}
|
for="default-search"
|
||||||
|
class="sr-only mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||||
<div class="container">
|
>Search</label
|
||||||
<p class="container d-flex justify-content-center">
|
>
|
||||||
<input id="search"
|
<div class="relative mb-4 max-w-56 content-center">
|
||||||
class="form-control"
|
<div
|
||||||
type="search" name="q"
|
class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3"
|
||||||
placeholder="Search"
|
>
|
||||||
aria-label="Search"
|
<svg
|
||||||
value='{{ query.search.as_deref().unwrap_or("") }}'
|
class="h-4 w-4 text-gray-500 dark:text-gray-400"
|
||||||
hx-get="/home/search"
|
aria-hidden="true"
|
||||||
hx-trigger="search, keyup delay:500ms changed"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
hx-target="#items"
|
fill="none"
|
||||||
hx-push-url="true"
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"
|
||||||
/>
|
/>
|
||||||
</p>
|
</svg>
|
||||||
|
|
||||||
<div id="items" class="container">
|
|
||||||
{% include "home_search_item_fragment.html" %}
|
|
||||||
</div>
|
</div>
|
||||||
|
<input
|
||||||
|
id="default-search"
|
||||||
|
class="block w-full rounded-lg border border-gray-300 bg-slate-100 p-4 ps-10 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:bg-neutral-900 dark:text-slate-100"
|
||||||
|
type="search"
|
||||||
|
name="q"
|
||||||
|
placeholder="Search"
|
||||||
|
aria-label="Search"
|
||||||
|
value='{{ query.search.as_deref().unwrap_or("") }}'
|
||||||
|
hx-get="/home/search"
|
||||||
|
hx-trigger="search, keyup delay:500ms changed"
|
||||||
|
hx-target="#items"
|
||||||
|
hx-push-url="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="items" class="container">
|
||||||
|
{% include "home_search_item_fragment.html" %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,16 +1,29 @@
|
|||||||
|
|
||||||
{% if items.len() > 0 %}
|
{% if items.len() > 0 %}
|
||||||
<div class="card">
|
<div class="mx-auto">
|
||||||
<ul class="list-group list-group-flush">
|
<div class="flex flex-col">
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
<li id="item-{{item.id}}-entry" class="list-group-item">
|
<div class="mx-1 mb-4 flex flex-row">
|
||||||
<div class="row">
|
<div class="basis-1/2">
|
||||||
<div class="col-6"><a href="/item/{{item.id}}/" hx-push-url="true">{{ item.name }}</a></div>
|
<a
|
||||||
<div class="col">Count: <span id="item-{{item.id}}-count" hx-get="/item/{{item.id}}/count" hx-trigger="load">0</span></div>
|
class="font-medium text-paynes-gray hover:underline dark:text-paynes-gray"
|
||||||
<div class="col">Reorder Point: {{ item.reorder_point }}</div>
|
href="/item/{{item.id}}/"
|
||||||
|
hx-push-url="true"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="basis-1/4">
|
||||||
|
Count:
|
||||||
|
<span
|
||||||
|
id="item-{{item.id}}-count"
|
||||||
|
hx-get="/item/{{item.id}}/count"
|
||||||
|
hx-trigger="load"
|
||||||
|
>0</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="basis-1/4">Reorder Point: {{ item.reorder_point }}</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
{% endfor %}
|
||||||
{% endfor %}
|
</div>
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -1,25 +1,31 @@
|
|||||||
|
<table
|
||||||
<table class="table" hx-get="/item/{{item_id}}/adjustments" hx-trigger="new-adjustment from:body" hx-swap="outerHTML">
|
class="w-full text-left text-sm rtl:text-right"
|
||||||
<thead>
|
hx-get="/item/{{item_id}}/adjustments"
|
||||||
|
hx-trigger="new-adjustment from:body"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
>
|
||||||
|
<thead
|
||||||
|
class="bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-400"
|
||||||
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Date</th>
|
<th class="px-6 py-3" scope="col">Date</th>
|
||||||
<th scope="col">Amount</th>
|
<th class="px-6 py-3" scope="col">Amount</th>
|
||||||
<th scope="col">Reason</th>
|
<th class="px-6 py-3" scope="col">Reason</th>
|
||||||
<th scope="col">Unit Value</th>
|
<th class="px-6 py-3" scope="col">Unit Value</th>
|
||||||
<th scope="col">Running Total</th>
|
<th class="px-6 py-3" scope="col">Running Total</th>
|
||||||
<th scope="col">Running Value</th>
|
<th class="px-6 py-3" scope="col">Running Value</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for item in adjustments %}
|
{% for item in adjustments %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ item.date }}</td>
|
<td class="px-6 py-4">{{ item.date }}</td>
|
||||||
<td>{{ item.amount }}</td>
|
<td class="px-6 py-4">{{ item.amount }}</td>
|
||||||
<td>{{ item.reason }}</td>
|
<td class="px-6 py-4">{{ item.reason }}</td>
|
||||||
<td>{{ item.unit_value }}</td>
|
<td class="px-6 py-4">{{ item.unit_value }}</td>
|
||||||
<td>{{ item.tally }}</td>
|
<td class="px-6 py-4">{{ item.tally }}</td>
|
||||||
<td>{{ item.tally_value }}</td>
|
<td class="px-6 py-4">{{ item.tally_value }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@ -1,65 +1,119 @@
|
|||||||
<form hx-post="/item/{{item_id}}/adjustment/negative"
|
<form
|
||||||
hx-target="this" hx-swap="outerHTML"
|
hx-post="/item/{{item_id}}/adjustment/negative"
|
||||||
x-ref="formNegativeAdjustment"
|
hx-target="this"
|
||||||
x-data="{ reason: 'Sale' }">
|
hx-swap="outerHTML"
|
||||||
<input id="reason" name="reason" type="hidden" x-model="reason"/>
|
x-ref="formNegativeAdjustment"
|
||||||
<div class="row">
|
x-data="{ reason: 'Sale', reason_dropdown_show: false }"
|
||||||
<div class="col">
|
>
|
||||||
<!--<label for="amount" class="form-label">Amount</label>-->
|
<div class="mb-5">
|
||||||
<input type="number"
|
<label for="amount" class="mb-2 block text-sm font-medium">Amount</label>
|
||||||
id="amount"
|
<input
|
||||||
name="amount"
|
type="number"
|
||||||
step="0.01"
|
id="amount"
|
||||||
class="form-control"
|
name="amount"
|
||||||
placeholder="Amount"
|
step="0.01"
|
||||||
aria-label="amount"
|
class="block max-w-56 rounded-lg border border-neutral-900 p-2.5 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:text-slate-100"
|
||||||
required
|
placeholder="Amount"
|
||||||
{% if !amount_error.is_empty() -%}
|
aria-label="amount"
|
||||||
aria-invalid="true"
|
required
|
||||||
aria-describedby="invalid-amount"
|
{%
|
||||||
{% endif -%}
|
if
|
||||||
/>
|
!amount_error.is_empty()
|
||||||
{% if !amount_error.is_empty() -%}
|
-%}
|
||||||
<small id="invalid-amount" class="invalid-feedback">{{ amount_error }}</small>
|
aria-invalid="true"
|
||||||
{% endif -%}
|
aria-describedby="invalid-amount"
|
||||||
</div>
|
{%
|
||||||
<div class="col">
|
endif
|
||||||
<button class="btn btn-primary" x-text="reason">Sale</button>
|
-%}
|
||||||
|
/>
|
||||||
</div>
|
{% if !amount_error.is_empty() -%}
|
||||||
<div class="col">
|
<small id="invalid-amount" class="mt-2 text-sm text-cerise">
|
||||||
<div class="dropdown">
|
{{ amount_error }}
|
||||||
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown"
|
</small>
|
||||||
aria-expanded="false">
|
{% endif -%}
|
||||||
<span class="visually-hidden">Other</span>
|
</div>
|
||||||
</button>
|
<div class="mb-5 flex justify-start">
|
||||||
<ul class="dropdown-menu">
|
<button
|
||||||
<li>
|
class="rounded-l-lg bg-english-violet px-5 py-2.5 text-sm font-medium text-slate-100 hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan"
|
||||||
<a class="dropdown-item"
|
x-text="reason"
|
||||||
@click="reason = 'Sale'">
|
>
|
||||||
Sale
|
Sale
|
||||||
</a>
|
</button>
|
||||||
</li>
|
<div
|
||||||
<li>
|
x-data="{ isOpen: false, openedWithKeyboard: false }"
|
||||||
<a class="dropdown-item"
|
class="relative w-fit"
|
||||||
@click="reason = 'Destruction'">
|
x-on:keydown.esc.window="isOpen = false; openedWithKeyboard = false"
|
||||||
Destruction
|
>
|
||||||
</a>
|
<button
|
||||||
</li>
|
type="button"
|
||||||
<li>
|
x-on:click="isOpen = ! isOpen"
|
||||||
<a class="dropdown-item"
|
class="rounded-radius inline-flex items-center whitespace-nowrap rounded-r-lg border-l-2 border-slate-100 bg-english-violet px-3.5 py-3.5 text-sm font-medium tracking-wide text-slate-100 transition hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan dark:border-neutral-900"
|
||||||
@click="reason = 'Expiration'">
|
aria-haspopup="true"
|
||||||
Expiration
|
x-on:keydown.space.prevent="openedWithKeyboard = true"
|
||||||
</a>
|
x-on:keydown.enter.prevent="openedWithKeyboard = true"
|
||||||
</li>
|
x-on:keydown.down.prevent="openedWithKeyboard = true"
|
||||||
<li>
|
x-bind:class="isOpen || openedWithKeyboard ? 'text-on-surface-strong dark:text-on-surface-dark-strong' : 'text-on-surface dark:text-on-surface-dark'"
|
||||||
<a class="dropdown-item"
|
x-bind:aria-expanded="isOpen || openedWithKeyboard"
|
||||||
@click="reason = 'Theft'">
|
>
|
||||||
Theft
|
<span class="sr-only">Reason Options</span>
|
||||||
</a>
|
<svg
|
||||||
</li>
|
aria-hidden="true"
|
||||||
</ul>
|
fill="none"
|
||||||
</div>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
</div>
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="size-4 rotate-0"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M19.5 8.25l-7.5 7.5-7.5-7.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<!-- Dropdown Menu -->
|
||||||
|
<div
|
||||||
|
x-cloak
|
||||||
|
x-show="isOpen || openedWithKeyboard"
|
||||||
|
x-transition
|
||||||
|
x-trap="openedWithKeyboard"
|
||||||
|
x-on:click.outside="isOpen = false, openedWithKeyboard = false"
|
||||||
|
x-on:keydown.down.prevent="$focus.wrap().next()"
|
||||||
|
x-on:keydown.up.prevent="$focus.wrap().previous()"
|
||||||
|
class="rounded-radius border-outline absolute left-0 top-11 flex w-fit min-w-48 flex-col overflow-hidden border border-neutral-900 bg-slate-100 dark:border-slate-100 dark:bg-neutral-900"
|
||||||
|
role="menu"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="focus-visible:outline-hidden px-4 py-2 text-sm hover:bg-dark-cyan hover:font-semibold focus-visible:bg-dark-cyan focus-visible:font-semibold"
|
||||||
|
role="menuitem"
|
||||||
|
@click="reason = 'Sale'; isOpen = false"
|
||||||
|
>
|
||||||
|
Sale
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="focus-visible:outline-hidden px-4 py-2 text-sm hover:bg-dark-cyan hover:font-semibold focus-visible:bg-dark-cyan focus-visible:font-semibold"
|
||||||
|
role="menuitem"
|
||||||
|
@click="reason = 'Destruction'; isOpen = false"
|
||||||
|
>
|
||||||
|
Destruction
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="focus-visible:outline-hidden px-4 py-2 text-sm hover:bg-dark-cyan hover:font-semibold focus-visible:bg-dark-cyan focus-visible:font-semibold"
|
||||||
|
role="menuitem"
|
||||||
|
@click="reason = 'Expiration'; isOpen = false"
|
||||||
|
>
|
||||||
|
Expiration
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="focus-visible:outline-hidden px-4 py-2 text-sm hover:bg-dark-cyan hover:font-semibold focus-visible:bg-dark-cyan focus-visible:font-semibold"
|
||||||
|
role="menuitem"
|
||||||
|
@click="reason = 'Theft'; isOpen = false"
|
||||||
|
>
|
||||||
|
Theft
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<input id="reason" name="reason" type="hidden" x-model="reason" />
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -1,43 +1,66 @@
|
|||||||
|
<form
|
||||||
<form hx-post="/item/{{item_id}}/adjustment/positive" hx-target="this" hx-swap="outerHTML" >
|
hx-post="/item/{{item_id}}/adjustment/positive"
|
||||||
<div class="row">
|
hx-target="this"
|
||||||
<div class="col">
|
hx-swap="outerHTML"
|
||||||
<input type="number"
|
>
|
||||||
id="amount"
|
<div class="mb-5">
|
||||||
name="amount"
|
<label for="amount" class="mb-2 block text-sm font-medium">Amount</label>
|
||||||
step="0.01"
|
<input
|
||||||
class="form-control"
|
type="number"
|
||||||
placeholder="Amount"
|
id="amount"
|
||||||
aria-label="amount"
|
name="amount"
|
||||||
required
|
class="block max-w-56 rounded-lg border border-neutral-900 p-2.5 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:text-slate-100"
|
||||||
{% if !amount_error.is_empty() -%}
|
step="0.01"
|
||||||
aria-invalid="true"
|
placeholder="Amount"
|
||||||
aria-describedby="invalid-amount"
|
aria-label="amount"
|
||||||
{% endif -%}
|
required
|
||||||
/>
|
{%
|
||||||
{% if !amount_error.is_empty() -%}
|
if
|
||||||
<small id="invalid-amount" class="invalid-feedback">{{ amount_error }}</small>
|
!amount_error.is_empty()
|
||||||
{% endif -%}
|
-%}
|
||||||
</div>
|
aria-invalid="true"
|
||||||
<div class="col">
|
aria-describedby="invalid-amount"
|
||||||
<input type="text"
|
{%
|
||||||
id="price"
|
endif
|
||||||
name="price"
|
-%}
|
||||||
placeholder="Price"
|
/>
|
||||||
class="form-control"
|
{% if !amount_error.is_empty() -%}
|
||||||
aria-label="price"
|
<small id="invalid-amount" class="mt-2 text-sm text-cerise">
|
||||||
required
|
{{ amount_error }}
|
||||||
{% if !price_error.is_empty() -%}
|
</small>
|
||||||
aria-invalid="true"
|
{% endif -%}
|
||||||
aria-describedby="invalid-price"
|
</div>
|
||||||
{% endif -%}
|
<div class="mb-5">
|
||||||
/>
|
<label for="price" class="mb-2 block text-sm font-medium">Price</label>
|
||||||
{% if !price_error.is_empty() -%}
|
<input
|
||||||
<small id="invalid-price" class="invalid-feedback">{{ price_error }}</small>
|
type="text"
|
||||||
{% endif -%}
|
id="price"
|
||||||
</div>
|
name="price"
|
||||||
<div class="col">
|
class="block max-w-56 rounded-lg border border-neutral-900 p-2.5 text-sm text-neutral-900 focus:border-paynes-gray focus:ring-paynes-gray dark:text-slate-100"
|
||||||
<button class="btn btn-primary">Add</button>
|
placeholder="Price"
|
||||||
</div>
|
aria-label="price"
|
||||||
</div>
|
required
|
||||||
|
{%
|
||||||
|
if
|
||||||
|
!price_error.is_empty()
|
||||||
|
-%}
|
||||||
|
aria-invalid="true"
|
||||||
|
aria-describedby="invalid-price"
|
||||||
|
{%
|
||||||
|
endif
|
||||||
|
-%}
|
||||||
|
/>
|
||||||
|
{% if !price_error.is_empty() -%}
|
||||||
|
<small id="invalid-price" class="mt-2 text-sm text-cerise"
|
||||||
|
>{{ price_error }}</small
|
||||||
|
>
|
||||||
|
{% endif -%}
|
||||||
|
</div>
|
||||||
|
<div class="mb-5">
|
||||||
|
<button
|
||||||
|
class="mb-2 me-2 rounded-lg bg-english-violet px-5 py-2.5 text-sm font-medium text-slate-100 hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan"
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -1,53 +1,66 @@
|
|||||||
{% extends "main.html" %}
|
{% extends "main.html" %} {% block title %} Items {% endblock %} {% block
|
||||||
|
content %}
|
||||||
|
|
||||||
{% block title %} Items {% endblock %}
|
<h2 class="mb-4 flex items-center text-4xl font-extrabold">
|
||||||
|
{{item.name}} {% if !item.active %}
|
||||||
|
<span
|
||||||
|
class="me-2 ms-2 rounded border border-cerise bg-orchid-pink px-2.5 py-0.5 text-2xl font-semibold text-cerise"
|
||||||
|
>
|
||||||
|
Inactive
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</h2>
|
||||||
|
|
||||||
{% block content %}
|
<section
|
||||||
|
hx-get="/item/{{item_id}}/stats"
|
||||||
<div class="container mb-5">
|
hx-trigger="load"
|
||||||
<h2>{{item.name}} {% if !item.active %}<span class="badge text-bg-danger">Inactive</span> {% endif %}</h2>
|
hx-swap="outerHTML"
|
||||||
</div>
|
></section>
|
||||||
|
|
||||||
<section class="container">
|
|
||||||
<div hx-get="/item/{{item_id}}/stats" hx-trigger="load" hx-swap="outerHTML">
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{% if item.active %}
|
{% if item.active %}
|
||||||
<section class="container-fluid">
|
<section
|
||||||
|
class="mx-auto mb-5"
|
||||||
|
x-data="{ negative_form_open: false, positive_form_open: false }"
|
||||||
|
>
|
||||||
|
<div class="flex justify-evenly">
|
||||||
|
<button
|
||||||
|
class="mb-2 me-2 rounded-lg bg-paynes-gray px-5 py-2.5 text-sm font-medium text-slate-100 hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan"
|
||||||
|
@click="negative_form_open = ! negative_form_open"
|
||||||
|
>
|
||||||
|
Minus
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="mb-2 me-2 rounded-lg bg-paynes-gray px-5 py-2.5 text-sm font-medium text-slate-100 hover:bg-dark-cyan focus:outline-none focus:ring-4 focus:ring-dark-cyan"
|
||||||
|
@click="positive_form_open = ! positive_form_open"
|
||||||
|
>
|
||||||
|
Plus
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div x-data="{ open: false }" class="mb-3">
|
<div x-show="negative_form_open" @click.outside="negative_form_open = false">
|
||||||
<div class="d-flex justify-content-start">
|
<div
|
||||||
<div class="me-3">
|
hx-get="/item/{{item_id}}/adjustment/negative"
|
||||||
<button class="btn btn-primary display-6" @click="open = ! open">
|
hx-trigger="load"
|
||||||
Minus
|
hx-swap="outerHTML"
|
||||||
</button>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div x-show="open" @click.outside="open = false">
|
|
||||||
<div hx-get="/item/{{item_id}}/adjustment/negative" hx-trigger="load" hx-swap="outerHTML"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div x-data="{ open: false }" class="mb-3">
|
<div x-show="positive_form_open" @click.outside="positive_form_open = false">
|
||||||
<div class="d-flex justify-content-start">
|
<div
|
||||||
<div class="me-3">
|
hx-get="/item/{{item_id}}/adjustment/positive"
|
||||||
<button class="btn btn-primary" @click="open = ! open">
|
hx-trigger="load"
|
||||||
Plus
|
hx-swap="outerHTML"
|
||||||
</button>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div x-show="open" @click.outside="open = false">
|
|
||||||
<div hx-get="/item/{{item_id}}/adjustment/positive" hx-trigger="load" hx-swap="outerHTML">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<section class="container">
|
<section class="mx-auto">
|
||||||
<div hx-get="/item/{{item_id}}/adjustments" hx-trigger="load" hx-swap="outerHTML">
|
<div
|
||||||
</div>
|
hx-get="/item/{{item_id}}/adjustments"
|
||||||
|
hx-trigger="load"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
{% extends "main.html" %}
|
{% extends "main.html" %} {% block content %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>Logged out</h1>
|
<h1>Logged out</h1>
|
||||||
<p>You have been logged out</p>
|
<p>You have been logged out</p>
|
||||||
<p><a href="/auth/login">Log In</a></p>
|
<p><a href="/auth/login">Log In</a></p>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,53 +1,83 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en" data-bs-theme="dark">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="color-scheme" content="light dark">
|
<meta name="color-scheme" content="light dark" />
|
||||||
<!-- <link rel="stylesheet" href="/css/pico.min.css" > -->
|
<link rel="stylesheet" href="/css/main.css" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<!--TODO Vendor css-->
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
|
||||||
|
|
||||||
<script src="/js/htmx.min.js"></script>
|
<script src="/js/htmx.min.js"></script>
|
||||||
<!--TODO Vendor this script -->
|
<!--TODO Vendor this script -->
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
<script
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
defer
|
||||||
|
src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"
|
||||||
|
></script>
|
||||||
<title>{% block title %}Title{% endblock %}</title>
|
<title>{% block title %}Title{% endblock %}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body
|
||||||
<header class="container mb-4">
|
class="min-h-screen bg-slate-100 text-neutral-900 dark:bg-neutral-900 dark:text-slate-100"
|
||||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
>
|
||||||
<div class="container-fluid">
|
<header class="top-0 w-full mb-4 bg-space-cadet font-sans">
|
||||||
<a class="navbar-brand" href="/home">Inventory App</a>
|
<nav
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
class="mx-auto flex max-w-7xl justify-between gap-2 px-2 py-4 sm:px-6 lg:px-8"
|
||||||
<span class="navbar-toggler-icon"></span>
|
>
|
||||||
</button>
|
<div>
|
||||||
<div class="collapse navbar-collapse justify-content-end" id="navbarNav">
|
<a
|
||||||
<ul class="navbar-nav ">
|
href="/home"
|
||||||
<li class="nav-item"><h1></h1></li>
|
class="rounded-md bg-english-violet px-3 py-2 text-sm font-medium text-white"
|
||||||
<li class="nav-item"><a class="nav-link" href="/overview">Overview</a></li>
|
>
|
||||||
<li class="nav-item"><a class="nav-link" href="/catalog">Catalog</a></li>
|
Inventory App
|
||||||
<li class="nav-item"><a class="nav-link" href="/upload">Upload</a></li>
|
</a>
|
||||||
<li class="nav-item"><a class="nav-link" href="/reports">Reports</a></li>
|
|
||||||
<li class="nav-item"><a class="nav-link" href="/history">History</a></li>
|
|
||||||
</ul>
|
|
||||||
<div class="d-flex">
|
|
||||||
<a class="btn btn-primary" href="/auth/logout">Logout</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
<div>
|
||||||
</header>
|
<a
|
||||||
<main class="container">
|
href="/overview"
|
||||||
{% block content %}<p>Content Missing</p>{% endblock %}
|
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
|
||||||
</main>
|
>
|
||||||
<footer class="container-fluid">
|
Overview
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/catalog"
|
||||||
|
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
|
||||||
|
>
|
||||||
|
Catalog
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/upload"
|
||||||
|
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/reports"
|
||||||
|
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
|
||||||
|
>
|
||||||
|
Reports
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/history"
|
||||||
|
class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white"
|
||||||
|
>
|
||||||
|
History
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main
|
||||||
|
class="relative mx-auto max-w-[68.75rem] w-[95vw] bg-slate-100 px-1 text-neutral-900 dark:bg-neutral-900 dark:text-slate-100"
|
||||||
|
>
|
||||||
|
{% block content %}
|
||||||
|
<p>Content Missing</p>
|
||||||
|
{% endblock %}
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<!--
|
||||||
<script>
|
<script>
|
||||||
// Needed for nice bootstrap dropdowns
|
// Needed for nice bootstrap dropdowns
|
||||||
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="dropdown"]');
|
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="dropdown"]');
|
||||||
const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl))
|
const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl))
|
||||||
</script>
|
</script>
|
||||||
</footer>
|
--></footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
{% extends "problem.html" %}
|
{% extends "problem.html" %} {% block content %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>Not Found</h1>
|
<h1>Not Found</h1>
|
||||||
<p>
|
<p>
|
||||||
Sorry, we can't seem to find the page you're looking for. Please press back button or return
|
Sorry, we can't seem to find the page you're looking for. Please press back
|
||||||
<a href="/">home</a>.
|
button or return
|
||||||
|
<a href="/">home</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
{% extends "main.html" %}
|
{% extends "main.html" %} {% block title %} Overview {% endblock %} {% block
|
||||||
|
content %}
|
||||||
{% block title %} Overview {% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>Overview (Coming soon)</h1>
|
<h1>Overview (Coming soon)</h1>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="color-scheme" content="light dark">
|
<meta name="color-scheme" content="light dark" />
|
||||||
<link rel="stylesheet" href="/css/pico.min.css">
|
<link rel="stylesheet" href="/css/pico.min.css" />
|
||||||
<script src="/js/htmx.min.js"></script>
|
<script src="/js/htmx.min.js"></script>
|
||||||
<title>Problem</title>
|
<title>Problem</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main class="container">
|
<main class="container">
|
||||||
{% block content %}<p>Something went wrong</p>{% endblock %}
|
{% block content %}
|
||||||
</main>
|
<p>Something went wrong</p>
|
||||||
</body>
|
{% endblock %}
|
||||||
</html>
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
{% extends "main.html" %}
|
{% extends "main.html" %} {% block title %} Reports {% endblock %} {% block
|
||||||
|
content %}
|
||||||
{% block title %} Reports {% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>Reports (Coming soon)</h1>
|
<h1>Reports (Coming soon)</h1>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,19 +1,27 @@
|
|||||||
{% extends "main.html" %}
|
{% extends "main.html" %} {% block title %} Upload {% endblock %} {% block
|
||||||
|
content %}
|
||||||
|
|
||||||
{% block title %} Upload {% endblock %}
|
<form
|
||||||
|
action="/upload/catalog"
|
||||||
{% block content %}
|
method="post"
|
||||||
|
enctype="multipart/form-data"
|
||||||
<form action="/upload/catalog" method="post" enctype="multipart/form-data" x-data="{ file: '' }">
|
x-data="{ file: '' }"
|
||||||
<fieldset class="grid">
|
>
|
||||||
<h3>Catalog Import</h3>
|
<fieldset class="grid">
|
||||||
<label role="button" class="secondary" x-show="!file">
|
<h3>Catalog Import</h3>
|
||||||
Choose File
|
<label role="button" class="secondary" x-show="!file">
|
||||||
<input type="file" name="file" x-model="file" style="display: none" required />
|
Choose File
|
||||||
</label>
|
<input
|
||||||
<input type="submit" value="Upload" x-show="file">
|
type="file"
|
||||||
<input type="reset" value="Cancel" x-show="file">
|
name="file"
|
||||||
</fieldset>
|
x-model="file"
|
||||||
|
style="display: none"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<input type="submit" value="Upload" x-show="file" />
|
||||||
|
<input type="reset" value="Cancel" x-show="file" />
|
||||||
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Loading…
Reference in new issue