Function bodies 57 total
DashboardApp function · typescript · L3-L11 (9 LOC)frontend/src/app/DashboardApp.tsx
export function DashboardApp() {
return (
<main className="app-shell">
<div className="app-shell__content">
<TaskDashboard />
</div>
</main>
)
}App function · typescript · L4-L6 (3 LOC)frontend/src/App.tsx
function App() {
return <DashboardApp />
}EmptyState function · typescript · L6-L13 (8 LOC)frontend/src/components/EmptyState.tsx
export function EmptyState({ title, description }: EmptyStateProps) {
return (
<div className="empty-state">
<h3>{title}</h3>
<p>{description}</p>
</div>
)
}StatusBadge function · typescript · L7-L16 (10 LOC)frontend/src/components/StatusBadge.tsx
export function StatusBadge({ status }: StatusBadgeProps) {
const tone = getTaskStatusTone(status)
return (
<span className={`status-badge status-badge--${tone}`}>
<span className="status-badge__dot" />
{getTaskStatusLabel(status)}
</span>
)
}TaskDashboard function · typescript · L10-L183 (174 LOC)frontend/src/features/tasks/TaskDashboard.tsx
export function TaskDashboard() {
const [tasks, setTasks] = useState<Task[]>([])
const [selectedStatus, setSelectedStatus] = useState<string>('all')
const [activeTask, setActiveTask] = useState<Task | null>(null)
const [isLoading, setIsLoading] = useState<boolean>(true)
const [isSubmitting, setIsSubmitting] = useState<boolean>(false)
const [busyTaskId, setBusyTaskId] = useState<number | null>(null)
const [screenError, setScreenError] = useState<string | null>(null)
const [formError, setFormError] = useState<string | null>(null)
useEffect(() => {
void loadTasks(selectedStatus)
}, [selectedStatus])
async function loadTasks(statusFilter: string) {
setIsLoading(true)
setScreenError(null)
try {
const status = statusFilter === 'all' ? undefined : Number(statusFilter)
const data = await getTasks(status)
setTasks(data)
} catch (error) {
setScreenError(getErrorMessage(error))
} finally {
setIsLoading(false)
}
}loadTasks function · typescript · L24-L37 (14 LOC)frontend/src/features/tasks/TaskDashboard.tsx
async function loadTasks(statusFilter: string) {
setIsLoading(true)
setScreenError(null)
try {
const status = statusFilter === 'all' ? undefined : Number(statusFilter)
const data = await getTasks(status)
setTasks(data)
} catch (error) {
setScreenError(getErrorMessage(error))
} finally {
setIsLoading(false)
}
}handleSubmit function · typescript · L39-L60 (22 LOC)frontend/src/features/tasks/TaskDashboard.tsx
async function handleSubmit(payload: TaskPayload, taskId?: number): Promise<boolean> {
setIsSubmitting(true)
setFormError(null)
try {
if (typeof taskId === 'number') {
const updatePayload: TaskUpdatePayload = { ...payload, id: taskId }
await updateTask(taskId, updatePayload)
setActiveTask(null)
} else {
await createTask(payload)
}
await loadTasks(selectedStatus)
return true
} catch (error) {
setFormError(getErrorMessage(error))
return false
} finally {
setIsSubmitting(false)
}
}Repobility analyzer · published findings · https://repobility.com
handleDelete function · typescript · L62-L82 (21 LOC)frontend/src/features/tasks/TaskDashboard.tsx
async function handleDelete(task: Task) {
const confirmed = window.confirm(`¿Eliminar la tarea "${task.name}"?`)
if (!confirmed) {
return
}
setBusyTaskId(task.id)
setScreenError(null)
try {
await deleteTask(task.id)
if (activeTask?.id === task.id) {
setActiveTask(null)
}
await loadTasks(selectedStatus)
} catch (error) {
setScreenError(getErrorMessage(error))
} finally {
setBusyTaskId(null)
}
}getFilterLabel function · typescript · L185-L195 (11 LOC)frontend/src/features/tasks/TaskDashboard.tsx
function getFilterLabel(value: string): string {
if (value === '1') {
return 'Pendiente'
}
if (value === '2') {
return 'Completada'
}
return 'Todas'
}TaskForm function · typescript · L33-L254 (222 LOC)frontend/src/features/tasks/TaskForm.tsx
export function TaskForm({
activeTask,
isSubmitting,
formError,
onCancelEdit,
onSubmit,
}: TaskFormProps) {
const [formState, setFormState] = useState<TaskFormState>(INITIAL_STATE)
const [localError, setLocalError] = useState<string | null>(null)
useEffect(() => {
if (!activeTask) {
setFormState(INITIAL_STATE)
setLocalError(null)
return
}
setFormState({
name: activeTask.name,
beginDate: formatApiDateToInput(activeTask.begin_date),
endDate: formatApiDateToInput(activeTask.end_date),
shortDescription: activeTask.short_description ?? '',
longDescription: activeTask.long_description ?? '',
status: String(activeTask.status),
})
setLocalError(null)
}, [activeTask])
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault()
setLocalError(null)
const beginDate = formatInputDateToApi(formState.beginDate)
const endDate = formatInputDateToApi(formState.endhandleSubmit function · typescript · L61-L92 (32 LOC)frontend/src/features/tasks/TaskForm.tsx
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault()
setLocalError(null)
const beginDate = formatInputDateToApi(formState.beginDate)
const endDate = formatInputDateToApi(formState.endDate)
if (!formState.name.trim()) {
setLocalError('El nombre de la tarea es obligatorio.')
return
}
if (!isValidApiDate(beginDate) || !isValidApiDate(endDate)) {
setLocalError('Las fechas deben existir y tener formato DD-MM-YYYY.')
return
}
const payload: TaskPayload = {
name: formState.name.trim(),
begin_date: beginDate,
end_date: endDate,
short_description: formState.shortDescription.trim() || null,
long_description: formState.longDescription.trim() || null,
status: Number(formState.status),
}
const wasSuccessful = await onSubmit(payload, activeTask?.id)
if (!activeTask && wasSuccessful) {
setFormState(INITIAL_STATE)
}
}handleChange function · typescript · L94-L99 (6 LOC)frontend/src/features/tasks/TaskForm.tsx
function handleChange<Key extends keyof TaskFormState>(key: Key, value: TaskFormState[Key]) {
setFormState((current) => ({
...current,
[key]: value,
}))
}TaskStatusFilter function · typescript · L9-L30 (22 LOC)frontend/src/features/tasks/TaskStatusFilter.tsx
export function TaskStatusFilter({ value, disabled = false, onChange }: TaskStatusFilterProps) {
return (
<div className="status-filter">
<label className="status-filter__label" htmlFor="task-status-filter">
Filtrar por estado
</label>
<select
id="task-status-filter"
className="select status-filter__select"
value={value}
disabled={disabled}
onChange={(event) => onChange(event.target.value)}
>
{TASK_FILTER_OPTIONS.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
)
}TaskTable function · typescript · L13-L90 (78 LOC)frontend/src/features/tasks/TaskTable.tsx
export function TaskTable({ tasks, busyTaskId, isLoading, onEdit, onDelete }: TaskTableProps) {
if (!isLoading && tasks.length === 0) {
return (
<div className="table-wrapper">
<EmptyState
title="No hay tareas para mostrar"
description="Crea una nueva tarea o cambia el filtro para ver otros resultados."
/>
</div>
)
}
return (
<div className="table-wrapper">
<div className="table-scroll">
<table className="task-table">
<thead>
<tr>
<th>Tarea</th>
<th>Fechas</th>
<th>Estado</th>
<th>Descripción larga</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
{tasks.map((task) => {
const isBusy = busyTaskId === task.id
return (
<tr key={task.id}>
<td>
<p className="task-title">{task.name}</p>
ApiError class · typescript · L8-L18 (11 LOC)frontend/src/services/http.ts
export class ApiError extends Error {
readonly status: number
readonly detail: unknown
constructor(message: string, status: number, detail: unknown) {
super(message)
this.name = 'ApiError'
this.status = status
this.detail = detail
}
}Repobility (the analyzer behind this table) · https://repobility.com
constructor method · typescript · L12-L17 (6 LOC)frontend/src/services/http.ts
constructor(message: string, status: number, detail: unknown) {
super(message)
this.name = 'ApiError'
this.status = status
this.detail = detail
}requestJson function · typescript · L20-L55 (36 LOC)frontend/src/services/http.ts
export async function requestJson<T>(path: string, options: RequestOptions = {}): Promise<T> {
const { expectedStatus, headers, ...requestInit } = options
const response = await fetch(`${API_BASE_URL}${path}`, {
...requestInit,
headers: {
Accept: 'application/json',
...headers,
},
})
const isJsonResponse = response.headers.get('content-type')?.includes('application/json') ?? false
const responseBody = isJsonResponse ? await response.json() : null
if (!response.ok) {
const message =
extractValidationMessage(responseBody) ||
(typeof responseBody === 'object' &&
responseBody !== null &&
'detail' in responseBody &&
typeof responseBody.detail === 'string'
? responseBody.detail
: `La solicitud falló con estado ${response.status}.`)
throw new ApiError(message, response.status, responseBody)
}
if (expectedStatus && !expectedStatus.includes(response.status)) {
throw new ApiError(
`La API extractValidationMessage function · typescript · L57-L68 (12 LOC)frontend/src/services/http.ts
function extractValidationMessage(value: unknown): string | null {
if (!value || typeof value !== 'object' || !('detail' in value)) {
return null
}
const detail = (value as ValidationErrorResponse).detail
if (!Array.isArray(detail) || detail.length === 0) {
return null
}
return detail.map((issue) => issue.msg).join(' ')
}getTasks function · typescript · L4-L13 (10 LOC)frontend/src/services/tasksApi.ts
export async function getTasks(status?: number): Promise<Task[]> {
const query = typeof status === 'number' ? `?status=${status}` : ''
const response = await requestJson<unknown>(`/tasks${query}`, { method: 'GET' })
if (!Array.isArray(response)) {
return []
}
return response as Task[]
}createTask function · typescript · L15-L24 (10 LOC)frontend/src/services/tasksApi.ts
export async function createTask(payload: TaskPayload): Promise<CreateTaskResponse> {
return requestJson<CreateTaskResponse>('/tasks', {
method: 'POST',
expectedStatus: [200, 201],
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
}updateTask function · typescript · L26-L35 (10 LOC)frontend/src/services/tasksApi.ts
export async function updateTask(id: number, payload: TaskUpdatePayload): Promise<void> {
await requestJson<null>(`/tasks/${id}`, {
method: 'PUT',
expectedStatus: [200, 204],
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
}deleteTask function · typescript · L37-L42 (6 LOC)frontend/src/services/tasksApi.ts
export async function deleteTask(id: number): Promise<void> {
await requestJson<null>(`/tasks/${id}`, {
method: 'DELETE',
expectedStatus: [200, 204],
})
}isValidApiDate function · typescript · L3-L17 (15 LOC)frontend/src/utils/date.ts
export function isValidApiDate(value: string): boolean {
const match = API_DATE_REGEX.exec(value)
if (!match) {
return false
}
const [, day, month, year] = match
const parsedDate = new Date(Number(year), Number(month) - 1, Number(day))
return (
parsedDate.getFullYear() === Number(year) &&
parsedDate.getMonth() === Number(month) - 1 &&
parsedDate.getDate() === Number(day)
)
}Repobility · open methodology · https://repobility.com/research/
formatInputDateToApi function · typescript · L19-L27 (9 LOC)frontend/src/utils/date.ts
export function formatInputDateToApi(value: string): string {
if (!value) {
return ''
}
const [year, month, day] = value.split('-')
return `${day}-${month}-${year}`
}formatApiDateToInput function · typescript · L29-L38 (10 LOC)frontend/src/utils/date.ts
export function formatApiDateToInput(value: string): string {
const match = API_DATE_REGEX.exec(value)
if (!match) {
return ''
}
const [, day, month, year] = match
return `${year}-${month}-${day}`
}getErrorMessage function · typescript · L3-L13 (11 LOC)frontend/src/utils/error.ts
export function getErrorMessage(error: unknown): string {
if (error instanceof ApiError) {
return error.message
}
if (error instanceof Error) {
return error.message
}
return 'Ocurrió un error inesperado. Intenta nuevamente.'
}getTaskStatusLabel function · typescript · L1-L11 (11 LOC)frontend/src/utils/status.ts
export function getTaskStatusLabel(status: number): string {
if (status === 1) {
return 'Pendiente'
}
if (status === 2) {
return 'Completada'
}
return `Estado ${status}`
}getTaskStatusTone function · typescript · L13-L23 (11 LOC)frontend/src/utils/status.ts
export function getTaskStatusTone(status: number): string {
if (status === 1) {
return 'pending'
}
if (status === 2) {
return 'done'
}
return 'unknown'
}Task class · python · L3-L9 (7 LOC)src/app/models/task.py
class Task(BaseModel):
name: str
begin_date: str
end_date: str
short_description: str | None
long_description: str | None
status: intTaskUpdate class · python · L3-L10 (8 LOC)src/app/models/task_update.py
class TaskUpdate(BaseModel):
id: int
name: str
begin_date: str
end_date: str
short_description: str | None
long_description: str | None
status: intBaseRepository class · python · L5-L43 (39 LOC)src/app/repository/base_repository.py
class BaseRepository:
def __enter__(self):
# Se ejecuta al momento de abrir la conexión y crea la conexión y el cursor. Retorna el DAO
self.connection = connect()
self.cursor = self.connection.cursor()
return self
def __exit__(self, exc_type, exc_value, traceback):
# Se ejecuta siempre al cierre de la operación; en caso de éxito hace commit, sino hace rollback. Para finalizar cierra conexión y cursor.
if exc_type:
self.connection.rollback()
else:
self.connection.commit()
self.cursor.close()
self.connection.close()
def _execute_query(self, query, params=None, mode=None):
"""
Ejecuta una consulta SQL.
# Params:
- query: la consulta SQL.
- params: los parámetros para la consulta.
- mode: 'one' para fetchone, 'all' para fetchall, None para operaciones tipo INSERT/UPDATE/DELETE.
"""
try:
if params is None:
Repobility · MCP-ready · https://repobility.com
__enter__ method · python · L6-L10 (5 LOC)src/app/repository/base_repository.py
def __enter__(self):
# Se ejecuta al momento de abrir la conexión y crea la conexión y el cursor. Retorna el DAO
self.connection = connect()
self.cursor = self.connection.cursor()
return self__exit__ method · python · L12-L19 (8 LOC)src/app/repository/base_repository.py
def __exit__(self, exc_type, exc_value, traceback):
# Se ejecuta siempre al cierre de la operación; en caso de éxito hace commit, sino hace rollback. Para finalizar cierra conexión y cursor.
if exc_type:
self.connection.rollback()
else:
self.connection.commit()
self.cursor.close()
self.connection.close()_execute_query method · python · L21-L43 (23 LOC)src/app/repository/base_repository.py
def _execute_query(self, query, params=None, mode=None):
"""
Ejecuta una consulta SQL.
# Params:
- query: la consulta SQL.
- params: los parámetros para la consulta.
- mode: 'one' para fetchone, 'all' para fetchall, None para operaciones tipo INSERT/UPDATE/DELETE.
"""
try:
if params is None:
self.cursor.execute(query)
else:
self.cursor.execute(query, params)
if mode == "one":
return fetch_one(self.cursor)
elif mode == "all":
return fetch_all(self.cursor)
elif mode is None:
return {"rowcount": self.cursor.rowcount, "lastrowid": self.cursor.lastrowid}
except:
raiseTasksRepository class · python · L3-L40 (38 LOC)src/app/repository/task_repository.py
class TasksRepository(BaseRepository):
def get_tasks(self):
query = """SELECT * FROM tasks;"""
return self._execute_query(query, mode="all")
def get_task_by_id(self, id: int):
query = """SELECT * FROM tasks WHERE id = ?;"""
return self._execute_query(query, params=(id,), mode="one")
def get_tasks_by_status(self, status: int):
query = """SELECT * FROM tasks WHERE status = ?"""
return self._execute_query(query, params=(status,), mode="all")
def create_task(self, name: str, begin_date: str, end_date: str, short_description: str, long_description: str, status: int):
query = """
INSERT INTO tasks (name, begin_date, end_date, short_description, long_description, status)
VALUES (?, ?, ?, ?, ?, ?);
"""
try:
data = self._execute_query(query, mode=None, params=(name, begin_date, end_date, short_description, long_description, status))
if data["get_tasks method · python · L4-L6 (3 LOC)src/app/repository/task_repository.py
def get_tasks(self):
query = """SELECT * FROM tasks;"""
return self._execute_query(query, mode="all")get_task_by_id method · python · L8-L10 (3 LOC)src/app/repository/task_repository.py
def get_task_by_id(self, id: int):
query = """SELECT * FROM tasks WHERE id = ?;"""
return self._execute_query(query, params=(id,), mode="one")get_tasks_by_status method · python · L12-L14 (3 LOC)src/app/repository/task_repository.py
def get_tasks_by_status(self, status: int):
query = """SELECT * FROM tasks WHERE status = ?"""
return self._execute_query(query, params=(status,), mode="all")create_task method · python · L16-L26 (11 LOC)src/app/repository/task_repository.py
def create_task(self, name: str, begin_date: str, end_date: str, short_description: str, long_description: str, status: int):
query = """
INSERT INTO tasks (name, begin_date, end_date, short_description, long_description, status)
VALUES (?, ?, ?, ?, ?, ?);
"""
try:
data = self._execute_query(query, mode=None, params=(name, begin_date, end_date, short_description, long_description, status))
if data["rowcount"] == 1:
return {"id": data["lastrowid"]}
except Exception:
raiseRepobility analyzer · published findings · https://repobility.com
delete_task method · python · L28-L31 (4 LOC)src/app/repository/task_repository.py
def delete_task(self, id: int):
query = """DELETE FROM tasks WHERE id = ?;"""
data = self._execute_query(query, (id,))
return dataupdate_task method · python · L33-L40 (8 LOC)src/app/repository/task_repository.py
def update_task(self, id: int, name: str, begin_date: str, end_date: str, short_description: str, long_description: str, status: int):
query = """
UPDATE tasks
SET name = ?, begin_date = ?, end_date = ?,
short_description = ?, long_description = ?, status = ?
WHERE id = ?
"""
return self._execute_query(query, (name, begin_date, end_date, short_description, long_description, status, id))get_tasks function · python · L20-L31 (12 LOC)src/app/routers/tasks.py
async def get_tasks(status: int | None = None):
with TasksRepository() as repo:
service = TasksService(repo)
data = None
if status is not None:
try:
data = service.list_tasks_by_status(status)
except ValueError as e:
raise HTTPException(400, detail=f"{e}")
else:
data = service.list_tasks()
return datacreate_task function · python · L38-L54 (17 LOC)src/app/routers/tasks.py
async def create_task(task: Task):
with TasksRepository() as repo:
service = TasksService(repo)
try:
task = service.create_task_service(
task.name,
task.begin_date,
task.end_date,
task.short_description,
task.long_description,
task.status
)
return JSONResponse(content={"id": task}, status_code=201, headers={"Location": f"/tasks/{task}"})
except ValueError as e:
raise HTTPException(400, detail=str(e))
except Exception as e:
raise HTTPException(500, detail=str(e))delete_task function · python · L61-L71 (11 LOC)src/app/routers/tasks.py
async def delete_task(id: int):
with TasksRepository() as repo:
service = TasksService(repo)
try:
task = service.get_task(id)
except NotFoundError:
raise HTTPException(status_code=404, detail=f"No existe la tarea con ID: {id}")
service.delete_task_service(task["id"])
return Response(status_code=204)update_task function · python · L78-L95 (18 LOC)src/app/routers/tasks.py
async def update_task(task: TaskUpdate):
try:
with TasksRepository() as repo:
service = TasksService(repo)
service.update_task_service(
task.id,
task.name,
task.begin_date,
task.end_date,
task.short_description,
task.long_description,
task.status
)
return Response(status_code=204)
except ValueError as e:
raise HTTPException(400, detail=str(e))
except NotFoundError as e:
raise HTTPException(404, detail=str(e))TasksService class · python · L5-L70 (66 LOC)src/app/services/tasks_service.py
class TasksService:
def __init__(self, repo: TasksRepository):
self.repo = repo
def list_tasks(self):
return self.repo.get_tasks()
def get_task(self, id: int):
task = self.repo.get_task_by_id(id)
if not task:
raise NotFoundError("La tarea no existe.")
return task
def list_tasks_by_status(self, status: int):
if status not in (0, 1, 2):
raise ValueError("Estado inválido.")
return self.repo.get_tasks_by_status(status)
def create_task_service(self, name: str, begin_date: str, end_date: str, short_description: str, long_description: str, status: int):
if not name:
raise ValueError("La tarea debe tener un nombre")
if not validate_date(begin_date):
raise ValueError("La fecha de inicio no es válida.")
if not validate_date(end_date):
raise ValueError("La fecha de finalización no es válida.")
if status not in (0, 1, 2):
get_task method · python · L12-L16 (5 LOC)src/app/services/tasks_service.py
def get_task(self, id: int):
task = self.repo.get_task_by_id(id)
if not task:
raise NotFoundError("La tarea no existe.")
return taskRepobility (the analyzer behind this table) · https://repobility.com
list_tasks_by_status method · python · L18-L21 (4 LOC)src/app/services/tasks_service.py
def list_tasks_by_status(self, status: int):
if status not in (0, 1, 2):
raise ValueError("Estado inválido.")
return self.repo.get_tasks_by_status(status)create_task_service method · python · L23-L42 (20 LOC)src/app/services/tasks_service.py
def create_task_service(self, name: str, begin_date: str, end_date: str, short_description: str, long_description: str, status: int):
if not name:
raise ValueError("La tarea debe tener un nombre")
if not validate_date(begin_date):
raise ValueError("La fecha de inicio no es válida.")
if not validate_date(end_date):
raise ValueError("La fecha de finalización no es válida.")
if status not in (0, 1, 2):
raise ValueError("Estado inválido.")
try:
data = self.repo.create_task(name, begin_date, end_date, short_description, long_description, status)
lastrowid = data.get("id")
if lastrowid:
return lastrowid
except Exception:
raisedelete_task_service method · python · L44-L52 (9 LOC)src/app/services/tasks_service.py
def delete_task_service(self, id: int):
try:
data = self.repo.delete_task(id)
rowcount = data["rowcount"]
if rowcount == 0:
raise NotFoundError("La tarea no existe en la base de datos.")
return True
except Exception:
raisepage 1 / 2next ›