Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit07290d1

Browse files
Dan notification banner (#1197)
1 parent73f24dd commit07290d1

File tree

16 files changed

+298
-13
lines changed

16 files changed

+298
-13
lines changed

‎pgml-dashboard/src/api/cms.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ impl Collection {
266266
Some(cluster.context.user.clone())
267267
};
268268

269-
letmut layout =crate::templates::Layout::new(&title);
269+
letmut layout =crate::templates::Layout::new(&title,Some(cluster.clone()));
270270
ifletSome(image) = image{
271271
// translate relative url into absolute for head social sharing
272272
let parts = image.split(".gitbook/assets/").collect::<Vec<&str>>();

‎pgml-dashboard/src/components/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ pub use nav_link::NavLink;
5353
// src/components/navigation
5454
pubmod navigation;
5555

56+
// src/components/notifications
57+
pubmod notifications;
58+
5659
// src/components/postgres_logo
5760
pubmod postgres_logo;
5861
pubuse postgres_logo::PostgresLogo;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#notifications-banner {
2+
margin-left:calc(var(--bs-gutter-x)*-0.5);
3+
margin-right:calc(var(--bs-gutter-x)*-0.5);
4+
}
5+
6+
div[data-controller="notifications-banner"] {
7+
.btn-tertiary {
8+
border:0px;
9+
}
10+
.news {
11+
background-color:#{$gray-100};
12+
color:#{$gray-900};
13+
.btn-tertiary:hover {
14+
filter:brightness(0.9);
15+
}
16+
}
17+
.blog {
18+
background-color:#{$neon-shade-100};
19+
.btn-tertiary {
20+
filter:brightness(1.5);
21+
}
22+
}
23+
.launch {
24+
background-color:#{$magenta-shade-200};
25+
.btn-tertiary {
26+
filter:brightness(1.5);
27+
}
28+
}
29+
.tip {
30+
background-color:#{$gray-900};
31+
}
32+
.level1 {
33+
background-color:#FFFF00;
34+
color:#{$gray-900};
35+
}
36+
.level2 {
37+
background-color:#FF6929;
38+
color:#{$gray-900};
39+
}
40+
.level3 {
41+
background-color:#{$peach-shade-200};
42+
}
43+
44+
.close-dark {
45+
color:#{$gray-900};
46+
}
47+
.close-light {
48+
color:#{$gray-100};
49+
}
50+
.close-dark,.close-light {
51+
margin-left:-100%;
52+
}
53+
54+
.message-area {
55+
max-width:75vw;
56+
}
57+
58+
.banner {
59+
min-height:2rem;
60+
}
61+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import{Controller}from'@hotwired/stimulus'
2+
3+
exportdefaultclassextendsController{}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
usecrate::{Notification,NotificationLevel};
2+
use pgml_components::component;
3+
use sailfish::TemplateOnce;
4+
5+
#[derive(TemplateOnce,Default,Clone)]
6+
#[template(path ="notifications/banner/template.html")]
7+
pubstructBanner{
8+
pubnotification:Notification,
9+
pubremove_banner:bool,
10+
}
11+
12+
implBanner{
13+
pubfnnew() ->Banner{
14+
Banner{
15+
notification:Notification::default(),
16+
remove_banner:false,
17+
}
18+
}
19+
20+
pubfnfrom_notification(notification:Notification) ->Banner{
21+
Banner{
22+
notification,
23+
remove_banner:false,
24+
}
25+
}
26+
27+
pubfnremove_banner(mutself,remove_banner:bool) ->Banner{
28+
self.remove_banner = remove_banner;
29+
self
30+
}
31+
}
32+
33+
component!(Banner);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<% use crate::NotificationLevel; %>
2+
<turbo-frameid="notifications-banner"class="position-relative d-block">
3+
<% if !remove_banner {%>
4+
<divdata-controller="notifications-banner">
5+
<divclass="<%- notification.level.to_string() %> W-100">
6+
<divclass="banner d-flex container p-1">
7+
<divclass="flex-grow-1 d-flex flex-column flex-md-row justify-content-center align-items-center row-gap-0 column-gap-3 fw-semibold overflow-hidden">
8+
<divclass="mx-3 overflow-hidden"style="max-width: 80%;">
9+
<pclass="m-0 text-center"><%- notification.message %></p>
10+
</div>
11+
<% if notification.link.is_some() {%>
12+
<aclass="btn btn-tertiary fw-semibold p-0"href="<%- notification.link.unwrap() %>"data-turbo="false">
13+
Learn More
14+
<spanclass="material-symbols-outlined">arrow_forward</span>
15+
</a>
16+
<% } %>
17+
</div>
18+
<% if notification.dismissible {%>
19+
<aclass="w-0 overflow-visible d-flex align-items-center"style="right: 4vw"href="/dashboard/notifications/remove_banner?id=<%- notification.id%>">
20+
<spanclass="material-symbols-outlined <% if notification.level == NotificationLevel::Tip {%>close-light<% } else {%>close-dark<% } %>">
21+
close
22+
</span></a>
23+
<% } %>
24+
</div>
25+
</div>
26+
</div>
27+
<% } %>
28+
</turbo-frame>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// This file is automatically generated.
2+
// You shouldn't modify it manually.
3+
4+
// src/components/notifications/banner
5+
pubmod banner;
6+
pubuse banner::Banner;

‎pgml-dashboard/src/guards.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ use sqlx::{postgres::PgPoolOptions, Executor, PgPool};
88

99
staticPOOL:OnceCell<PgPool> =OnceCell::new();
1010

11-
usecrate::{models, utils::config,Context};
11+
usecrate::{models, utils::config,Context,Notification};
1212

13-
#[derive(Debug)]
13+
#[derive(Debug,Clone,Default)]
1414
pubstructCluster{
1515
pubpool:Option<PgPool>,
1616
pubcontext:Context,
17+
pubnotifications:Option<Vec<Notification>>,
1718
}
1819

1920
implCluster{
@@ -132,6 +133,7 @@ impl Cluster {
132133
lower_left_nav:StaticNav::default(),
133134
marketing_footer:MarketingFooter::new().render_once().unwrap(),
134135
},
136+
notifications:None,
135137
}
136138
}
137139
}

