fix: resolve settings page icon and 404 errors
- Change icon from 'envelope' to 'mail' (envelope not in icons.js)
- Add default query param to GET /admin/settings/{key} endpoint
- Return AdminSettingDefaultResponse instead of 404 when default provided
- Update loadShippingSettings() to use default param for carrier settings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ from app.services.admin_settings_service import admin_settings_service
|
|||||||
from models.database.user import User
|
from models.database.user import User
|
||||||
from models.schema.admin import (
|
from models.schema.admin import (
|
||||||
AdminSettingCreate,
|
AdminSettingCreate,
|
||||||
|
AdminSettingDefaultResponse,
|
||||||
AdminSettingListResponse,
|
AdminSettingListResponse,
|
||||||
AdminSettingResponse,
|
AdminSettingResponse,
|
||||||
AdminSettingUpdate,
|
AdminSettingUpdate,
|
||||||
@@ -75,16 +76,24 @@ def get_setting_categories(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{key}", response_model=AdminSettingResponse)
|
@router.get("/{key}", response_model=AdminSettingResponse | AdminSettingDefaultResponse)
|
||||||
def get_setting(
|
def get_setting(
|
||||||
key: str,
|
key: str,
|
||||||
|
default: str | None = Query(None, description="Default value if setting not found"),
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
current_admin: User = Depends(get_current_admin_api),
|
current_admin: User = Depends(get_current_admin_api),
|
||||||
):
|
) -> AdminSettingResponse | AdminSettingDefaultResponse:
|
||||||
"""Get specific setting by key."""
|
"""Get specific setting by key.
|
||||||
|
|
||||||
|
If `default` is provided and the setting doesn't exist, returns a response
|
||||||
|
with the default value instead of 404.
|
||||||
|
"""
|
||||||
setting = admin_settings_service.get_setting_by_key(db, key)
|
setting = admin_settings_service.get_setting_by_key(db, key)
|
||||||
|
|
||||||
if not setting:
|
if not setting:
|
||||||
|
if default is not None:
|
||||||
|
# Return default value without creating the setting
|
||||||
|
return AdminSettingDefaultResponse(key=key, value=default, exists=False)
|
||||||
raise ResourceNotFoundException(resource_type="Setting", identifier=key)
|
raise ResourceNotFoundException(resource_type="Setting", identifier=key)
|
||||||
|
|
||||||
return AdminSettingResponse.model_validate(setting)
|
return AdminSettingResponse.model_validate(setting)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
{% call tabs_nav() %}
|
{% call tabs_nav() %}
|
||||||
{{ tab_button('display', 'Display', icon='view-grid') }}
|
{{ tab_button('display', 'Display', icon='view-grid') }}
|
||||||
{{ tab_button('logging', 'Logging', icon='document-text') }}
|
{{ tab_button('logging', 'Logging', icon='document-text') }}
|
||||||
{{ tab_button('email', 'Email', icon='envelope') }}
|
{{ tab_button('email', 'Email', icon='mail') }}
|
||||||
{{ tab_button('shipping', 'Shipping', icon='truck') }}
|
{{ tab_button('shipping', 'Shipping', icon='truck') }}
|
||||||
{{ tab_button('system', 'System', icon='cog') }}
|
{{ tab_button('system', 'System', icon='cog') }}
|
||||||
{{ tab_button('security', 'Security', icon='shield-check') }}
|
{{ tab_button('security', 'Security', icon='shield-check') }}
|
||||||
|
|||||||
@@ -172,6 +172,14 @@ class AdminSettingResponse(BaseModel):
|
|||||||
model_config = {"from_attributes": True}
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class AdminSettingDefaultResponse(BaseModel):
|
||||||
|
"""Response when returning a default value for non-existent setting."""
|
||||||
|
|
||||||
|
key: str
|
||||||
|
value: str
|
||||||
|
exists: bool = False
|
||||||
|
|
||||||
|
|
||||||
class AdminSettingUpdate(BaseModel):
|
class AdminSettingUpdate(BaseModel):
|
||||||
"""Update admin setting value."""
|
"""Update admin setting value."""
|
||||||
|
|
||||||
|
|||||||
@@ -242,24 +242,24 @@ function adminSettings() {
|
|||||||
|
|
||||||
async loadShippingSettings() {
|
async loadShippingSettings() {
|
||||||
try {
|
try {
|
||||||
// Load each carrier setting
|
// Load each carrier setting with defaults to avoid 404 errors
|
||||||
const carriers = ['greco', 'colissimo', 'xpresslogistics'];
|
const carriers = [
|
||||||
|
{ name: 'greco', default: 'https://dispatchweb.fr/Tracky/Home/' },
|
||||||
|
{ name: 'colissimo', default: '' },
|
||||||
|
{ name: 'xpresslogistics', default: '' }
|
||||||
|
];
|
||||||
for (const carrier of carriers) {
|
for (const carrier of carriers) {
|
||||||
try {
|
const key = `carrier_${carrier.name}_label_url`;
|
||||||
const key = `carrier_${carrier}_label_url`;
|
// Use default query param to avoid 404 for non-existent settings
|
||||||
const data = await apiClient.get(`/admin/settings/${key}`);
|
const data = await apiClient.get(`/admin/settings/${key}?default=${encodeURIComponent(carrier.default)}`);
|
||||||
if (data && data.value) {
|
if (data && data.value !== undefined) {
|
||||||
this.shippingSettings[key] = data.value;
|
this.shippingSettings[key] = data.value;
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// Setting doesn't exist yet, use default
|
|
||||||
settingsLog.debug(`Setting carrier_${carrier}_label_url not found, using default`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
settingsLog.info('Shipping settings loaded:', this.shippingSettings);
|
settingsLog.info('Shipping settings loaded:', this.shippingSettings);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
settingsLog.error('Failed to load shipping settings:', error);
|
settingsLog.error('Failed to load shipping settings:', error);
|
||||||
// Don't show error for missing settings, just use defaults
|
// On error, keep existing defaults
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user