Skip to content

Commit

Permalink
chg: refactor tag component, show taxonomy predicates and entries in …
Browse files Browse the repository at this point in the history
…taxonomy view
  • Loading branch information
righel committed Dec 4, 2024
1 parent d0ed79a commit c7f5bad
Show file tree
Hide file tree
Showing 13 changed files with 289 additions and 41 deletions.
9 changes: 8 additions & 1 deletion api/app/repositories/taxonomies.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ def update_taxonomies(db: Session):
description=raw_taxonomy["description"],
version=raw_taxonomy["version"],
enabled=False,
exclusive=False,
exclusive=(
raw_taxonomy["exclusive"]
if "exclusive" in raw_taxonomy
else False
),
required=False,
highlighted=False,
)
Expand Down Expand Up @@ -93,6 +97,9 @@ def update_taxonomies(db: Session):
else raw_predicate["value"]
),
value=raw_predicate["value"],
colour=(
raw_predicate["colour"] if "colour" in raw_predicate else ""
),
)

db.add(db_predicate)
Expand Down
18 changes: 17 additions & 1 deletion api/app/routers/taxonomies.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from app.repositories import taxonomies as taxonomies_repository
from app.schemas import taxonomy as taxonomies_schemas
from app.schemas import user as user_schemas
from fastapi import APIRouter, Depends, Security
from fastapi import APIRouter, Depends, HTTPException, Security, status
from fastapi_pagination import Page
from sqlalchemy.orm import Session

Expand All @@ -20,6 +20,22 @@ def get_taxonomies(
return taxonomies_repository.get_taxonomies(db)


@router.get("/taxonomies/{taxonomy_id}", response_model=taxonomies_schemas.Taxonomy)
def get_taxonomy_by_id(
taxonomy_id: int,
db: Session = Depends(get_db),
user: user_schemas.User = Security(
get_current_active_user, scopes=["taxonomies:read"]
),
) -> taxonomies_schemas.Taxonomy:
db_taxonomy = taxonomies_repository.get_taxonomy_by_id(db, taxonomy_id=taxonomy_id)
if db_taxonomy is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Attribute not found"
)
return db_taxonomy


@router.post("/taxonomies/update", response_model=list[taxonomies_schemas.Taxonomy])
def update_taxonomies(
db: Session = Depends(get_db),
Expand Down
37 changes: 20 additions & 17 deletions api/app/schemas/taxonomy.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@ class TaxonomyBase(BaseModel):
highlighted: bool


class Taxonomy(TaxonomyBase):
id: int
model_config = ConfigDict(from_attributes=True)


class TaxonomyUpdate(BaseModel):
enabled: Optional[bool] = None
exclusive: Optional[bool] = None
highlighted: Optional[bool] = None
enabled: Optional[bool] = None

Expand All @@ -28,26 +24,33 @@ class TaxonomyPredicateBase(BaseModel):
taxonomy_id: int
value: str
expanded: str
colour: str
description: str
exclusive: bool
numerical_value: int


class TaxonomyPredicate(TaxonomyPredicateBase):
id: int
model_config = ConfigDict(from_attributes=True)
colour: Optional[str]
description: Optional[str]
exclusive: Optional[bool]
numerical_value: Optional[int]


class TaxonomyEntryBase(BaseModel):
taxonomy_predicate_id: int
value: str
expanded: str
colour: str
description: str
numerical_value: int
colour: Optional[str]
description: Optional[str]
numerical_value: Optional[int]


class TaxonomyEntry(TaxonomyEntryBase):
id: int
model_config = ConfigDict(from_attributes=True)


class TaxonomyPredicate(TaxonomyPredicateBase):
id: int
entries: list[TaxonomyEntry] = []
model_config = ConfigDict(from_attributes=True)


class Taxonomy(TaxonomyBase):
id: int
predicates: list[TaxonomyPredicate] = []
model_config = ConfigDict(from_attributes=True)
24 changes: 24 additions & 0 deletions frontend/src/components/misc/Badge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script setup>
import { tagHelper } from "@/helpers";
const props = defineProps({
value: {
type: String,
required: true
},
colour: {
type: String,
default: '#000000'
},
namespace: {
type: String,
default: ''
}
});
</script>

<template>
<span class="badge mx-1 tag" :style="{ backgroundColor: tagHelper.getBackgroundColor(props.colour), color: tagHelper.getContrastColor(props.colour) }" :title="props.value">
{{ tagHelper.getTag(props.namespace, props.value) }}
</span>
</template>
28 changes: 7 additions & 21 deletions frontend/src/components/tags/TagsIndex.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<script setup>
import Badge from "@/components/misc/Badge.vue";
import { tagHelper } from "@/helpers";
defineProps(['tags']);
</script>

<style scoped>
Expand All @@ -14,10 +19,7 @@ defineProps(['tags']);
</style>
<template>
<div class="col-auto">
<span class="badge mx-1 tag" v-for="tag in tags" :key="tag.name"
:style="{ backgroundColor: tag.colour, color: getContrastColor(tag.colour) }" :title="tag.name">
{{ tag.name }}
</span>
<Badge v-for="tag in tags" :key="tag.name" :value="tag.name" :colour="tag.colour" />
</div>
</template>

Expand All @@ -28,23 +30,7 @@ export default {
type: Array,
required: true,
},
},
methods: {
getContrastColor(hex) {
hex = hex.replace("#", "");
// Convert the hex color to RGB
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
// Calculate the luminance
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
// If luminance is high, use black text; otherwise, use white text
return luminance > 0.5 ? "#000000" : "#FFFFFF";
},
},
}
};
</script>