‎pgml-dashboard/src/lib.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
externcrate rocket;
33

44
use rocket::form::Form;
5+
use rocket::http::{Cookie,CookieJar};
56
use rocket::response::Redirect;
67
use rocket::route::Route;
78
use rocket::serde::json::Json;
@@ -20,6 +21,7 @@ pub mod templates;
2021
pubmod types;
2122
pubmod utils;
2223

24+
use components::notifications::banner::Banner;
2325
use guards::{Cluster,ConnectedCluster};
2426
use responses::{BadRequest,Error,ResponseOk};
2527
use templates::{
@@ -28,6 +30,10 @@ use templates::{
2830
};
2931
use utils::tabs;
3032

33+
usecrate::utils::cookies::Notifications;
34+
use std::collections::hash_map::DefaultHasher;
35+
use std::hash::{Hash,Hasher};
36+
3137
#[derive(Debug,Default,Clone)]
3238
pubstructClustersSettings{
3339
pubmax_connections:u32,
@@ -50,6 +56,77 @@ pub struct Context {
5056
pubmarketing_footer:String,
5157
}
5258

59+
#[derive(Debug,Clone,Default)]
60+
pubstructNotification{
61+
pubmessage:String,
62+
publevel:NotificationLevel,
63+
pubid:String,
64+
pubdismissible:bool,
65+
pubviewed:bool,
66+
publink:Option<String>,
67+
}
68+
implNotification{
69+
pubfnnew(message:&str) ->Notification{
70+
letmut s =DefaultHasher::new();
71+
message.hash(&mut s);
72+
73+
Notification{
74+
message: message.to_string(),
75+
level:NotificationLevel::News,
76+
id: s.finish().to_string(),
77+
dismissible:true,
78+
viewed:false,
79+
link:None,
80+
}
81+
}
82+
83+
pubfnlevel(mutself,level:&NotificationLevel) ->Notification{
84+
self.level = level.clone();
85+
self
86+
}
87+
88+
pubfndismissible(mutself,dismissible:bool) ->Notification{
89+
self.dismissible = dismissible;
90+
self
91+
}
92+
93+
pubfnlink(mutself,link:&str) ->Notification{
94+
self.link =Some(link.into());
95+
self
96+
}
97+
98+
pubfnviewed(mutself,viewed:bool) ->Notification{
99+
self.viewed = viewed;
100+
self
101+
}
102+
}
103+
104+
impl std::fmt::DisplayforNotificationLevel{
105+
fnfmt(&self,f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result{
106+
matchself{
107+
NotificationLevel::News =>write!(f,"news"),
108+
NotificationLevel::Blog =>write!(f,"blog"),
109+
NotificationLevel::Launch =>write!(f,"launch"),
110+
NotificationLevel::Tip =>write!(f,"tip"),
111+
NotificationLevel::Level1 =>write!(f,"level1"),
112+
NotificationLevel::Level2 =>write!(f,"level2"),
113+
NotificationLevel::Level3 =>write!(f,"level3"),
114+
}
115+
}
116+
}
117+
118+
#[derive(Debug,Clone,Default,PartialEq)]
119+
pubenumNotificationLevel{
120+
#[default]
121+
News,
122+
Blog,
123+
Launch,
124+
Tip,
125+
Level1,
126+
Level2,
127+
Level3,
128+
}
129+
53130
#[get("/projects")]
54131
pubasyncfnproject_index(cluster:ConnectedCluster<'_>) ->Result<ResponseOk,Error>{
55132
Ok(ResponseOk(
@@ -672,6 +749,30 @@ pub async fn playground(cluster: &Cluster) -> Result<ResponseOk, Error> {
672749
Ok(ResponseOk(layout.render(templates::Playground{})))
673750
}
674751

752+
#[get("/notifications/remove_banner?<id>")]
753+
pubfnremove_banner(id:String,cookies:&CookieJar<'_>,context:&Cluster) ->ResponseOk{
754+
letmut viewed =Notifications::get_viewed(cookies);
755+
756+
viewed.push(id);
757+
Notifications::update_viewed(&viewed, cookies);
758+
759+
match context.notifications.as_ref(){
760+
Some(notifications) =>{
761+
for notificationin notifications{
762+
if !viewed.contains(&notification.id){
763+
returnResponseOk(
764+
Banner::from_notification(notification.clone())
765+
.render_once()
766+
.unwrap(),
767+
);
768+
}
769+
}
770+
returnResponseOk(Banner::new().remove_banner(true).render_once().unwrap());
771+
}
772+
None =>returnResponseOk(Banner::new().remove_banner(true).render_once().unwrap()),
773+
}
774+
}
775+
675776
pubfnroutes() ->Vec<Route>{
676777
routes![
677778
notebook_index,
@@ -699,6 +800,7 @@ pub fn routes() -> Vec<Route> {
699800
uploaded_index,
700801
dashboard,
701802
notebook_reorder,
803+
remove_banner,
702804
]
703805
}
704806

‎pgml-dashboard/src/responses.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,8 @@ impl<'r> response::Responder<'r, 'r> for Response {
8181
let body =matchself.body{
8282
Some(body) => body,
8383
None =>matchself.status.code{
84-
404 =>{
85-
templates::Layout::new("Internal Server Error").render(templates::NotFound{})
86-
}
84+
404 => templates::Layout::new("Internal Server Error",None)
85+
.render(templates::NotFound{}),
8786
_ =>"".into(),
8887
},
8988
};
@@ -134,8 +133,8 @@ impl<'r> response::Responder<'r, 'r> for Error {
134133
"".into()
135134
};
136135

137-
let body =
138-
templates::Layout::new("Internal Server Error").render(templates::Error{ error});
136+
let body = templates::Layout::new("Internal Server Error",None)
137+
.render(templates::Error{ error});
139138

140139
response::Response::build_from(body.respond_to(request)?)
141140
.header(ContentType::new("text","html"))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp