Add name field for places; show place ID in API key section
This commit is contained in:
parent
689f2b5a6e
commit
8287b7ed6d
1
migrations/0005_place_name.sql
Normal file
1
migrations/0005_place_name.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE places ADD COLUMN name TEXT;
|
||||
|
|
@ -19,6 +19,8 @@
|
|||
<div class="card" style="margin-top: 16px;">
|
||||
<h3 style="margin-top:0;font-size:14px;">Add place</h3>
|
||||
<form id="add-place-form">
|
||||
<label for="place-name">Name <span style="color:var(--muted);font-weight:normal;">(optional)</span></label>
|
||||
<input type="text" id="place-name">
|
||||
<div id="add-place-custom-fields" class="hidden">
|
||||
<label for="place-id">Place ID <span style="color:var(--muted);font-weight:normal;">(leave blank to auto-generate)</span></label>
|
||||
<input type="text" id="place-id">
|
||||
|
|
@ -41,9 +43,24 @@
|
|||
<button class="danger" id="delete-place-btn">Delete place</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Name</h3>
|
||||
<form id="set-place-name-form" class="inline-form">
|
||||
<div class="field-group">
|
||||
<label for="place-name-custom">Place name <span style="color:var(--muted);font-weight:normal;">(leave blank to show the place ID instead)</span></label>
|
||||
<input type="text" id="place-name-custom">
|
||||
</div>
|
||||
<button type="submit" class="primary">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>API Key</h3>
|
||||
<div class="inline-form">
|
||||
<div class="field-group">
|
||||
<label for="place-id-display">Place ID</label>
|
||||
<input type="text" id="place-id-display" readonly>
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<label for="place-api-key-display">Current key</label>
|
||||
<input type="password" id="place-api-key-display" readonly>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ function renderPlaceList() {
|
|||
|
||||
const idSpan = document.createElement('span');
|
||||
idSpan.className = 'place-list-id';
|
||||
idSpan.textContent = place.id;
|
||||
idSpan.textContent = place.name || place.id;
|
||||
li.appendChild(idSpan);
|
||||
|
||||
if (place.ownerUsername) {
|
||||
|
|
@ -82,7 +82,10 @@ async function selectPlace(placeId) {
|
|||
|
||||
document.getElementById('no-place').classList.add('hidden');
|
||||
document.getElementById('place-view').classList.remove('hidden');
|
||||
document.getElementById('place-title').textContent = placeId;
|
||||
document.getElementById('place-title').textContent = data.place.name || placeId;
|
||||
|
||||
document.getElementById('place-id-display').value = placeId;
|
||||
document.getElementById('place-name-custom').value = data.place.name || '';
|
||||
|
||||
const apiKeyInput = document.getElementById('place-api-key-display');
|
||||
apiKeyInput.value = data.place.apiKey || '';
|
||||
|
|
@ -177,10 +180,12 @@ document.getElementById('add-place-form').addEventListener('submit', async (e) =
|
|||
e.preventDefault();
|
||||
const id = document.getElementById('place-id').value.trim();
|
||||
const apiKey = document.getElementById('place-api-key').value.trim();
|
||||
const name = document.getElementById('place-name').value.trim();
|
||||
|
||||
const body = {};
|
||||
if (id) body.id = id;
|
||||
if (apiKey) body.apiKey = apiKey;
|
||||
if (name) body.name = name;
|
||||
|
||||
const data = await api('/dashboard/places', {
|
||||
method: 'POST',
|
||||
|
|
@ -190,6 +195,7 @@ document.getElementById('add-place-form').addEventListener('submit', async (e) =
|
|||
if (data.success) {
|
||||
document.getElementById('place-id').value = '';
|
||||
document.getElementById('place-api-key').value = '';
|
||||
document.getElementById('place-name').value = '';
|
||||
await loadPlaces();
|
||||
selectPlace(data.place.id);
|
||||
} else {
|
||||
|
|
@ -265,6 +271,24 @@ document.getElementById('regenerate-api-key-btn').addEventListener('click', asyn
|
|||
}
|
||||
});
|
||||
|
||||
document.getElementById('set-place-name-form').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
if (!currentPlaceId) return;
|
||||
|
||||
const name = document.getElementById('place-name-custom').value.trim();
|
||||
const data = await api(`/dashboard/places/${encodeURIComponent(currentPlaceId)}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ name })
|
||||
});
|
||||
|
||||
if (data.success) {
|
||||
await loadPlaces();
|
||||
selectPlace(currentPlaceId);
|
||||
} else {
|
||||
alert(data.message || 'Failed to set place name');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('set-api-key-form').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
if (!currentPlaceId) return;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ router.get('/places', (req, res) => {
|
|||
router.post('/places', (req, res) => {
|
||||
const canSetCustomValues = req.user.role >= ROLES.ADMIN;
|
||||
const { settings } = req.body || {};
|
||||
let { id, apiKey } = req.body || {};
|
||||
let { id, apiKey, name } = req.body || {};
|
||||
|
||||
if (!canSetCustomValues && (id || apiKey)) {
|
||||
return res.status(403).json({ success: false, message: "Only admins can set a custom place id or API key" });
|
||||
|
|
@ -106,6 +106,7 @@ router.post('/places', (req, res) => {
|
|||
// If we reach here, either the caller is an admin, or both id and apiKey were already falsy.
|
||||
id = id ? String(id).trim() : '';
|
||||
apiKey = apiKey ? String(apiKey).trim() : '';
|
||||
name = name ? String(name).trim() : '';
|
||||
|
||||
if (!id) id = generatePlaceId();
|
||||
if (!apiKey) apiKey = generateApiKey();
|
||||
|
|
@ -119,12 +120,12 @@ router.post('/places', (req, res) => {
|
|||
return res.status(409).json({ success: false, message: "A place with that id already exists" });
|
||||
}
|
||||
|
||||
db.run(`INSERT INTO places (id, apiKey, settings, ownerId) VALUES (?, ?, ?, ?)`, [id, apiKey, settings || '{}', req.user.id], (err) => {
|
||||
db.run(`INSERT INTO places (id, apiKey, settings, ownerId, name) VALUES (?, ?, ?, ?, ?)`, [id, apiKey, settings || '{}', req.user.id, name || null], (err) => {
|
||||
if (err) {
|
||||
console.error('Failed to create place:', err.message);
|
||||
return res.status(500).json({ success: false, message: "Internal server error" });
|
||||
}
|
||||
res.json({ success: true, place: { id, apiKey, settings: settings || '{}', ownerId: req.user.id } });
|
||||
res.json({ success: true, place: { id, apiKey, settings: settings || '{}', ownerId: req.user.id, name: name || null } });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -155,8 +156,9 @@ router.put('/places/:placeId', loadPlace, (req, res) => {
|
|||
apiKey = String(req.body.apiKey).trim() || generateApiKey();
|
||||
}
|
||||
const settings = req.body.settings !== undefined ? req.body.settings : req.place.settings;
|
||||
const name = req.body.name !== undefined ? (String(req.body.name).trim() || null) : req.place.name;
|
||||
|
||||
db.run(`UPDATE places SET apiKey = ?, settings = ? WHERE id = ?`, [apiKey, settings, req.place.id], (err) => {
|
||||
db.run(`UPDATE places SET apiKey = ?, settings = ?, name = ? WHERE id = ?`, [apiKey, settings, name, req.place.id], (err) => {
|
||||
if (err) {
|
||||
console.error('Failed to update place:', err.message);
|
||||
return res.status(500).json({ success: false, message: "Internal server error" });
|
||||
|
|
|
|||
Loading…
Reference in a new issue