Expand Down
11 changes: 11 additions & 0 deletions frontend/src/components/taxonomies/TaxonomiesIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function toggle(property, taxonomy) {
<!-- <th scope="col">description</th> -->
<th scope="col">version</th>
<th scope="col">enabled</th>
<th scope="col">exclusive</th>
<th scope="col">required</th>
<th scope="col">highlighted</th>
<th scope="col">active tags</th>
Expand All @@ -70,6 +71,16 @@ function toggle(property, taxonomy) {
</button>
</div>
</td>
<td>
<div class="flex-wrap btn-group me-2">
<button type="button" class="btn" @click="toggle('exclusive', taxonomy)"
:class="{ 'btn-outline-success': taxonomy.exclusive, 'btn-outline-danger': !taxonomy.exclusive }"
data-toggle="tooltip" data-placement="top" title="Toggle taxonomy">
<font-awesome-icon v-if="taxonomy.exclusive" icon="fa-solid fa-check" />
<font-awesome-icon v-if="!taxonomy.exclusive" icon="fa-solid fa-xmark" />
</button>
</div>
</td>
<td>
<div class="flex-wrap btn-group me-2">
<button type="button" class="btn" @click="toggle('required', taxonomy)"
Expand Down
124 changes: 124 additions & 0 deletions frontend/src/components/taxonomies/TaxonomyView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<script setup>
import Badge from "@/components/misc/Badge.vue";
const props = defineProps(['taxonomy', 'status']);
function handleTaxonomyDeleted(event) {
router.go(-1);
}
</script>

<style>
.single-stat-card .card-body {
font-size: x-large;
text-align: center;
padding: 0;
}
div.row h3 {
margin-bottom: 0;
}
.single-stat-card .card-body p {
margin-bottom: 0;
}
</style>
<template>
<div class="card">
<div class="taxonomy-title card-header border-bottom">
<div class="row">
<div class="col-10">
<h3>Taxonomy #{{ taxonomy.id }}</h3>
</div>
<div class="col-2 text-end">
<div class="flex-wrap" :class="{ 'btn-group-vertical': $isMobile, 'btn-group': !$isMobile }"
aria-label="Taxonomy Actions">
<button type="button" class="btn btn-outline-danger" data-bs-toggle="modal"
:data-bs-target="'#deleteTaxonomyModal-' + taxonomy.id">
<font-awesome-icon icon="fa-solid fa-trash" />
</button>
</div>
</div>
</div>
</div>
<div class="row m-1">
<div class="mt-2">
<div class="card">
<div class="card-body d-flex flex-column">
<div class="table-responsive-sm">
<table class="table table-striped">
<tbody>
<tr>
<th>id</th>
<td>{{ taxonomy.id }}</td>
</tr>
<tr>
<th>description</th>
<td>{{ taxonomy.description }}</td>
</tr>
<tr>
<th>version</th>
<td>{{ taxonomy.version }}</td>
</tr>
<tr>
<th>enabled</th>
<td>{{ taxonomy.enabled }}</td>
</tr>
<tr>
<th>exclusive</th>
<td>{{ taxonomy.exclusive }}</td>
</tr>
<tr>
<th>required</th>
<td>{{ taxonomy.required }}</td>
</tr>
<tr>
<th>highlighted</th>
<td>{{ taxonomy.highlighted }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="row">
<div class="mt-2">
<div class="card">
<div class="card-body d-flex flex-column">
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">id</th>
<th scope="col">tag</th>
<th scope="col">expanded</th>
</tr>
</thead>
<tbody>
<template v-for="predicate in taxonomy.predicates" :key="predicate.id">
<tr v-if="predicate.entries.length" v-for="entry in predicate.entries" :key="entry.id">
<td>{{ entry.id }}</td>
<td>
<Badge :value="entry.value" :namespace="taxonomy.namespace" :colour="entry.colour" />
</td>
<td>{{ entry.expanded }}</td>
</tr>
<tr v-if="!predicate.entries.length" >
<td>{{ predicate.id }}</td>
<td>
<Badge :value="predicate.value" :namespace="taxonomy.namespace" :colour="predicate.colour" />
</td>
<td>{{ predicate.expanded }}</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<DeleteTaxonomyModal @taxonomy-deleted="handleTaxonomyDeleted" :taxonomy_id="taxonomy.id" />
</div>
</template>
1 change: 1 addition & 0 deletions frontend/src/helpers/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./fetch-wrapper";
export * from "./error-handler";
export * from "./tags";
34 changes: 34 additions & 0 deletions frontend/src/helpers/tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export const tagHelper = {
getContrastColor,
getBackgroundColor,
getTag
};

function getTag(namspace, tag) {
if (!namspace || !tag) return "";
return `${namspace}:${tag}`;
}

function getBackgroundColor(hex) {
if (!hex) return "#DDD";
return hex;
};


function getContrastColor(hex) {

if (!hex) return "#000000";

hex = hex.replace("#", "");

// Convert the hex color to RGB
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);

// Calculate the luminance
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;

// If luminance is high, use black text; otherwise, use white text
return luminance > 0.5 ? "#000000" : "#FFFFFF";
};
4 changes: 3 additions & 1 deletion frontend/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import {
AddFeed,
ViewFeed,
UpdateFeed,
IndexTaxonomies
IndexTaxonomies,
ViewTaxonomy
} from "@/views";

export const router = createRouter({
Expand Down Expand Up @@ -60,6 +61,7 @@ export const router = createRouter({
{ path: "/feeds/:id", component: ViewFeed, props: true },
{ path: "/feeds/add", component: AddFeed },
{ path: "/feeds/update/:id", component: UpdateFeed, props: true },
{ path: "/taxonomies/:id", component: ViewTaxonomy, props: true },
],
});

Expand Down
Loading

0 comments on commit c7f5bad

Please sign in to comment.