Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
41 changes: 41 additions & 0 deletions .github/workflows/main-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Deploy Backend

on:
push:
branches: [main]
paths:
- "backend/**"
- "frontend/**"

jobs:
test-backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Build and test backend
working-directory: ./backend
run: |
docker build --target test -t backend-test .
docker run backend-test

test-frontend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./frontend
steps:
- uses: actions/checkout@v3

- name: Use Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: 18.x
cache: "npm"
cache-dependency-path: "./frontend/package-lock.json"

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build
3 changes: 2 additions & 1 deletion backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ DB_URL=sqlite:///./kanban.db
# Optional Settings
# ---------------
# Application
APP_NAME=Simple Kanban API
APP_NAME=Locus API
DEBUG=false
USE_STATIC=false

# Database Behavior
DB_ECHO=false # Enable SQL query logging
Expand Down
3 changes: 2 additions & 1 deletion backend/kanban_api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@


class Settings(BaseSettings):
app_name: str = "Simple Kanban API"
app_name: str = "Locus API"
debug: bool = False
use_static: bool = False
secret_key: str
algorithm: str
db_url: str
Expand Down
3 changes: 2 additions & 1 deletion backend/kanban_api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ async def lifespan(app: FastAPI):

app.include_router(api)

app.mount("/", StaticFiles(directory=settings.static_files_dir, html=True), name="static")
if settings.use_static:
app.mount("/", StaticFiles(directory=settings.static_files_dir, html=True), name="static")

if __name__ == "__main__":
import uvicorn
Expand Down
21 changes: 12 additions & 9 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
[tool.poetry]
name = "kanban-api"
name = "locus-api"
version = "0.1.0"
description = "A simple kanban API"
authors = ["Mateo Velez <mateo.velezcobian@gmail.com>"]
authors = [
"Ihor Savenko <csigorek@gmail.com>",
"Mateo Velez <mateo.velezcobian@gmail.com>",
]
license = "MIT License"
readme = "README.md"
packages = [{include = "kanban_api"}]
packages = [{ include = "kanban_api" }]

[tool.poetry.dependencies]
python = ">=3.10"
fastapi = "^0.115.7"
uvicorn = {extras = ["standard"], version = "^0.34.0"}
sqlalchemy = {extras = ["asyncio"], version = "^2.0.37"}
pydantic = {extras = ["email"], version = "^2.10.6"}
uvicorn = { extras = ["standard"], version = "^0.34.0" }
sqlalchemy = { extras = ["asyncio"], version = "^2.0.37" }
pydantic = { extras = ["email"], version = "^2.10.6" }
pyjwt = "^2.10.1"
pydantic-settings = "^2.7.1"
passlib = {extras = ["bcrypt"], version = "^1.7.4"}
passlib = { extras = ["bcrypt"], version = "^1.7.4" }
psycopg2-binary = "^2.9.10"
asyncpg = "^0.30.0"
python-multipart = "^0.0.20"
faker = "^35.0.0"


[tool.poetry.group.dev.dependencies]
fastapi = {extras = ["standard"], version = "^0.115.7"}
fastapi = { extras = ["standard"], version = "^0.115.7" }
pytest = "^8.3.4"
httpx = "^0.28.1"
black = "^24.10.0"
Expand All @@ -42,4 +45,4 @@ preview = true
line-length = 100
target-version = "py310"
select = ["E", "F", "I", "N", "W", "D"]
ignore = ["D100", "D101", "D103", "D102", "D107"]
ignore = ["D100", "D101", "D103", "D102", "D107"]
6 changes: 4 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ services:
retries: 5

backend:
image: skppy/simple-kanban-server:latest
build:
context: backend/
dockerfile: Dockerfile
environment:
SECRET_KEY: e022b6e22b2f42ae5e1d77194a0aac4ff16e47090ac2fd15e15926e3761c2773
ALGORITHM: HS256
Expand All @@ -29,4 +31,4 @@ services:
condition: service_healthy

volumes:
postgres_data:
postgres_data:
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@
"postcss": "^8",
"tailwindcss": "^3.4.1",
"typescript": "^5"
}
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
53 changes: 15 additions & 38 deletions frontend/src/app/board/_components/board.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,27 @@ const Backlog = ({ children }: { children: React.ReactNode }) => {
);
};

export const RezizableBoard = ({
export const BoardColumns = ({
data,
setMetadata,
}: {
data: Data;
setMetadata: Dispatch<SetStateAction<Metadata>>;
}) => {
return (
<ResizablePanelGroup direction="vertical" className="h-full rounded-lg">
<ResizablePanel
defaultSize={70}
minSize={30}
className="h-full flex gap-6 p-6 bg-gradient-to-b from-background to-background/50"
>
{[CardColumn.Todo, CardColumn.Doing, CardColumn.Done].map((columnValue) => (
<div className="h-full flex gap-6 p-6 bg-gradient-to-b from-background to-background/50">
{[CardColumn.Backlog, CardColumn.Todo, CardColumn.Doing, CardColumn.Done].map((columnValue) => (
<Column key={columnValue} title={columnValue}>
{
columnValue === CardColumn.Backlog && (
<AddCard
boardId={data.board.id}
setMetadata={setMetadata}
className="border-2 border-card-foreground/20 hover:border-card-foreground/40 transition-colors shadow-sm hover:shadow-md h-full min-h-16"
/>
)

}
{data.cards
.filter((card) => card.column === columnValue)
.map((card) => (
Expand All @@ -67,35 +72,7 @@ export const RezizableBoard = ({
/>
))}
</Column>
))}
</ResizablePanel>

<ResizableHandle
withHandle
className="bg-gradient-to-r from-border/50 via-border to-border/50"
/>

<ResizablePanel className="h-full bg-gradient-to-b from-background/50 to-background">
<Backlog>
<AddCard
boardId={data.board.id}
setMetadata={setMetadata}
className="border-2 border-card-foreground/20 hover:border-card-foreground/40 transition-colors shadow-sm hover:shadow-md h-full min-h-16"
/>
{data.cards
.filter((card) => card.column === CardColumn.Backlog)
.map((card) => (
<DisplayCard
key={card.id}
card={card}
board={data.board}
setMetadata={setMetadata}
className="border-2 border-card-foreground/20 hover:border-card-foreground/40 transition-colors shadow-sm hover:shadow-md h-full min-h-16"
N={70}
/>
))}
</Backlog>
</ResizablePanel>
</ResizablePanelGroup>
))}
</div>
);
};
4 changes: 2 additions & 2 deletions frontend/src/app/board/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getConfig } from "@/auth/utils";

import { DialogRoot } from "./_components/dialog/dialog";
import { Header } from "./_components/header";
import { RezizableBoard } from "./_components/board";
import { BoardColumns } from "./_components/board";
import { Spinner } from "@/components/ui/spinner";
import { Data, Metadata } from "./_components/interfaces";

Expand Down Expand Up @@ -50,7 +50,7 @@ function BoardContent() {
<div className="h-full w-full flex flex-col">
<Header board={data.board} setMetadata={setMetadata} setOpen={setOpen} />
<div className="h-full bg-background">
<RezizableBoard data={data} setMetadata={setMetadata} />
<BoardColumns data={data} setMetadata={setMetadata} />
</div>
</div>
</DialogRoot>
Expand Down
Loading