When a new user is added, it now gives them a column -- as well as when you remove a user it deletes their column and moves all tasks to ROD

This commit is contained in:
NPS Agent
2026-05-12 09:32:56 +09:30
parent 6bcea3ee5d
commit 62d431818a
4 changed files with 24 additions and 14 deletions
+8 -2
View File
@@ -57,6 +57,10 @@ function App() {
const { tasks, users: dbUsers, audit, loading } = useApiData(authed); const { tasks, users: dbUsers, audit, loading } = useApiData(authed);
const [tab, setTab] = React.useState('overview'); const [tab, setTab] = React.useState('overview');
React.useEffect(() => {
window.dbUsers = dbUsers;
}, [dbUsers]);
const [adding, setAdding] = React.useState(null); const [adding, setAdding] = React.useState(null);
const [openTaskId, setOpenTaskId] = React.useState(null); const [openTaskId, setOpenTaskId] = React.useState(null);
const [showLogs, setShowLogs] = React.useState(false); const [showLogs, setShowLogs] = React.useState(false);
@@ -72,7 +76,7 @@ function App() {
]); ]);
if (!authed) { if (!authed) {
return <LoginScreen onLogin={async (id, pwd) => { return <LoginScreen dbUsers={dbUsers} onLogin={async (id, pwd) => {
await api.login(id, pwd); await api.login(id, pwd);
setMeId(id); setMeId(id);
setAuthed(true); setAuthed(true);
@@ -200,6 +204,7 @@ function App() {
<div className="app"> <div className="app">
<TopBar <TopBar
me={me} me={me}
dbUsers={dbUsers}
isAdmin={isAdmin} isAdmin={isAdmin}
tab={tab} tab={tab}
setTab={setTab} setTab={setTab}
@@ -214,6 +219,7 @@ function App() {
{tab === 'overview' && ( {tab === 'overview' && (
<OverviewScreen <OverviewScreen
tasks={frontendTasks} density={t.density} tasks={frontendTasks} density={t.density}
dbUsers={dbUsers}
onOpen={(task) => setOpenTaskId(task.id)} onOpen={(task) => setOpenTaskId(task.id)}
onAddFor={(uid) => setAdding(uid)} onAddFor={(uid) => setAdding(uid)}
onMoveTask={moveTask} onMoveTask={moveTask}
@@ -228,7 +234,7 @@ function App() {
)} )}
</main> </main>
<AddTaskModal open={!!adding} onClose={() => setAdding(null)} onSubmit={addTask} defaultAssignee={adding} me={me} /> <AddTaskModal open={!!adding} onClose={() => setAdding(null)} onSubmit={addTask} defaultAssignee={adding} me={me} dbUsers={dbUsers} />
{mappedOpenTask && ( {mappedOpenTask && (
<TaskDetail task={mappedOpenTask} allAudit={frontendAudit} onClose={() => setOpenTaskId(null)} onMove={moveTask} onPriority={setPriority} onComplete={() => completeTask(mappedOpenTask.id)} onReopen={() => reopenTask(mappedOpenTask.id)} onEditDesc={(newDesc) => editTaskDesc(mappedOpenTask.id, newDesc)} onDeleteTask={() => deleteTask(mappedOpenTask.id)} /> <TaskDetail task={mappedOpenTask} allAudit={frontendAudit} onClose={() => setOpenTaskId(null)} onMove={moveTask} onPriority={setPriority} onComplete={() => completeTask(mappedOpenTask.id)} onReopen={() => reopenTask(mappedOpenTask.id)} onEditDesc={(newDesc) => editTaskDesc(mappedOpenTask.id, newDesc)} onDeleteTask={() => deleteTask(mappedOpenTask.id)} />
)} )}
+5 -1
View File
@@ -91,7 +91,11 @@ function fmtDateTime(iso) {
' · ' + d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' }); ' · ' + d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });
} }
function findUser(id) { return USERS.find(u => u.id === id); } function findUser(id) {
const live = window.dbUsers;
if (live) return live.find(u => u.id === id);
return USERS.find(u => u.id === id);
}
function TaskCard({ task, onOpen, density = 'cozy', dragging = false, onDragStart, onDragEnd }) { function TaskCard({ task, onOpen, density = 'cozy', dragging = false, onDragStart, onDragEnd }) {
const author = findUser(task.addedBy); const author = findUser(task.addedBy);
BIN
View File
Binary file not shown.
+11 -11
View File
@@ -1,6 +1,6 @@
// Screens for Dashy // Screens for Dashy
function LoginScreen({ onLogin }) { function LoginScreen({ onLogin, dbUsers = [] }) {
const [pickedId, setPickedId] = React.useState('rod'); const [pickedId, setPickedId] = React.useState('rod');
const [password, setPassword] = React.useState(''); const [password, setPassword] = React.useState('');
const [error, setError] = React.useState(''); const [error, setError] = React.useState('');
@@ -31,7 +31,7 @@ function LoginScreen({ onLogin }) {
<p className="login__sub">Sign in to your team workspace · <span className="mono">murchison-auto</span></p> <p className="login__sub">Sign in to your team workspace · <span className="mono">murchison-auto</span></p>
<div className="login__users"> <div className="login__users">
{USERS.map(u => ( {dbUsers.map(u => (
<button <button
key={u.id} key={u.id}
className={"login__user" + (pickedId === u.id ? " is-picked" : "")} className={"login__user" + (pickedId === u.id ? " is-picked" : "")}
@@ -106,7 +106,7 @@ function BrandMark({ size = 22 }) {
); );
} }
function TopBar({ me, isAdmin, tab, setTab, onAdd, onLogs, onLogout, onProfile, onDB }) { function TopBar({ me, dbUsers = [], isAdmin, tab, setTab, onAdd, onLogs, onLogout, onProfile }) {
return ( return (
<header className="topbar"> <header className="topbar">
<div className="topbar__left"> <div className="topbar__left">
@@ -117,7 +117,7 @@ function TopBar({ me, isAdmin, tab, setTab, onAdd, onLogs, onLogout, onProfile,
<nav className="tabs" role="tablist"> <nav className="tabs" role="tablist">
<Tab id="overview" label="Overview" tab={tab} setTab={setTab} /> <Tab id="overview" label="Overview" tab={tab} setTab={setTab} />
{USERS.map(u => ( {dbUsers.map(u => (
<Tab key={u.id} id={u.id} label={u.name} tab={tab} setTab={setTab} user={u} /> <Tab key={u.id} id={u.id} label={u.name} tab={tab} setTab={setTab} user={u} />
))} ))}
</nav> </nav>
@@ -189,14 +189,14 @@ function HeadsUp({ items, onDismiss, onOpenTask }) {
); );
} }
function OverviewScreen({ tasks, onOpen, onAddFor, density, onMoveTask }) { function OverviewScreen({ tasks, onOpen, onAddFor, density, onMoveTask, dbUsers = [] }) {
const byUser = Object.fromEntries(USERS.map(u => [u.id, []])); const byUser = Object.fromEntries(dbUsers.map(u => [u.id, []]));
tasks.forEach(t => { if (byUser[t.assignee] && t.status !== 'closed') byUser[t.assignee].push(t); }); tasks.forEach(t => { if (byUser[t.assignee] && t.status !== 'closed') byUser[t.assignee].push(t); });
const [draggingTask, setDraggingTask] = React.useState(null); const [draggingTask, setDraggingTask] = React.useState(null);
const [dragOverCol, setDragOverCol] = React.useState(null); const [dragOverCol, setDragOverCol] = React.useState(null);
return ( return (
<div className="board"> <div className="board">
{USERS.map(u => ( {dbUsers.map(u => (
<Column <Column
key={u.id} key={u.id}
user={u} user={u}
@@ -325,7 +325,7 @@ function Section({ title, sub, children }) {
); );
} }
function AddTaskModal({ open, onClose, onSubmit, defaultAssignee, me }) { function AddTaskModal({ open, onClose, onSubmit, defaultAssignee, me, dbUsers = [] }) {
const [title, setTitle] = React.useState(''); const [title, setTitle] = React.useState('');
const [desc, setDesc] = React.useState(''); const [desc, setDesc] = React.useState('');
const [assignee, setAssignee] = React.useState(defaultAssignee || 'lani'); const [assignee, setAssignee] = React.useState(defaultAssignee || 'lani');
@@ -370,7 +370,7 @@ function AddTaskModal({ open, onClose, onSubmit, defaultAssignee, me }) {
<div className="field"> <div className="field">
<span className="field__label">Assign to</span> <span className="field__label">Assign to</span>
<div className="picker"> <div className="picker">
{USERS.map(u => ( {dbUsers.map(u => (
<button <button
type="button" type="button"
key={u.id} key={u.id}
@@ -545,7 +545,7 @@ function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComple
<Field label="Assigned to"> <Field label="Assigned to">
<div className="picker"> <div className="picker">
{USERS.map(u => ( {dbUsers.map(u => (
<button key={u.id} <button key={u.id}
className={"picker__item" + (task.assignee === u.id ? " is-on" : "")} className={"picker__item" + (task.assignee === u.id ? " is-on" : "")}
onClick={() => onMove(task.id, u.id)}> onClick={() => onMove(task.id, u.id)}>
@@ -636,7 +636,7 @@ function AuditScreen({ entries, onOpen }) {
<div className="audit__filter"> <div className="audit__filter">
<FilterChip on={filter==='all'} onClick={() => setFilter('all')}>All</FilterChip> <FilterChip on={filter==='all'} onClick={() => setFilter('all')}>All</FilterChip>
<FilterChip on={filter==='system'} onClick={() => setFilter('system')}>System</FilterChip> <FilterChip on={filter==='system'} onClick={() => setFilter('system')}>System</FilterChip>
{USERS.map(u => ( {dbUsers.map(u => (
<FilterChip key={u.id} on={filter===u.id} onClick={() => setFilter(u.id)}> <FilterChip key={u.id} on={filter===u.id} onClick={() => setFilter(u.id)}>
<Avatar user={u} size={16} /> {u.name} <Avatar user={u} size={16} /> {u.name}
</FilterChip> </FilterChip>