Skip to content

Commit d91b3e4

Browse files
authored
Merge pull request #73 from ssciwr/fix_52_news_items_editable_from_admin_interface
News items can be edited from admin interface
2 parents 0c1b7df + a3b75b4 commit d91b3e4

File tree

11 files changed

+136
-44
lines changed

11 files changed

+136
-44
lines changed

backend/src/predicTCR_server/app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ def runner_result():
450450
max_filesize_h5_mb=50,
451451
max_filesize_csv_mb=10,
452452
about_md="",
453+
news_items_json="[]",
453454
)
454455
)
455456
db.session.commit()

backend/src/predicTCR_server/model.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class Settings(db.Model):
5757
max_filesize_h5_mb: Mapped[int] = mapped_column(Integer, nullable=False)
5858
max_filesize_csv_mb: Mapped[int] = mapped_column(Integer, nullable=False)
5959
about_md: Mapped[str] = mapped_column(String, nullable=False)
60+
news_items_json: Mapped[str] = mapped_column(String, nullable=False)
6061

6162
def as_dict(self):
6263
return {c: getattr(self, c) for c in inspect(self).attrs.keys()}

backend/tests/test_app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ def test_get_settings_valid(client):
146146
"max_filesize_h5_mb": 50,
147147
"max_filesize_csv_mb": 10,
148148
"about_md": "",
149+
"news_items_json": "[]",
149150
}
150151

151152

@@ -165,6 +166,7 @@ def test_update_settings_valid(client):
165166
"max_filesize_csv_mb": 12,
166167
"about_md": "# About",
167168
"invalid-key": "invalid",
169+
"news_items_json": "[{'id': '1', 'url': 'https://example.com', 'text': 'Example'}]",
168170
}
169171
response = client.post("/api/admin/settings", headers=headers, json=new_settings)
170172
assert response.status_code == 200

frontend/src/assets/news.json

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<script setup lang="ts">
2+
import { FwbButton, FwbTextarea } from "flowbite-vue";
3+
import { useSettingsStore } from "@/stores/settings";
4+
5+
const settingsStore = useSettingsStore();
6+
</script>
7+
8+
<template>
9+
<div class="flex flex-col mb-2 p-2" v-if="settingsStore.settings">
10+
<fwb-textarea
11+
v-model="settingsStore.settings.about_md"
12+
:rows="32"
13+
class="mb-2"
14+
label="About page text (markdown)"
15+
></fwb-textarea>
16+
<fwb-button @click="settingsStore.saveChanges" class="mt-2" color="green">
17+
Save
18+
</fwb-button>
19+
</div>
20+
</template>

frontend/src/components/CarouselComponent.vue

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
<script setup lang="ts">
2+
import { computed } from "vue";
23
import { VueperSlides, VueperSlide } from "vueperslides";
34
import "vueperslides/dist/vueperslides.css";
4-
import items from "@/assets/news.json";
5+
import { useSettingsStore } from "@/stores/settings";
6+
const settingsStore = useSettingsStore();
7+
8+
const items = computed(() => {
9+
try {
10+
return JSON.parse(settingsStore.settings.news_items_json);
11+
} catch {
12+
return [];
13+
}
14+
});
515
</script>
616

717
<template>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<script setup lang="ts">
2+
import { FwbButton, FwbInput, FwbListGroupItem } from "flowbite-vue";
3+
import { computed } from "vue";
4+
import { useSettingsStore } from "@/stores/settings";
5+
6+
const settingsStore = useSettingsStore();
7+
8+
type Item = {
9+
id: string;
10+
url: string;
11+
text: string;
12+
};
13+
14+
const items = computed((): Array<Item> => {
15+
try {
16+
return JSON.parse(settingsStore.settings.news_items_json);
17+
} catch (e) {
18+
console.log(e);
19+
return [];
20+
}
21+
});
22+
23+
function add() {
24+
settingsStore.settings.news_items_json = JSON.stringify(
25+
items.value.concat([{ id: "", url: "", text: "" }]),
26+
);
27+
}
28+
29+
function remove(id: string) {
30+
settingsStore.settings.news_items_json = JSON.stringify(
31+
items.value.filter((item) => item.id !== id),
32+
);
33+
}
34+
35+
function save() {
36+
settingsStore.settings.news_items_json = JSON.stringify(items.value);
37+
settingsStore.saveChanges();
38+
}
39+
</script>
40+
41+
<template>
42+
<div class="flex flex-col mb-2 p-2" v-if="settingsStore.settings">
43+
<fwb-list-group-item v-for="item in items" v-bind:key="item.id">
44+
<div class="flex flex-col mb-4 flex-grow mr-2">
45+
<fwb-input v-model="item.id" label="ID" class="mb-1" />
46+
<fwb-input v-model="item.url" label="URL" class="mb-1" />
47+
<fwb-input v-model="item.text" label="Text" class="mb-1" />
48+
<fwb-button
49+
color="red"
50+
class="grow-0"
51+
@click="
52+
() => {
53+
remove(item.id);
54+
}
55+
"
56+
>Delete</fwb-button
57+
>
58+
</div>
59+
</fwb-list-group-item>
60+
<fwb-list-group-item>
61+
<fwb-button @click="add" class="my-2 grow">Add new item</fwb-button>
62+
</fwb-list-group-item>
63+
<fwb-button @click="save" class="mt-2" color="green"> Save </fwb-button>
64+
</div>
65+
</template>

