lets add settings new to css
This commit is contained in:
152
py_app/CSS_MODULAR_GUIDE.md
Normal file
152
py_app/CSS_MODULAR_GUIDE.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# CSS Modular Structure Guide
|
||||
|
||||
## Overview
|
||||
This guide explains how to migrate from a monolithic CSS file to a modular CSS structure for better maintainability and organization.
|
||||
|
||||
## New CSS Structure
|
||||
|
||||
```
|
||||
app/static/css/
|
||||
├── base.css # Global styles, header, buttons, theme
|
||||
├── login.css # Login page specific styles
|
||||
├── dashboard.css # Dashboard and module cards
|
||||
├── warehouse.css # Warehouse module styles
|
||||
├── etichete.css # Labels/etiquette module styles (to be created)
|
||||
├── quality.css # Quality module styles (to be created)
|
||||
└── scan.css # Scan module styles (to be created)
|
||||
```
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Phase 1: Setup Modular Structure ✅
|
||||
- [x] Created `css/` directory
|
||||
- [x] Created `base.css` with global styles
|
||||
- [x] Created `login.css` for login page
|
||||
- [x] Created `warehouse.css` for warehouse module
|
||||
- [x] Updated `base.html` to include modular CSS
|
||||
- [x] Updated `login.html` to use new structure
|
||||
|
||||
### Phase 2: Migration Plan (Next Steps)
|
||||
|
||||
1. **Extract module-specific styles from style.css:**
|
||||
- Etiquette/Labels module → `etichete.css`
|
||||
- Quality module → `quality.css`
|
||||
- Scan module → `scan.css`
|
||||
|
||||
2. **Update templates to use modular CSS:**
|
||||
```html
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/module-name.css') }}">
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
3. **Clean up original style.css:**
|
||||
- Remove extracted styles
|
||||
- Keep only legacy/common styles temporarily
|
||||
- Eventually eliminate when all modules migrated
|
||||
|
||||
## Template Usage Pattern
|
||||
|
||||
### Standard Template Structure:
|
||||
```html
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Page Title{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<!-- Include module-specific CSS -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/module-name.css') }}">
|
||||
<!-- Page-specific overrides -->
|
||||
<style>
|
||||
/* Only use this for page-specific customizations */
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Page content -->
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
## CSS Loading Order
|
||||
|
||||
1. `base.css` - Global styles, header, buttons, theme
|
||||
2. `style.css` - Legacy styles (temporary, for backward compatibility)
|
||||
3. Module-specific CSS (e.g., `warehouse.css`)
|
||||
4. Inline `<style>` blocks for page-specific overrides
|
||||
|
||||
## Benefits of This Structure
|
||||
|
||||
### 1. **Maintainability**
|
||||
- Easy to find and edit module-specific styles
|
||||
- Reduced conflicts between different modules
|
||||
- Clear separation of concerns
|
||||
|
||||
### 2. **Performance**
|
||||
- Only load CSS needed for specific pages
|
||||
- Smaller file sizes per page
|
||||
- Better caching (module CSS rarely changes)
|
||||
|
||||
### 3. **Team Development**
|
||||
- Different developers can work on different modules
|
||||
- Less merge conflicts in CSS files
|
||||
- Clear ownership of styles
|
||||
|
||||
### 4. **Scalability**
|
||||
- Easy to add new modules
|
||||
- Simple to deprecate old styles
|
||||
- Clear migration path
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
### For Each Template:
|
||||
- [ ] Identify module/page type
|
||||
- [ ] Extract relevant styles to module CSS file
|
||||
- [ ] Update template to include module CSS
|
||||
- [ ] Test styling works correctly
|
||||
- [ ] Remove old styles from style.css
|
||||
|
||||
### Current Status:
|
||||
- [x] Login page - Fully migrated
|
||||
- [x] Warehouse module - Partially migrated (create_locations.html updated)
|
||||
- [ ] Dashboard - CSS created, templates need updating
|
||||
- [ ] Etiquette module - Needs CSS extraction
|
||||
- [ ] Quality module - Needs CSS extraction
|
||||
- [ ] Scan module - Needs CSS extraction
|
||||
|
||||
## Example: Migrating a Template
|
||||
|
||||
### Before:
|
||||
```html
|
||||
{% block head %}
|
||||
<style>
|
||||
.my-module-specific-class {
|
||||
/* styles here */
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
### After:
|
||||
1. Move styles to `css/module-name.css`
|
||||
2. Update template:
|
||||
```html
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/module-name.css') }}">
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use semantic naming:** `warehouse.css`, `login.css`, not `page1.css`
|
||||
2. **Keep base.css minimal:** Only truly global styles
|
||||
3. **Avoid deep nesting:** Keep CSS selectors simple
|
||||
4. **Use consistent naming:** Follow existing patterns
|
||||
5. **Document changes:** Update this guide when adding new modules
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Extract etiquette module styles to `etichete.css`
|
||||
2. Update all etiquette templates to use new CSS
|
||||
3. Extract quality module styles to `quality.css`
|
||||
4. Extract scan module styles to `scan.css`
|
||||
5. Gradually remove migrated styles from `style.css`
|
||||
6. Eventually remove `style.css` dependency from `base.html`
|
||||
133
py_app/MOBILE_LOGIN_GUIDE.md
Normal file
133
py_app/MOBILE_LOGIN_GUIDE.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# Mobile-Responsive Login Page
|
||||
|
||||
## Overview
|
||||
The login page has been enhanced with comprehensive mobile-responsive CSS to provide an optimal user experience across all device types and screen sizes.
|
||||
|
||||
## Mobile-Responsive Features Added
|
||||
|
||||
### 1. **Responsive Breakpoints**
|
||||
- **Tablet (≤768px)**: Column layout, optimized logo and form sizing
|
||||
- **Mobile (≤480px)**: Enhanced touch targets, better spacing
|
||||
- **Small Mobile (≤320px)**: Minimal padding, compact design
|
||||
- **Landscape (height ≤500px)**: Horizontal layout for landscape phones
|
||||
|
||||
### 2. **Layout Adaptations**
|
||||
|
||||
#### Desktop (>768px)
|
||||
- Side-by-side logo and form layout
|
||||
- Large logo (90vh height)
|
||||
- Fixed form width (600px)
|
||||
|
||||
#### Tablet (≤768px)
|
||||
- Vertical stacked layout
|
||||
- Logo height reduced to 30vh
|
||||
- Form width becomes responsive (100%, max 400px)
|
||||
|
||||
#### Mobile (≤480px)
|
||||
- Optimized touch targets (44px minimum)
|
||||
- Increased padding and margins
|
||||
- Better visual hierarchy
|
||||
- Enhanced shadows and border radius
|
||||
|
||||
#### Small Mobile (≤320px)
|
||||
- Minimal padding to maximize space
|
||||
- Compact logo (20vh height)
|
||||
- Reduced font sizes where appropriate
|
||||
|
||||
### 3. **Touch Optimizations**
|
||||
|
||||
#### iOS/Safari Specific
|
||||
- `font-size: 16px` on inputs prevents automatic zoom
|
||||
- Proper touch target sizing (44px minimum)
|
||||
|
||||
#### Touch Device Enhancements
|
||||
- Active states for button presses
|
||||
- Optimized image rendering for high DPI screens
|
||||
- Hover effects disabled on touch devices
|
||||
|
||||
### 4. **Accessibility Improvements**
|
||||
- Proper contrast ratios maintained
|
||||
- Touch targets meet accessibility guidelines
|
||||
- Readable font sizes across all devices
|
||||
- Smooth transitions and animations
|
||||
|
||||
### 5. **Performance Considerations**
|
||||
- CSS-only responsive design (no JavaScript required)
|
||||
- Efficient media queries
|
||||
- Optimized image rendering for retina displays
|
||||
|
||||
## Key CSS Features
|
||||
|
||||
### Flexible Layout
|
||||
```css
|
||||
.login-page {
|
||||
display: flex;
|
||||
flex-direction: column; /* Mobile */
|
||||
justify-content: center;
|
||||
}
|
||||
```
|
||||
|
||||
### Responsive Images
|
||||
```css
|
||||
.login-logo {
|
||||
max-height: 25vh; /* Mobile */
|
||||
max-width: 85vw;
|
||||
}
|
||||
```
|
||||
|
||||
### Touch-Friendly Inputs
|
||||
```css
|
||||
.form-container input {
|
||||
padding: 12px;
|
||||
font-size: 16px; /* Prevents iOS zoom */
|
||||
min-height: 44px; /* Touch target size */
|
||||
}
|
||||
```
|
||||
|
||||
### Landscape Optimization
|
||||
```css
|
||||
@media screen and (max-height: 500px) and (orientation: landscape) {
|
||||
.login-page {
|
||||
flex-direction: row; /* Back to horizontal */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
### Device Testing
|
||||
- [ ] iPhone (various sizes)
|
||||
- [ ] Android phones (various sizes)
|
||||
- [ ] iPad/Android tablets
|
||||
- [ ] Desktop browsers with responsive mode
|
||||
|
||||
### Orientation Testing
|
||||
- [ ] Portrait mode on all devices
|
||||
- [ ] Landscape mode on phones
|
||||
- [ ] Landscape mode on tablets
|
||||
|
||||
### Browser Testing
|
||||
- [ ] Safari (iOS)
|
||||
- [ ] Chrome (Android/iOS)
|
||||
- [ ] Firefox Mobile
|
||||
- [ ] Samsung Internet
|
||||
- [ ] Desktop browsers (Chrome, Firefox, Safari, Edge)
|
||||
|
||||
## Browser Support
|
||||
- Modern browsers (ES6+ support)
|
||||
- iOS Safari 12+
|
||||
- Android Chrome 70+
|
||||
- Desktop browsers (last 2 versions)
|
||||
|
||||
## Performance Impact
|
||||
- **CSS Size**: Increased by ~2KB (compressed)
|
||||
- **Load Time**: No impact (CSS only)
|
||||
- **Rendering**: Optimized for mobile GPUs
|
||||
- **Memory**: Minimal additional usage
|
||||
|
||||
## Future Enhancements
|
||||
1. **Dark mode mobile optimizations**
|
||||
2. **Progressive Web App (PWA) features**
|
||||
3. **Biometric authentication UI**
|
||||
4. **Loading states and animations**
|
||||
5. **Error message responsive design**
|
||||
BIN
py_app/app/__pycache__/__init__.cpython-312.pyc
Executable file → Normal file
BIN
py_app/app/__pycache__/__init__.cpython-312.pyc
Executable file → Normal file
Binary file not shown.
BIN
py_app/app/__pycache__/models.cpython-312.pyc
Executable file → Normal file
BIN
py_app/app/__pycache__/models.cpython-312.pyc
Executable file → Normal file
Binary file not shown.
BIN
py_app/app/__pycache__/permissions.cpython-312.pyc
Executable file → Normal file
BIN
py_app/app/__pycache__/permissions.cpython-312.pyc
Executable file → Normal file
Binary file not shown.
BIN
py_app/app/__pycache__/routes.cpython-312.pyc
Executable file → Normal file
BIN
py_app/app/__pycache__/routes.cpython-312.pyc
Executable file → Normal file
Binary file not shown.
BIN
py_app/app/__pycache__/settings.cpython-312.pyc
Executable file → Normal file
BIN
py_app/app/__pycache__/settings.cpython-312.pyc
Executable file → Normal file
Binary file not shown.
BIN
py_app/app/__pycache__/warehouse.cpython-312.pyc
Executable file → Normal file
BIN
py_app/app/__pycache__/warehouse.cpython-312.pyc
Executable file → Normal file
Binary file not shown.
@@ -2382,6 +2382,41 @@ def generate_location_label_pdf():
|
||||
from app.warehouse import generate_location_label_pdf
|
||||
return generate_location_label_pdf()
|
||||
|
||||
@warehouse_bp.route('/update_location', methods=['POST'])
|
||||
def update_location():
|
||||
from app.warehouse import update_location
|
||||
try:
|
||||
data = request.get_json()
|
||||
location_id = data.get('location_id')
|
||||
location_code = data.get('location_code')
|
||||
size = data.get('size')
|
||||
description = data.get('description')
|
||||
|
||||
if not location_id or not location_code:
|
||||
return jsonify({'success': False, 'error': 'Location ID and code are required'})
|
||||
|
||||
result = update_location(location_id, location_code, size, description)
|
||||
return jsonify(result)
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)})
|
||||
|
||||
@warehouse_bp.route('/delete_location', methods=['POST'])
|
||||
def delete_location():
|
||||
from app.warehouse import delete_location_by_id
|
||||
try:
|
||||
data = request.get_json()
|
||||
location_id = data.get('location_id')
|
||||
|
||||
if not location_id:
|
||||
return jsonify({'success': False, 'error': 'Location ID is required'})
|
||||
|
||||
result = delete_location_by_id(location_id)
|
||||
return jsonify(result)
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)})
|
||||
|
||||
|
||||
# NOTE for frontend/extension developers:
|
||||
# To print labels, call the Chrome extension and pass the PDF URL:
|
||||
|
||||
149
py_app/app/static/css/base.css
Normal file
149
py_app/app/static/css/base.css
Normal file
@@ -0,0 +1,149 @@
|
||||
/* Global Base Styles - Common across all pages */
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f4f4f9;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: none;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Header Styles */
|
||||
header {
|
||||
padding: 10px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.left-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.left-header .logo {
|
||||
width: 60px;
|
||||
height: auto;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.left-header .page-title {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.right-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.right-header .user-info {
|
||||
margin-right: 15px;
|
||||
font-size: 1em;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.right-header .logout-button {
|
||||
padding: 5px 10px;
|
||||
font-size: 1em;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.right-header .logout-button:hover {
|
||||
background-color: #0056b3;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Common Button Styles */
|
||||
.btn {
|
||||
padding: 8px 16px;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
background-color: #17a2b8;
|
||||
}
|
||||
|
||||
.btn-info:hover {
|
||||
background-color: #138496;
|
||||
}
|
||||
|
||||
/* Theme Toggle */
|
||||
.theme-toggle {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.theme-toggle:hover {
|
||||
background-color: #5a6268;
|
||||
}
|
||||
|
||||
/* Dark Mode Base Styles */
|
||||
body.dark-mode {
|
||||
background-color: #121212;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode header {
|
||||
background-color: #1e1e1e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .user-info {
|
||||
color: #ccc;
|
||||
}
|
||||
67
py_app/app/static/css/dashboard.css
Normal file
67
py_app/app/static/css/dashboard.css
Normal file
@@ -0,0 +1,67 @@
|
||||
/* Dashboard and General Page Styles */
|
||||
|
||||
.dashboard-container {
|
||||
padding: 20px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.module-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.module-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.module-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.module-card h3 {
|
||||
margin: 0 0 15px 0;
|
||||
color: #333;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.module-card p {
|
||||
color: #666;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.module-card a {
|
||||
display: inline-block;
|
||||
padding: 8px 16px;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.module-card a:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
/* Dark mode for dashboard */
|
||||
body.dark-mode .module-card {
|
||||
background: #2d2d2d;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode .module-card h3 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .module-card p {
|
||||
color: #ccc;
|
||||
}
|
||||
216
py_app/app/static/css/login.css
Normal file
216
py_app/app/static/css/login.css
Normal file
@@ -0,0 +1,216 @@
|
||||
/* Login Page Specific Styles */
|
||||
|
||||
.login-page {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 100vh;
|
||||
background-color: #f4f4f9;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
max-height: 90vh;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
width: 600px;
|
||||
background: #fff;
|
||||
padding: 15px 30px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
margin: 0;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.form-container h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-container form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.form-container label {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.form-container input {
|
||||
margin-bottom: 10px;
|
||||
padding: 8px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
font-size: 16px; /* Prevents zoom on iOS */
|
||||
}
|
||||
|
||||
.form-container button {
|
||||
padding: 10px;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.form-container button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
/* Hide the header only on the login page */
|
||||
body.light-mode.login-page header,
|
||||
body.dark-mode.login-page header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Mobile Responsive Design */
|
||||
|
||||
/* Tablet styles (768px and down) */
|
||||
@media screen and (max-width: 768px) {
|
||||
.login-page {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 20px 15px;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
max-height: 30vh;
|
||||
max-width: 80vw;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
padding: 20px 25px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile styles (480px and down) */
|
||||
@media screen and (max-width: 480px) {
|
||||
.login-page {
|
||||
padding: 15px 10px;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
max-height: 25vh;
|
||||
max-width: 85vw;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
padding: 20px 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.form-container h2 {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-container input {
|
||||
padding: 12px;
|
||||
font-size: 16px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-container button {
|
||||
padding: 12px;
|
||||
font-size: 16px;
|
||||
border-radius: 5px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-container label {
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Small mobile styles (320px and down) */
|
||||
@media screen and (max-width: 320px) {
|
||||
.login-page {
|
||||
padding: 10px 8px;
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
max-height: 20vh;
|
||||
max-width: 90vw;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
padding: 15px;
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
|
||||
.form-container h2 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Landscape orientation adjustments */
|
||||
@media screen and (max-height: 500px) and (orientation: landscape) {
|
||||
.login-page {
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
flex: 1;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
max-height: 80vh;
|
||||
max-width: 40vw;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
flex: 1;
|
||||
max-width: 350px;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch device optimizations */
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
.form-container input {
|
||||
min-height: 44px; /* Apple's recommended touch target size */
|
||||
}
|
||||
|
||||
.form-container button {
|
||||
min-height: 44px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-container button:active {
|
||||
background-color: #004494;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
}
|
||||
|
||||
/* High DPI displays */
|
||||
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
|
||||
.login-logo {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: crisp-edges;
|
||||
}
|
||||
}
|
||||
759
py_app/app/static/css/warehouse.css
Normal file
759
py_app/app/static/css/warehouse.css
Normal file
@@ -0,0 +1,759 @@
|
||||
|
||||
/* Ensure .main-content is full width for warehouse pages */
|
||||
/* Fix horizontal overflow: use 100% width, not 100vw */
|
||||
.main-content {
|
||||
width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: transparent !important;
|
||||
border-radius: 0 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
/* Normalize box-sizing for all elements */
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* WAREHOUSE PAGE CSS - FRESH START */
|
||||
|
||||
/* Reset and override all base styles for warehouse pages */
|
||||
.main-content {
|
||||
width: 100% !important;
|
||||
height: calc(100vh - 60px) !important; /* Full height minus header */
|
||||
margin: 0 !important;
|
||||
padding: 10px !important; /* 10px margin from page edges */
|
||||
background: #f4f4f9 !important; /* Match body background */
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
box-sizing: border-box !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
}
|
||||
|
||||
/* Main warehouse container - full width with 10px padding */
|
||||
.warehouse-page-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
gap: 10px; /* 10px between containers */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* The 3 main containers with 1:2:1 ratio */
|
||||
.warehouse-container-1 {
|
||||
flex: 1; /* 1 part */
|
||||
background: #f8fafc; /* Theme card background */
|
||||
color: #1e293b; /* Theme text color */
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
align-self: flex-start;
|
||||
max-height: 640px;
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
.warehouse-container-2 {
|
||||
flex: 2; /* 2 parts */
|
||||
background: #f8fafc; /* Theme card background */
|
||||
color: #1e293b; /* Theme text color */
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
max-height: 640px;
|
||||
}
|
||||
|
||||
.warehouse-container-3 {
|
||||
flex: 1; /* 1 part */
|
||||
background: #f8fafc; /* Theme card background */
|
||||
color: #1e293b; /* Theme text color */
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
max-height: 640px;
|
||||
}
|
||||
|
||||
/* Form and table styles for warehouse components */
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px; /* Reduced gap for compactness */
|
||||
}
|
||||
|
||||
form label {
|
||||
font-weight: bold;
|
||||
margin-bottom: 2px; /* Reduced margin for compactness */
|
||||
}
|
||||
|
||||
form input, form select {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
background: #e2e8f0; /* Theme input background */
|
||||
color: #1e293b; /* Theme input text */
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 8px 16px;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
background-color: #17a2b8;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
|
||||
/* Table styles */
|
||||
.scan-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.scan-table th, .scan-table td {
|
||||
border: 1px solid #cbd5e1; /* Theme border color */
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.scan-table th {
|
||||
background-color: #e2e8f0; /* Theme input background for headers */
|
||||
font-weight: bold;
|
||||
color: #334155; /* Theme label color */
|
||||
}
|
||||
|
||||
.location-row {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.location-row:hover {
|
||||
background-color: #e2e8f0; /* Theme hover background */
|
||||
}
|
||||
|
||||
.location-row.selected {
|
||||
background-color: #ffb300 !important;
|
||||
color: #222 !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Edit/Delete card styles */
|
||||
.edit-delete-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.selection-message {
|
||||
color: #64748b; /* Slightly lighter theme text */
|
||||
font-style: italic;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.selection-info {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Barcode preview */
|
||||
#barcode-label-preview {
|
||||
width: 8cm;
|
||||
height: 4cm;
|
||||
border: 2px solid #333;
|
||||
background: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px auto;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
#barcode-label-preview .location-text {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Modal styles */
|
||||
.modal {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.confirm-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.confirm-table td {
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.confirm-table td:first-child {
|
||||
width: 30%;
|
||||
background-color: #f8f9fa;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.modal-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.scan-container {
|
||||
width: 100vw !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
display: block !important; /* Override any grid from style.css */
|
||||
grid-template-columns: unset !important; /* Remove any grid columns */
|
||||
gap: unset !important; /* Remove any gap */
|
||||
max-width: 100vw !important; /* Override max-width from style.css */
|
||||
box-shadow: none !important; /* Remove box shadow */
|
||||
border-radius: 0 !important; /* Remove border radius */
|
||||
}
|
||||
|
||||
/* Full-width container for warehouse pages - avoids scan-container restrictions */
|
||||
.warehouse-full-container {
|
||||
width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
display: block !important;
|
||||
box-sizing: border-box;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
/* Container card with left/right margins */
|
||||
.warehouse-container-card {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
width: calc(100% - 30px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 3-column layout for warehouse create locations */
|
||||
.warehouse-grid {
|
||||
display: grid !important;
|
||||
grid-template-columns: 1fr 2fr 1fr !important;
|
||||
gap: 20px;
|
||||
margin: 0;
|
||||
min-height: auto;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Make cards equal height in grid with higher specificity */
|
||||
.warehouse-grid .card {
|
||||
height: fit-content;
|
||||
align-self: start;
|
||||
width: 100% !important;
|
||||
max-width: none !important;
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* Responsive grid - collapse to single column on smaller screens */
|
||||
@media (max-width: 1024px) {
|
||||
.warehouse-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.warehouse-grid {
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.scan-container {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.scan-form-card {
|
||||
max-width: 600px;
|
||||
margin: 0 auto 20px auto;
|
||||
}
|
||||
|
||||
.scan-table-card {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.scan-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.scan-table th, .scan-table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scan-table th {
|
||||
background-color: #f4f4f4;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Location row selection styles */
|
||||
.location-row {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.location-row:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
tr.location-row.selected, .location-row.selected td {
|
||||
background-color: #ffb300 !important;
|
||||
color: #222 !important;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 2px 8px rgba(255,179,0,0.12);
|
||||
border-left: 4px solid #ff9800;
|
||||
transition: background 0.2s, color 0.2s;
|
||||
}
|
||||
|
||||
/* Print section styles */
|
||||
.print-section {
|
||||
margin-top: 24px;
|
||||
padding: 16px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
/* Edit/Delete card styles - compact version */
|
||||
.edit-delete-card {
|
||||
margin-top: 16px;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.edit-delete-card h3 {
|
||||
font-size: 1.05em;
|
||||
margin: 0 0 8px 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.edit-delete-card .selection-message {
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
margin-bottom: 8px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.edit-delete-card .selection-info {
|
||||
margin-bottom: 8px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.edit-delete-card .button-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.edit-delete-card .btn {
|
||||
font-size: 11px;
|
||||
padding: 5px 12px;
|
||||
}
|
||||
|
||||
/* Barcode label preview */
|
||||
#barcode-label-preview {
|
||||
width: 8cm;
|
||||
height: 4cm;
|
||||
border: 2px solid #333;
|
||||
background: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px auto;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.07);
|
||||
}
|
||||
|
||||
#barcode-label-preview .location-text {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#barcode-label-preview #location-barcode {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 90%;
|
||||
max-height: 70%;
|
||||
}
|
||||
|
||||
#barcode-label-preview #barcode-placeholder {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Dark mode for warehouse */
|
||||
body.dark-mode .card {
|
||||
background: #2d2d2d;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode .scan-table {
|
||||
background-color: #1e1e1e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .scan-table th {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
body.dark-mode .scan-table td {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
body.dark-mode .scan-table tr:nth-child(even) {
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
body.dark-mode .print-section {
|
||||
background-color: #333;
|
||||
border-color: #555;
|
||||
}
|
||||
|
||||
body.dark-mode .edit-delete-card {
|
||||
background-color: #333;
|
||||
border-color: #555;
|
||||
}
|
||||
|
||||
body.dark-mode .edit-delete-card h3 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .edit-delete-card .selection-message {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* Modal Styles */
|
||||
.modal {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.modal-header h3 {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-group input {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.modal-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.confirm-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.confirm-table td {
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.confirm-table td:first-child {
|
||||
width: 30%;
|
||||
background-color: #f8f9fa;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #5a6268;
|
||||
}
|
||||
|
||||
/* Dark mode for modals */
|
||||
body.dark-mode .modal-content {
|
||||
background-color: #2d2d2d;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-header {
|
||||
background-color: #333;
|
||||
border-bottom-color: #555;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-header h3 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .close {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
body.dark-mode .close:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .form-group input {
|
||||
background-color: #333;
|
||||
border-color: #555;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode .confirm-table td:first-child {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-buttons {
|
||||
border-top-color: #555;
|
||||
}
|
||||
|
||||
/* ENHANCED DARK MODE SUPPORT FOR NEW WAREHOUSE LAYOUT */
|
||||
body.dark-mode .main-content {
|
||||
background: #121212 !important; /* Match body dark background */
|
||||
}
|
||||
|
||||
body.dark-mode .warehouse-container-1,
|
||||
body.dark-mode .warehouse-container-2,
|
||||
body.dark-mode .warehouse-container-3 {
|
||||
background: #1e1e1e !important; /* Match header dark background */
|
||||
color: #e0e0e0 !important; /* Match body dark text */
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
body.dark-mode form label {
|
||||
color: #e0e0e0 !important; /* Match body dark text */
|
||||
}
|
||||
|
||||
body.dark-mode form input,
|
||||
body.dark-mode form select {
|
||||
background: #2d2d2d !important; /* Slightly lighter than containers */
|
||||
color: #e0e0e0 !important; /* Match body dark text */
|
||||
border: 1px solid #444 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .btn {
|
||||
background-color: #4299e1 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .btn:hover {
|
||||
background-color: #3182ce !important;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-success {
|
||||
background-color: #48bb78 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-info {
|
||||
background-color: #38b2ac !important;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-danger {
|
||||
background-color: #f56565 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .scan-table {
|
||||
background-color: #1e1e1e !important; /* Match header background */
|
||||
color: #e0e0e0 !important; /* Match body dark text */
|
||||
}
|
||||
|
||||
body.dark-mode .scan-table th {
|
||||
background-color: #2d2d2d !important; /* Slightly lighter */
|
||||
color: #e0e0e0 !important; /* Match body dark text */
|
||||
border: 1px solid #444 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .scan-table td {
|
||||
color: #e0e0e0 !important; /* Match body dark text */
|
||||
border: 1px solid #444 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .location-row:hover {
|
||||
background-color: #2d2d2d !important; /* Slightly lighter than table */
|
||||
}
|
||||
|
||||
body.dark-mode .location-row.selected {
|
||||
background-color: #ed8936 !important;
|
||||
color: #1a202c !important;
|
||||
}
|
||||
|
||||
body.dark-mode .selection-message {
|
||||
color: #999 !important; /* Lighter gray for secondary text */
|
||||
}
|
||||
|
||||
body.dark-mode .selection-info {
|
||||
color: #e0e0e0 !important; /* Match body dark text */
|
||||
}
|
||||
|
||||
body.dark-mode #barcode-label-preview {
|
||||
background: #f8fafc !important; /* Keep white for readability */
|
||||
border: 2px solid #444 !important;
|
||||
}
|
||||
@@ -4,7 +4,12 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Flask App{% endblock %}</title>
|
||||
<!-- Base CSS for common styles -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}">
|
||||
<!-- Legacy CSS for backward compatibility (temporarily) -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
<!-- Page-specific CSS -->
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body class="light-mode">
|
||||
{% if request.endpoint != 'main.login' %}
|
||||
@@ -38,7 +43,7 @@
|
||||
</div>
|
||||
</header>
|
||||
{% endif %}
|
||||
<div class="container">
|
||||
<div class="main-content">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='script.js') }}"></script>
|
||||
|
||||
@@ -2,72 +2,13 @@
|
||||
{% block title %}Create Warehouse Locations{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<style>
|
||||
/* Barcode label preview */
|
||||
#barcode-label-preview {
|
||||
width: 8cm;
|
||||
height: 4cm;
|
||||
border: 2px solid #333;
|
||||
background: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px auto;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.07);
|
||||
}
|
||||
|
||||
#barcode-label-preview .location-text {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#barcode-label-preview #location-barcode {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 90%;
|
||||
max-height: 70%;
|
||||
}
|
||||
|
||||
#barcode-label-preview #barcode-placeholder {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.print-section {
|
||||
margin-top: 24px;
|
||||
padding: 16px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.location-row.selected {
|
||||
background-color: #ffb300 !important; /* Accent color: Amber */
|
||||
color: #222 !important;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 2px 8px rgba(255,179,0,0.12);
|
||||
border-left: 4px solid #ff9800;
|
||||
transition: background 0.2s, color 0.2s;
|
||||
}
|
||||
|
||||
.location-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.location-row:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/warehouse.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="scan-container">
|
||||
<!-- Add Warehouse Location Card -->
|
||||
<div class="card scan-form-card">
|
||||
<div class="warehouse-page-container">
|
||||
<!-- Container 1: Add Location (1 part width) -->
|
||||
<div class="warehouse-container-1">
|
||||
<h3>Add Warehouse Location</h3>
|
||||
{% if message %}
|
||||
<div class="form-message">{{ message }}</div>
|
||||
@@ -81,7 +22,7 @@
|
||||
<input type="text" name="description" maxlength="250"><br>
|
||||
<button type="submit" class="btn">Add Location</button>
|
||||
</form>
|
||||
<!-- Import from CSV content moved here -->
|
||||
<!-- Import from CSV section -->
|
||||
<div style="margin-top: 24px;">
|
||||
<h3 style="font-size: 1.1em;">Import Locations from CSV</h3>
|
||||
<div style="display: flex; flex-direction: row; gap: 16px; align-items: center;">
|
||||
@@ -89,11 +30,75 @@
|
||||
<a href="{{ url_for('warehouse.import_locations_csv') }}" class="btn" style="padding: 4px 12px; font-size: 0.95em;">Go to Import Page</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Print Barcode Section -->
|
||||
<div class="print-section">
|
||||
</div>
|
||||
|
||||
<!-- Container 2: Warehouse Locations Table (2 parts width) -->
|
||||
<div class="warehouse-container-2">
|
||||
<h3>Warehouse Locations</h3>
|
||||
<div id="location-selection-hint" style="margin-bottom: 10px; font-size: 11px; color: #666; text-align: center;">
|
||||
Click on a row to select a location for printing
|
||||
</div>
|
||||
<table class="scan-table" id="locations-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Location Code</th>
|
||||
<th>Size</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for loc in locations %}
|
||||
<tr class="location-row" data-location-code="{{ loc[1] }}"
|
||||
data-location-id="{{ loc[0] }}"
|
||||
data-location-size="{{ loc[2] or '' }}"
|
||||
data-location-description="{{ loc[3] or '' }}">
|
||||
<td>{{ loc[0] }}</td>
|
||||
<td>{{ loc[1] }}</td>
|
||||
<td>{{ loc[2] or '' }}</td>
|
||||
<td>{{ loc[3] or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Container 3: Edit/Delete and Print (1 part width) -->
|
||||
<div class="warehouse-container-3">
|
||||
<div class="edit-delete-card">
|
||||
<h3>Edit/Delete Selected Location</h3>
|
||||
<div id="no-selection-message" class="selection-message">
|
||||
Select a location from the table to edit or delete it.
|
||||
</div>
|
||||
<div id="selected-location-info" class="selection-info" style="display: none;">
|
||||
<strong>Selected:</strong> <span id="selected-location-display"></span>
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<button id="edit-location-btn" class="btn btn-info" disabled>
|
||||
✏️ Edit Selected Location
|
||||
</button>
|
||||
<button id="delete-location-btn" class="btn btn-danger" disabled>
|
||||
🗑️ Delete Selected Location
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% if session['role'] in ['administrator', 'management'] %}
|
||||
<div style="margin-top: 32px; padding: 12px; border-top: 1px solid #eee;">
|
||||
<label style="font-weight:bold;">Delete location from table</label>
|
||||
<div style="font-size:0.95em; margin-bottom:8px;">To delete a location, enter the ID of the location and press delete.<br>To delete 2 or multiple locations, enter the IDs separated by "," and then press delete.</div>
|
||||
<form method="POST" style="display:flex; gap:8px; align-items:center;" onsubmit="return confirmDeleteLocations();">
|
||||
<input type="text" name="delete_ids" placeholder="e.g. 5,7,12" style="width:160px;">
|
||||
<button type="submit" name="delete_locations" value="1" class="btn" style="padding:4px 16px;">Delete Locations</button>
|
||||
</form>
|
||||
<script>
|
||||
function confirmDeleteLocations() {
|
||||
return confirm('Do you really want to delete the selected locations?');
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
{% endif %}
|
||||
<hr style="margin: 32px 0 24px 0;">
|
||||
<h3 style="font-size: 1.1em; margin-bottom: 12px;">Print Location Barcode</h3>
|
||||
|
||||
<!-- Label Preview -->
|
||||
<div id="barcode-label-preview" style="display: flex; align-items: center; justify-content: center;">
|
||||
<div style="width: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;">
|
||||
@@ -104,7 +109,6 @@
|
||||
<div id="barcode-placeholder" style="color: #999; font-style: italic; text-align: center;">No location selected</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Print Controls -->
|
||||
<div style="text-align: center; margin-top: 15px;">
|
||||
<div style="margin-bottom: 10px;">
|
||||
@@ -121,51 +125,29 @@
|
||||
</button>
|
||||
<div id="print-status" style="margin-top: 8px; font-size: 11px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Location Area -->
|
||||
{% if session['role'] in ['administrator', 'management'] %}
|
||||
<div style="margin-top: 32px; padding: 12px; border-top: 1px solid #eee;">
|
||||
<label style="font-weight:bold;">Delete location from table</label>
|
||||
<div style="font-size:0.95em; margin-bottom:8px;">To delete a location, enter the ID of the location and press delete.<br>To delete 2 or multiple locations, enter the IDs separated by "," and then press delete.</div>
|
||||
<form method="POST" style="display:flex; gap:8px; align-items:center;" onsubmit="return confirmDeleteLocations();">
|
||||
<input type="text" name="delete_ids" placeholder="e.g. 5,7,12" style="width:160px;">
|
||||
<button type="submit" name="delete_locations" value="1" class="btn" style="padding:4px 16px;">Delete Locations</button>
|
||||
</form>
|
||||
<script>
|
||||
function confirmDeleteLocations() {
|
||||
return confirm('Do you really want to delete the selected locations?');
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<!-- Locations Table Card -->
|
||||
<div class="card scan-table-card">
|
||||
<h3>Warehouse Locations</h3>
|
||||
<div id="location-selection-hint" style="margin-bottom: 10px; font-size: 11px; color: #666; text-align: center;">
|
||||
Click on a row to select a location for printing
|
||||
</div>
|
||||
|
||||
<!-- Delete Confirmation Modal -->
|
||||
<div id="delete-modal" class="modal" style="display: none;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Confirm Delete</h3>
|
||||
<span class="close" onclick="closeDeleteModal()">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are you sure you want to delete the following location?</p>
|
||||
<table class="confirm-table">
|
||||
<tr><td><strong>ID:</strong></td><td id="delete-confirm-id"></td></tr>
|
||||
<tr><td><strong>Location Code:</strong></td><td id="delete-confirm-code"></td></tr>
|
||||
<tr><td><strong>Size:</strong></td><td id="delete-confirm-size"></td></tr>
|
||||
<tr><td><strong>Description:</strong></td><td id="delete-confirm-description"></td></tr>
|
||||
</table>
|
||||
<div class="modal-buttons">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeDeleteModal()">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" onclick="confirmDelete()">Delete Location</button>
|
||||
</div>
|
||||
</div>
|
||||
<table class="scan-table" id="locations-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Location Code</th>
|
||||
<th>Size</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for loc in locations %}
|
||||
<tr class="location-row" data-location-code="{{ loc[1] }}">
|
||||
<td>{{ loc[0] }}</td>
|
||||
<td>{{ loc[1] }}</td>
|
||||
<td>{{ loc[2] }}</td>
|
||||
<td>{{ loc[3] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -369,6 +351,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const locationRows = document.querySelectorAll('.location-row');
|
||||
const locationCodeDisplay = document.getElementById('location-code-display');
|
||||
const printButton = document.getElementById('print-barcode-btn');
|
||||
const editButton = document.getElementById('edit-location-btn');
|
||||
const deleteButton = document.getElementById('delete-location-btn');
|
||||
const noSelectionMessage = document.getElementById('no-selection-message');
|
||||
const selectedLocationInfo = document.getElementById('selected-location-info');
|
||||
const selectedLocationDisplay = document.getElementById('selected-location-display');
|
||||
|
||||
let selectedLocation = null;
|
||||
|
||||
locationRows.forEach(row => {
|
||||
row.addEventListener('click', function() {
|
||||
@@ -378,22 +367,49 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
// Select this row
|
||||
this.classList.add('selected');
|
||||
|
||||
// Get location code
|
||||
// Get location data
|
||||
selectedLocationCode = this.dataset.locationCode;
|
||||
selectedLocation = {
|
||||
id: this.cells[0].textContent,
|
||||
code: this.cells[1].textContent,
|
||||
size: this.cells[2].textContent,
|
||||
description: this.cells[3].textContent
|
||||
};
|
||||
|
||||
// Update display
|
||||
locationCodeDisplay.textContent = selectedLocationCode;
|
||||
selectedLocationDisplay.textContent = `${selectedLocation.code} (ID: ${selectedLocation.id})`;
|
||||
|
||||
// Show/hide selection info
|
||||
noSelectionMessage.style.display = 'none';
|
||||
selectedLocationInfo.style.display = 'block';
|
||||
|
||||
// Generate barcode
|
||||
generateLocationBarcode(selectedLocationCode);
|
||||
|
||||
// Enable print button
|
||||
// Enable buttons
|
||||
printButton.disabled = false;
|
||||
editButton.disabled = false;
|
||||
deleteButton.disabled = false;
|
||||
|
||||
showNotification(`📍 Selected location: ${selectedLocationCode}`, 'info');
|
||||
});
|
||||
});
|
||||
|
||||
// Edit button functionality
|
||||
editButton.addEventListener('click', function() {
|
||||
if (selectedLocation) {
|
||||
openEditModal(selectedLocation);
|
||||
}
|
||||
});
|
||||
|
||||
// Delete button functionality
|
||||
deleteButton.addEventListener('click', function() {
|
||||
if (selectedLocation) {
|
||||
openDeleteModal(selectedLocation);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize QZ Tray
|
||||
initializeQZTray();
|
||||
});
|
||||
@@ -519,5 +535,111 @@ async function testQZConnection() {
|
||||
|
||||
// Add test button functionality (for debugging - can be removed in production)
|
||||
console.log('🔧 QZ Tray test function available: testQZConnection()');
|
||||
|
||||
// Modal Functions for Edit/Delete
|
||||
function openEditModal(location) {
|
||||
document.getElementById('edit-location-id').value = location.id;
|
||||
document.getElementById('edit-location-code').value = location.code;
|
||||
document.getElementById('edit-size').value = location.size || '';
|
||||
document.getElementById('edit-description').value = location.description || '';
|
||||
document.getElementById('edit-modal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function closeEditModal() {
|
||||
document.getElementById('edit-modal').style.display = 'none';
|
||||
}
|
||||
|
||||
function openDeleteModal(location) {
|
||||
document.getElementById('delete-confirm-id').textContent = location.id;
|
||||
document.getElementById('delete-confirm-code').textContent = location.code;
|
||||
document.getElementById('delete-confirm-size').textContent = location.size || '-';
|
||||
document.getElementById('delete-confirm-description').textContent = location.description || '-';
|
||||
document.getElementById('delete-modal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function closeDeleteModal() {
|
||||
document.getElementById('delete-modal').style.display = 'none';
|
||||
}
|
||||
|
||||
// Handle edit form submission
|
||||
document.getElementById('edit-form').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(this);
|
||||
const data = {
|
||||
location_id: formData.get('location_id'),
|
||||
location_code: formData.get('location_code'),
|
||||
size: formData.get('size'),
|
||||
description: formData.get('description')
|
||||
};
|
||||
|
||||
// Send update request
|
||||
fetch('/update_location', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
showNotification('✅ Location updated successfully!', 'success');
|
||||
closeEditModal();
|
||||
// Reload page to show changes
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
showNotification('❌ Error updating location: ' + result.error, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('❌ Error updating location: ' + error.message, 'error');
|
||||
});
|
||||
});
|
||||
|
||||
// Handle delete confirmation
|
||||
function confirmDelete() {
|
||||
const locationId = document.getElementById('delete-confirm-id').textContent;
|
||||
|
||||
// Send delete request
|
||||
fetch('/delete_location', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ location_id: locationId })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
showNotification('✅ Location deleted successfully!', 'success');
|
||||
closeDeleteModal();
|
||||
// Reload page to show changes
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
showNotification('❌ Error deleting location: ' + result.error, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('❌ Error deleting location: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Close modals when clicking outside
|
||||
window.addEventListener('click', function(event) {
|
||||
const editModal = document.getElementById('edit-modal');
|
||||
const deleteModal = document.getElementById('delete-modal');
|
||||
|
||||
if (event.target === editModal) {
|
||||
closeEditModal();
|
||||
}
|
||||
if (event.target === deleteModal) {
|
||||
closeDeleteModal();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/login.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="login-page">
|
||||
<div class="logo-container">
|
||||
|
||||
@@ -218,3 +218,59 @@ def generate_location_label_pdf():
|
||||
except Exception as e:
|
||||
print(f"Error generating location label PDF: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
def update_location(location_id, location_code, size, description):
|
||||
"""Update an existing warehouse location"""
|
||||
try:
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Check if location exists
|
||||
cursor.execute("SELECT id FROM warehouse_locations WHERE id = ?", (location_id,))
|
||||
if not cursor.fetchone():
|
||||
conn.close()
|
||||
return {"success": False, "error": "Location not found"}
|
||||
|
||||
# Check if location code already exists for different location
|
||||
cursor.execute("SELECT id FROM warehouse_locations WHERE location_code = ? AND id != ?", (location_code, location_id))
|
||||
if cursor.fetchone():
|
||||
conn.close()
|
||||
return {"success": False, "error": "Location code already exists"}
|
||||
|
||||
# Update location
|
||||
cursor.execute(
|
||||
"UPDATE warehouse_locations SET location_code = ?, size = ?, description = ? WHERE id = ?",
|
||||
(location_code, size if size else None, description, location_id)
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return {"success": True, "message": "Location updated successfully"}
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error updating location: {e}")
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
def delete_location_by_id(location_id):
|
||||
"""Delete a warehouse location by ID"""
|
||||
try:
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Check if location exists
|
||||
cursor.execute("SELECT location_code FROM warehouse_locations WHERE id = ?", (location_id,))
|
||||
location = cursor.fetchone()
|
||||
if not location:
|
||||
conn.close()
|
||||
return {"success": False, "error": "Location not found"}
|
||||
|
||||
# Delete location
|
||||
cursor.execute("DELETE FROM warehouse_locations WHERE id = ?", (location_id,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return {"success": True, "message": f"Location '{location[0]}' deleted successfully"}
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error deleting location: {e}")
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
server_domain=localhost
|
||||
port=3602
|
||||
database_name=recticel
|
||||
username=sa
|
||||
password=12345678
|
||||
database_name=trasabilitate_database
|
||||
username=trasabilitate
|
||||
password=Initial01!
|
||||
|
||||
Reference in New Issue
Block a user