a ver
This commit is contained in:
@@ -55,10 +55,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
|
<<<<<<< HEAD
|
||||||
<div v-if="loading.users" class="muted">Cargando usuarios…</div>
|
<div v-if="loading.users" class="muted">Cargando usuarios…</div>
|
||||||
<div v-else class="grid">
|
<div v-else class="grid">
|
||||||
<UserCard v-for="u in filteredUsers" :key="u.username" :item="u" :mode="layoutMode"
|
<UserCard v-for="u in filteredUsers" :key="u.username" :item="u" :mode="layoutMode"
|
||||||
@toggleDisable="toggleDisable" @remove="removeUser" @edit="openEditUser" />
|
@toggleDisable="toggleDisable" @remove="removeUser" @edit="openEditUser" />
|
||||||
|
=======
|
||||||
|
<form @submit.prevent="createUser" class="row" style="margin-bottom:10px;">
|
||||||
|
<input v-model="form.username" placeholder="usuario" required class="toggle"/>
|
||||||
|
<input v-model="form.password" placeholder="contraseña" required class="toggle"/>
|
||||||
|
<input v-model="form.vlan" placeholder="VLAN" class="toggle"/>
|
||||||
|
<label class="row toggle" style="gap:6px;"><input type="checkbox" v-model="form.disabled"/> deshabilitado</label>
|
||||||
|
<button type="submit" class="icon-btn">Crear / Actualizar</button>
|
||||||
|
</form>
|
||||||
|
<div v-if="loading.users" class="muted">Cargando usuarios…</div>
|
||||||
|
<div v-else class="grid">
|
||||||
|
<UserCard v-for="u in filteredUsers" :key="u.username" :item="u" :mode="layoutMode"
|
||||||
|
@toggleDisable="toggleDisable" @remove="removeUser" />
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@@ -89,11 +103,14 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
<Modal :open="showUserForm" :title="userFormMode==='edit' ? 'Editar usuario' : (userFormMode==='guest' ? 'Agregar invitado' : 'Agregar usuario')"
|
<Modal :open="showUserForm" :title="userFormMode==='edit' ? 'Editar usuario' : (userFormMode==='guest' ? 'Agregar invitado' : 'Agregar usuario')"
|
||||||
@close="showUserForm=false">
|
@close="showUserForm=false">
|
||||||
<UserForm :model-value="userFormModel" :mode="userFormMode" @submit="handleUserFormSubmit" @cancel="showUserForm=false" />
|
<UserForm :model-value="userFormModel" :mode="userFormMode" @submit="handleUserFormSubmit" @cancel="showUserForm=false" />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
=======
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -101,12 +118,19 @@ import { onMounted, reactive, ref, computed } from 'vue';
|
|||||||
import EventCard from './components/EventCard.js';
|
import EventCard from './components/EventCard.js';
|
||||||
import UserCard from './components/UserCard.js';
|
import UserCard from './components/UserCard.js';
|
||||||
import Modal from './components/Modal.vue';
|
import Modal from './components/Modal.vue';
|
||||||
|
<<<<<<< HEAD
|
||||||
import UserForm from './components/UserForm.vue';
|
import UserForm from './components/UserForm.vue';
|
||||||
|
=======
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
|
|
||||||
const users = ref([]);
|
const users = ref([]);
|
||||||
const requests = ref([]);
|
const requests = ref([]);
|
||||||
const loading = reactive({ users: false, requests: false });
|
const loading = reactive({ users: false, requests: false });
|
||||||
|
<<<<<<< HEAD
|
||||||
// formulario inline removido: se usa modal con UserForm
|
// formulario inline removido: se usa modal con UserForm
|
||||||
|
=======
|
||||||
|
const form = reactive({ username: '', password: '', vlan: '', disabled: false });
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
|
|
||||||
const showEventFilters = ref(false);
|
const showEventFilters = ref(false);
|
||||||
const showUserFilters = ref(false);
|
const showUserFilters = ref(false);
|
||||||
@@ -136,6 +160,20 @@ async function fetchRequests() {
|
|||||||
} finally { loading.requests = false; }
|
} finally { loading.requests = false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
async function createUser() {
|
||||||
|
const payload = { ...form };
|
||||||
|
if (!payload.vlan) delete payload.vlan;
|
||||||
|
await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
|
||||||
|
form.username = '';
|
||||||
|
form.password = '';
|
||||||
|
form.vlan = '';
|
||||||
|
form.disabled = false;
|
||||||
|
await fetchUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
async function toggleDisable(u) {
|
async function toggleDisable(u) {
|
||||||
await fetch(`/api/users/${encodeURIComponent(u.username)}`, {
|
await fetch(`/api/users/${encodeURIComponent(u.username)}`, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
@@ -215,6 +253,7 @@ function applyTheme() {
|
|||||||
document.documentElement.classList.toggle('light', theme.value === 'light');
|
document.documentElement.classList.toggle('light', theme.value === 'light');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
const showUserForm = ref(false);
|
const showUserForm = ref(false);
|
||||||
const userFormMode = ref('create'); // 'create' | 'edit' | 'guest'
|
const userFormMode = ref('create'); // 'create' | 'edit' | 'guest'
|
||||||
const userFormModel = ref({ username:'', password:'', vlan:'', disabled:false });
|
const userFormModel = ref({ username:'', password:'', vlan:'', disabled:false });
|
||||||
@@ -247,4 +286,9 @@ async function handleUserFormSubmit(data) {
|
|||||||
await fetchUsers();
|
await fetchUsers();
|
||||||
showUserForm.value = false;
|
showUserForm.value = false;
|
||||||
}
|
}
|
||||||
|
=======
|
||||||
|
function openAddUser() { /* placeholder for advanced modal */ }
|
||||||
|
function openAddGuest() { /* placeholder for advanced modal */ }
|
||||||
|
function openSettings() { /* placeholder for advanced modal */ }
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -5,18 +5,28 @@ const html = htm.bind(h);
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'UserCard',
|
name: 'UserCard',
|
||||||
props: { item: { type: Object, required: true }, mode: { type: String, default: 'user' } },
|
props: { item: { type: Object, required: true }, mode: { type: String, default: 'user' } },
|
||||||
|
<<<<<<< HEAD
|
||||||
emits: ['toggleDisable', 'remove', 'edit'],
|
emits: ['toggleDisable', 'remove', 'edit'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
function toggle() { emit('toggleDisable', props.item); }
|
function toggle() { emit('toggleDisable', props.item); }
|
||||||
function remove() { emit('remove', props.item); }
|
function remove() { emit('remove', props.item); }
|
||||||
function edit() { emit('edit', props.item); }
|
function edit() { emit('edit', props.item); }
|
||||||
|
=======
|
||||||
|
emits: ['toggleDisable', 'remove'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
function toggle() { emit('toggleDisable', props.item); }
|
||||||
|
function remove() { emit('remove', props.item); }
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
return () => html`<div class="card">
|
return () => html`<div class="card">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<b>${props.mode === 'user' ? props.item.username : (props.item.device || props.item.username)}</b>
|
<b>${props.mode === 'user' ? props.item.username : (props.item.device || props.item.username)}</b>
|
||||||
<span class="chip">VLAN ${props.item.vlan}</span>
|
<span class="chip">VLAN ${props.item.vlan}</span>
|
||||||
${props.item.disabled ? html`<span class="chip" style="color:#b33">deshabilitado</span>` : html`<span class="chip">activo</span>`}
|
${props.item.disabled ? html`<span class="chip" style="color:#b33">deshabilitado</span>` : html`<span class="chip">activo</span>`}
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
|
<<<<<<< HEAD
|
||||||
<button class="icon-btn" onClick=${edit}>Editar</button>
|
<button class="icon-btn" onClick=${edit}>Editar</button>
|
||||||
|
=======
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
<button class="icon-btn" onClick=${toggle}>${props.item.disabled ? 'Habilitar' : 'Deshabilitar'}</button>
|
<button class="icon-btn" onClick=${toggle}>${props.item.disabled ? 'Habilitar' : 'Deshabilitar'}</button>
|
||||||
<button class="icon-btn" onClick=${remove}>Eliminar</button>
|
<button class="icon-btn" onClick=${remove}>Eliminar</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -24,3 +34,7 @@ export default defineComponent({
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
|
|||||||
@@ -7,12 +7,15 @@
|
|||||||
--border: 255 255 255 / 0.12;
|
--border: 255 255 255 / 0.12;
|
||||||
--glass-blur: 14px;
|
--glass-blur: 14px;
|
||||||
--radius: 14px;
|
--radius: 14px;
|
||||||
|
<<<<<<< HEAD
|
||||||
/* Scrollbar */
|
/* Scrollbar */
|
||||||
--sb-size: 10px;
|
--sb-size: 10px;
|
||||||
--sb-thumb: rgba(255, 159, 203, 0.55);
|
--sb-thumb: rgba(255, 159, 203, 0.55);
|
||||||
--sb-thumb-hover: rgba(255, 159, 203, 0.75);
|
--sb-thumb-hover: rgba(255, 159, 203, 0.75);
|
||||||
--sb-thumb-active: rgba(255, 127, 187, 0.9);
|
--sb-thumb-active: rgba(255, 127, 187, 0.9);
|
||||||
--sb-track: rgba(255,255,255,0.05);
|
--sb-track: rgba(255,255,255,0.05);
|
||||||
|
=======
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
}
|
}
|
||||||
:root.light {
|
:root.light {
|
||||||
--bg: 245 245 248;
|
--bg: 245 245 248;
|
||||||
@@ -21,10 +24,13 @@
|
|||||||
--accent: 18 108 242;
|
--accent: 18 108 242;
|
||||||
--card: 255 255 255 / 0.6;
|
--card: 255 255 255 / 0.6;
|
||||||
--border: 0 0 0 / 0.08;
|
--border: 0 0 0 / 0.08;
|
||||||
|
<<<<<<< HEAD
|
||||||
--sb-thumb: rgba(255, 127, 187, 0.65);
|
--sb-thumb: rgba(255, 127, 187, 0.65);
|
||||||
--sb-thumb-hover: rgba(255, 127, 187, 0.82);
|
--sb-thumb-hover: rgba(255, 127, 187, 0.82);
|
||||||
--sb-thumb-active: rgba(255, 110, 178, 0.95);
|
--sb-thumb-active: rgba(255, 110, 178, 0.95);
|
||||||
--sb-track: rgba(0,0,0,0.06);
|
--sb-track: rgba(0,0,0,0.06);
|
||||||
|
=======
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
}
|
}
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
html, body, #app { height: 100%; }
|
html, body, #app { height: 100%; }
|
||||||
@@ -38,6 +44,7 @@ a { color: inherit; }
|
|||||||
position: sticky; top: 0; z-index: 10;
|
position: sticky; top: 0; z-index: 10;
|
||||||
display: flex; flex-wrap: wrap; align-items: center;
|
display: flex; flex-wrap: wrap; align-items: center;
|
||||||
gap: 10px; padding: 10px 14px; backdrop-filter: blur(var(--glass-blur));
|
gap: 10px; padding: 10px 14px; backdrop-filter: blur(var(--glass-blur));
|
||||||
|
<<<<<<< HEAD
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
background:
|
background:
|
||||||
linear-gradient(rgba(var(--card)), rgba(var(--card))) padding-box,
|
linear-gradient(rgba(var(--card)), rgba(var(--card))) padding-box,
|
||||||
@@ -62,6 +69,10 @@ a { color: inherit; }
|
|||||||
rgba(0, 0, 0, 0.00) 70%
|
rgba(0, 0, 0, 0.00) 70%
|
||||||
) border-box;
|
) border-box;
|
||||||
border-width: 0.5px; /* borde más delgado en dark */
|
border-width: 0.5px; /* borde más delgado en dark */
|
||||||
|
=======
|
||||||
|
background: linear-gradient(180deg, rgba(var(--card)), rgba(var(--card)) 60%, rgba(0,0,0,0));
|
||||||
|
border-bottom: 1px solid rgba(var(--border));
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
}
|
}
|
||||||
.title { font-size: 16px; font-weight: 700; letter-spacing: .2px; flex: 1 1 auto; }
|
.title { font-size: 16px; font-weight: 700; letter-spacing: .2px; flex: 1 1 auto; }
|
||||||
.actions { display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
.actions { display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
||||||
@@ -72,6 +83,7 @@ a { color: inherit; }
|
|||||||
|
|
||||||
/* Layout */
|
/* Layout */
|
||||||
.shell { height: calc(100vh - 54px); display: grid; grid-template-columns: 360px 1fr; gap: 12px; padding: 12px; }
|
.shell { height: calc(100vh - 54px); display: grid; grid-template-columns: 360px 1fr; gap: 12px; padding: 12px; }
|
||||||
|
<<<<<<< HEAD
|
||||||
.panel {
|
.panel {
|
||||||
border: 1px solid #ffcfe4; /* light más claro */
|
border: 1px solid #ffcfe4; /* light más claro */
|
||||||
background: linear-gradient(rgba(var(--card)), rgba(var(--card))) padding-box;
|
background: linear-gradient(rgba(var(--card)), rgba(var(--card))) padding-box;
|
||||||
@@ -80,6 +92,9 @@ a { color: inherit; }
|
|||||||
overflow: hidden; display: flex; flex-direction: column; min-height: 0;
|
overflow: hidden; display: flex; flex-direction: column; min-height: 0;
|
||||||
}
|
}
|
||||||
:root:not(.light) .panel { border-color: #ff2e86; border-width: 0.5px; /* borde más delgado en dark */ }
|
:root:not(.light) .panel { border-color: #ff2e86; border-width: 0.5px; /* borde más delgado en dark */ }
|
||||||
|
=======
|
||||||
|
.panel { border: 1px solid rgba(var(--border)); background: rgba(var(--card)); border-radius: var(--radius); backdrop-filter: blur(var(--glass-blur)); overflow: hidden; display: flex; flex-direction: column; min-height: 0; }
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
.panel-header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; padding: 10px 12px; border-bottom: 1px solid rgba(var(--border)); }
|
.panel-header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; padding: 10px 12px; border-bottom: 1px solid rgba(var(--border)); }
|
||||||
.panel-title { font-weight: 600; }
|
.panel-title { font-weight: 600; }
|
||||||
.panel-actions { display: inline-flex; flex-wrap: wrap; gap: 6px; }
|
.panel-actions { display: inline-flex; flex-wrap: wrap; gap: 6px; }
|
||||||
@@ -112,6 +127,7 @@ a { color: inherit; }
|
|||||||
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
||||||
.spacer { flex: 1; }
|
.spacer { flex: 1; }
|
||||||
.toggle { padding: 6px 10px; border-radius: 8px; border: 1px solid rgba(var(--border)); background: rgba(var(--card)); }
|
.toggle { padding: 6px 10px; border-radius: 8px; border: 1px solid rgba(var(--border)); background: rgba(var(--card)); }
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
/* Scrollbars */
|
/* Scrollbars */
|
||||||
/* Firefox */
|
/* Firefox */
|
||||||
@@ -142,3 +158,5 @@ html::-webkit-scrollbar-thumb:active, body::-webkit-scrollbar-thumb:active, .scr
|
|||||||
background: var(--sb-thumb-active);
|
background: var(--sb-thumb-active);
|
||||||
background-clip: content-box;
|
background-clip: content-box;
|
||||||
}
|
}
|
||||||
|
=======
|
||||||
|
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
|
||||||
|
|||||||
Reference in New Issue
Block a user