frontend/src/components/SettingsTable.vue

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,8 @@
11
<script setup lang="ts">
2-
import { FwbButton, FwbInput, FwbRange, FwbTextarea } from "flowbite-vue";
2+
import { FwbButton, FwbInput, FwbRange } from "flowbite-vue";
33
import { useSettingsStore } from "@/stores/settings";
4-
import { apiClient, logout } from "@/utils/api-client";
54
65
const settingsStore = useSettingsStore();
7-
settingsStore.refresh();
8-
9-
function update_settings() {
10-
apiClient
11-
.post("admin/settings", settingsStore.settings)
12-
.then(() => {
13-
console.log("Settings updated");
14-
})
15-
.catch((error) => {
16-
if (error.response.status > 400) {
17-
logout();
18-
}
19-
console.log(error);
20-
});
21-
}
226
</script>
237

248
<template>
@@ -91,13 +75,7 @@ function update_settings() {
9175
:label="`Max csv upload filesize: ${settingsStore.settings.max_filesize_csv_mb}mb`"
9276
class="mb-2"
9377
/>
94-
<fwb-textarea
95-
v-model="settingsStore.settings.about_md"
96-
:rows="32"
97-
class="mb-2"
98-
label="About page text (markdown)"
99-
></fwb-textarea>
100-
<fwb-button @click="update_settings" class="mt-2" color="green">
78+
<fwb-button @click="settingsStore.saveChanges" class="mt-2" color="green">
10179
Save settings
10280
</fwb-button>
10381
</div>

frontend/src/stores/settings.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ref } from "vue";
22
import type { Settings } from "@/utils/types";
33
import { defineStore } from "pinia";
4-
import { apiClient } from "@/utils/api-client";
4+
import { apiClient, logout } from "@/utils/api-client";
55

66
export const useSettingsStore = defineStore("settings", () => {
77
const settings = ref({
@@ -17,6 +17,7 @@ export const useSettingsStore = defineStore("settings", () => {
1717
about_md: "",
1818
max_filesize_h5_mb: 1,
1919
max_filesize_csv_mb: 1,
20+
news_items_json: "[]",
2021
} as Settings);
2122

2223
function refresh() {
@@ -30,5 +31,19 @@ export const useSettingsStore = defineStore("settings", () => {
3031
});
3132
}
3233

33-
return { settings, refresh };
34+
function saveChanges() {
35+
apiClient
36+
.post("admin/settings", settings.value)
37+
.then(() => {
38+
console.log("Settings updated");
39+
})
40+
.catch((error) => {
41+
if (error.response?.status > 400) {
42+
logout();
43+
}
44+
console.log(error);
45+
});
46+
}
47+
48+
return { settings, refresh, saveChanges };
3449
});

frontend/src/utils/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export type Settings = {
3939
about_md: string;
4040
max_filesize_h5_mb: number;
4141
max_filesize_csv_mb: number;
42+
news_items_json: string;
4243
};
4344

4445
export type Job = {

frontend/src/views/AdminView.vue

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import UsersTable from "@/components/UsersTable.vue";
55
import ListComponent from "@/components/ListComponent.vue";
66
import JobsTable from "@/components/JobsTable.vue";
77
import ListItem from "@/components/ListItem.vue";
8+
import NewsEditor from "@/components/NewsEditor.vue";
89
import { FwbButton, FwbTab, FwbTabs } from "flowbite-vue";
910
import { onUnmounted, ref } from "vue";
1011
import type { Sample } from "@/utils/types";
1112
import { apiClient, logout } from "@/utils/api-client";
13+
import AboutEditor from "@/components/AboutEditor.vue";
1214
1315
function generate_api_token() {
1416
apiClient.get("admin/runner_token").then((response) => {
@@ -99,6 +101,20 @@ onUnmounted(() => {
99101
</ListItem>
100102
</ListComponent>
101103
</fwb-tab>
104+
<fwb-tab name="news" title="News">
105+
<ListComponent>
106+
<ListItem title="News items">
107+
<NewsEditor />
108+
</ListItem>
109+
</ListComponent>
110+
</fwb-tab>
111+
<fwb-tab name="about" title="About">
112+
<ListComponent>
113+
<ListItem title="About page">
114+
<AboutEditor />
115+
</ListItem>
116+
</ListComponent>
117+
</fwb-tab>
102118
<fwb-tab name="settings" title="Settings">
103119
<ListComponent>
104120
<ListItem title="Settings">

0 commit comments

Comments
 (0)