Expose merge conflicts in the JavaScript editor. This fixes #23
This commit is contained in:
parent
b685139d5b
commit
a09aa4b601
3 changed files with 71 additions and 30 deletions
|
@ -78,15 +78,27 @@ function openEditor() {
|
|||
// Update body:
|
||||
rendered.innerHTML = result.rendered;
|
||||
|
||||
if (result.conflict) {
|
||||
form.elements.title.value = result.title;
|
||||
form.elements.body.value = result.body;
|
||||
}
|
||||
|
||||
// Update form:
|
||||
form.elements.base_revision.value = result.revision;
|
||||
for (const element of form.elements) {
|
||||
element.defaultValue = element.value;
|
||||
}
|
||||
|
||||
container.classList.remove('edit');
|
||||
if (!result.conflict) {
|
||||
container.classList.remove('edit');
|
||||
}
|
||||
|
||||
textarea.disabled = false;
|
||||
|
||||
if (result.conflict) {
|
||||
alert("Your edit came into conflict with another change and has not been saved.\n" +
|
||||
"Please resolve the merge conflict and save again.");
|
||||
}
|
||||
}).catch(err => {
|
||||
textarea.disabled = false;
|
||||
console.error(err);
|
||||
|
|
|
@ -133,9 +133,11 @@ impl Resource for ArticleResource {
|
|||
|
||||
#[derive(Serialize)]
|
||||
struct PutResponse<'a> {
|
||||
conflict: bool,
|
||||
slug: &'a str,
|
||||
revision: i32,
|
||||
title: &'a str,
|
||||
body: Option<&'a str>,
|
||||
rendered: &'a str,
|
||||
last_updated: &'a str,
|
||||
}
|
||||
|
@ -150,26 +152,54 @@ impl Resource for ArticleResource {
|
|||
.and_then(move |update: UpdateArticle| {
|
||||
self.state.update_article(self.article_id, update.base_revision, update.title, update.body, identity)
|
||||
})
|
||||
.and_then(|updated| {
|
||||
let updated = updated.unwrap();
|
||||
futures::finished(Response::new()
|
||||
.with_status(hyper::StatusCode::Ok)
|
||||
.with_header(ContentType(APPLICATION_JSON.clone()))
|
||||
.with_body(serde_json::to_string(&PutResponse {
|
||||
slug: &updated.slug,
|
||||
revision: updated.revision,
|
||||
title: &updated.title,
|
||||
rendered: &Template {
|
||||
.and_then(|updated| match updated {
|
||||
UpdateResult::Success(updated) =>
|
||||
Ok(Response::new()
|
||||
.with_status(hyper::StatusCode::Ok)
|
||||
.with_header(ContentType(APPLICATION_JSON.clone()))
|
||||
.with_body(serde_json::to_string(&PutResponse {
|
||||
conflict: false,
|
||||
slug: &updated.slug,
|
||||
revision: updated.revision,
|
||||
title: &updated.title,
|
||||
rendered: render_markdown(&updated.body),
|
||||
}.to_string(),
|
||||
last_updated: &last_updated(
|
||||
updated.article_id,
|
||||
&Local.from_utc_datetime(&updated.created),
|
||||
updated.author.as_ref().map(|x| &**x)
|
||||
),
|
||||
}).expect("Should never fail"))
|
||||
)
|
||||
body: None,
|
||||
rendered: &Template {
|
||||
title: &updated.title,
|
||||
rendered: render_markdown(&updated.body),
|
||||
}.to_string(),
|
||||
last_updated: &last_updated(
|
||||
updated.article_id,
|
||||
&Local.from_utc_datetime(&updated.created),
|
||||
updated.author.as_ref().map(|x| &**x)
|
||||
),
|
||||
}).expect("Should never fail"))
|
||||
),
|
||||
UpdateResult::RebaseConflict(RebaseConflict {
|
||||
base_article, title, body
|
||||
}) => {
|
||||
let title = title.flatten();
|
||||
let body = body.flatten();
|
||||
Ok(Response::new()
|
||||
.with_status(hyper::StatusCode::Ok)
|
||||
.with_header(ContentType(APPLICATION_JSON.clone()))
|
||||
.with_body(serde_json::to_string(&PutResponse {
|
||||
conflict: true,
|
||||
slug: &base_article.slug,
|
||||
revision: base_article.revision,
|
||||
title: &title,
|
||||
body: Some(&body),
|
||||
rendered: &Template {
|
||||
title: &title,
|
||||
rendered: render_markdown(&body),
|
||||
}.to_string(),
|
||||
last_updated: &last_updated(
|
||||
base_article.article_id,
|
||||
&Local.from_utc_datetime(&base_article.created),
|
||||
base_article.author.as_ref().map(|x| &**x)
|
||||
),
|
||||
}).expect("Should never fail"))
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
19
src/state.rs
19
src/state.rs
|
@ -58,16 +58,6 @@ pub enum UpdateResult {
|
|||
RebaseConflict(RebaseConflict),
|
||||
}
|
||||
|
||||
impl UpdateResult {
|
||||
// TODO Move to mod tests below
|
||||
pub fn unwrap(self) -> models::ArticleRevision {
|
||||
match self {
|
||||
UpdateResult::Success(x) => x,
|
||||
_ => panic!("Expected success")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decide_slug(conn: &SqliteConnection, article_id: i32, prev_title: &str, title: &str, prev_slug: Option<&str>) -> Result<String, Error> {
|
||||
let base_slug = ::slug::slugify(title);
|
||||
|
||||
|
@ -485,6 +475,15 @@ mod test {
|
|||
use super::*;
|
||||
use db;
|
||||
|
||||
impl UpdateResult {
|
||||
pub fn unwrap(self) -> models::ArticleRevision {
|
||||
match self {
|
||||
UpdateResult::Success(x) => x,
|
||||
_ => panic!("Expected success")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! init {
|
||||
($state:ident) => {
|
||||
let db = db::test_connection();
|
||||
|
|
Loading…
Reference in a new issue