diff --git a/admin-frontend/src/components/articles-list.js b/admin-frontend/src/components/articles-list.js new file mode 100644 index 0000000000000000000000000000000000000000..144b708d4fe5e95e5eb3b02ec9884695dc49d3d6 --- /dev/null +++ b/admin-frontend/src/components/articles-list.js @@ -0,0 +1,47 @@ +"use strict"; + +const { fetch_all_articles } = require("../xhr"); + +class ArticleList { + constructor() { + this.state = { + articles: [] + } + this.fetch_list(); + } + + fetch_list() { + fetch_all_articles() + .then(articles => { + this.state.articles = articles; + this.refresh_list(); + }) + .catch(err => console.log(err)) + } + + refresh_list() { + obj2htm.subRender(this.render_list(), document.getElementById("browse-articles-results"), { mode: "replace" }) + } + + render_list() { + return { + tag: "ul", + id: "browse-articles-results", + contents: this.state.articles.map(art => { + return { tag: "li", contents: `[${art.locale}] <b>${art.title}</b> - ${art._id.$oid}` }; + }), + } + } + + render() { + return { + tag: "div", + contents: [ + { tag: "button", onclick: this.fetch_list.bind(this), contents: "REFRESH" }, + this.render_list() + ], + } + } +} + +module.exports = ArticleList; \ No newline at end of file diff --git a/admin-frontend/src/components/root.js b/admin-frontend/src/components/root.js index e4cf91679b9ed73c8c0773b96b0a0737a4e044f6..4dfc6e540663ea44242d6575c0dd0764a07e8738 100644 --- a/admin-frontend/src/components/root.js +++ b/admin-frontend/src/components/root.js @@ -1,6 +1,7 @@ const CreateArticleForm = require("./create-article-form"); const UpdateArticleForm = require("./update-article-form"); +const ArticleList = require("./articles-list"); class RootComponent { constructor() { @@ -20,6 +21,8 @@ class RootComponent { return new CreateArticleForm().render(); case "update": return new UpdateArticleForm().render(); + case "browse": + return new ArticleList().render(); default: return undefined; } @@ -43,6 +46,11 @@ class RootComponent { class: this.state.selected_tab === "update" ? "selected" : "", onclick: this.handle_nav_click.bind(this), }, + { + tag: "span", contents: "Browse articles", tab_name: "browse", + class: this.state.selected_tab === "browse" ? "selected" : "", + onclick: this.handle_nav_click.bind(this), + }, ], }, this.render_state(), diff --git a/admin-frontend/src/xhr.js b/admin-frontend/src/xhr.js index 6d1e210272f6f5341dcf919b90e2a5e0a04c202b..32845c93ec1121fef9b79b74fc8c61c31191467c 100644 --- a/admin-frontend/src/xhr.js +++ b/admin-frontend/src/xhr.js @@ -107,6 +107,22 @@ async function fetch_delete_article(article_id) { }); } +async function fetch_all_articles() { + return new Promise((resolve, reject) => { + fetch(`/articles`) + .then(async res => { + if (res.status >= 400 && res.status < 600) { + const text = await res.text(); + reject(text) + } else { + const json = await res.json(); + resolve(json); + } + }) + .catch(err => reject(err)) + }); +} + module.exports = { fetch_article, @@ -115,4 +131,5 @@ module.exports = { fetch_post_article, fetch_update_article, fetch_delete_article, + fetch_all_articles, } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 3b83cc9cb176d13ad6690363143a9a0391a07eae..91b8a4ff80e7eda66522fef84f91323b8b2a9c57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -89,6 +89,7 @@ async fn main() -> std::io::Result<()> { .service(get_articles_by_category) .service(get_article) .service(get_article_by_title) + .service(get_all_articles) ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // STANDARD FILES /////////////////////////////////////////////////////////////////////////////////////////// .service(resource("/favicon.ico").route(get().to(favicon))) diff --git a/src/service/articles.rs b/src/service/articles.rs index 3d5abc23619db42a21a9ed5055150c0707cf0fc4..692ca3c5480ab452fa1e15c69b8a066db78650cc 100644 --- a/src/service/articles.rs +++ b/src/service/articles.rs @@ -175,6 +175,27 @@ pub async fn get_article_by_title( } } +#[get("/articles")] +pub async fn get_all_articles(app_state: Data<AppState>) -> impl Responder { + match get_collection(&app_state).find(None, None).await { + Ok(mut cursor) => { + let mut results: Vec<Article> = Vec::new(); + while let Some(result) = cursor.next().await { + match result { + Ok(article) => { + results.push(article); + } + Err(_) => { + return HttpResponse::InternalServerError().finish(); + } + } + } + HttpResponse::Ok().json(results) + } + Err(_) => HttpResponse::InternalServerError().finish(), + } +} + /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@@ *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@@ * _______ ______ ______ _______ *@@ diff --git a/website/src/style.scss b/website/src/style.scss index e230ce652c57499dec5c31bf0a05311054939e96..9fce3a9fed41050678982cc276c743b5f7a109e8 100644 --- a/website/src/style.scss +++ b/website/src/style.scss @@ -383,39 +383,14 @@ main { .detail { display: grid; grid-template-columns: 1fr auto; + gap: 20px; font-size: 12px; border-bottom: 1px solid $light_0; - padding: 5px 0; label { font-weight: bold; color: $medium_grey; } - ul { - display: flex; - flex-wrap: wrap; - gap: 10px; - } - } - } - .detail { - display: grid; - grid-template-columns: 1fr auto; - font-size: 12px; - border-bottom: 1px solid $light_0; - - padding: 5px 0; - label { - font-weight: bold; - color: $medium_grey; - } - .label { - color: $light_2; - } - ul { - display: flex; - flex-wrap: wrap; - gap: 10px; } } }