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:
|
// Update body:
|
||||||
rendered.innerHTML = result.rendered;
|
rendered.innerHTML = result.rendered;
|
||||||
|
|
||||||
|
if (result.conflict) {
|
||||||
|
form.elements.title.value = result.title;
|
||||||
|
form.elements.body.value = result.body;
|
||||||
|
}
|
||||||
|
|
||||||
// Update form:
|
// Update form:
|
||||||
form.elements.base_revision.value = result.revision;
|
form.elements.base_revision.value = result.revision;
|
||||||
for (const element of form.elements) {
|
for (const element of form.elements) {
|
||||||
element.defaultValue = element.value;
|
element.defaultValue = element.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.classList.remove('edit');
|
if (!result.conflict) {
|
||||||
|
container.classList.remove('edit');
|
||||||
|
}
|
||||||
|
|
||||||
textarea.disabled = false;
|
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 => {
|
}).catch(err => {
|
||||||
textarea.disabled = false;
|
textarea.disabled = false;
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
|
@ -133,9 +133,11 @@ impl Resource for ArticleResource {
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct PutResponse<'a> {
|
struct PutResponse<'a> {
|
||||||
|
conflict: bool,
|
||||||
slug: &'a str,
|
slug: &'a str,
|
||||||
revision: i32,
|
revision: i32,
|
||||||
title: &'a str,
|
title: &'a str,
|
||||||
|
body: Option<&'a str>,
|
||||||
rendered: &'a str,
|
rendered: &'a str,
|
||||||
last_updated: &'a str,
|
last_updated: &'a str,
|
||||||
}
|
}
|
||||||
|
@ -150,26 +152,54 @@ impl Resource for ArticleResource {
|
||||||
.and_then(move |update: UpdateArticle| {
|
.and_then(move |update: UpdateArticle| {
|
||||||
self.state.update_article(self.article_id, update.base_revision, update.title, update.body, identity)
|
self.state.update_article(self.article_id, update.base_revision, update.title, update.body, identity)
|
||||||
})
|
})
|
||||||
.and_then(|updated| {
|
.and_then(|updated| match updated {
|
||||||
let updated = updated.unwrap();
|
UpdateResult::Success(updated) =>
|
||||||
futures::finished(Response::new()
|
Ok(Response::new()
|
||||||
.with_status(hyper::StatusCode::Ok)
|
.with_status(hyper::StatusCode::Ok)
|
||||||
.with_header(ContentType(APPLICATION_JSON.clone()))
|
.with_header(ContentType(APPLICATION_JSON.clone()))
|
||||||
.with_body(serde_json::to_string(&PutResponse {
|
.with_body(serde_json::to_string(&PutResponse {
|
||||||
slug: &updated.slug,
|
conflict: false,
|
||||||
revision: updated.revision,
|
slug: &updated.slug,
|
||||||
title: &updated.title,
|
revision: updated.revision,
|
||||||
rendered: &Template {
|
|
||||||
title: &updated.title,
|
title: &updated.title,
|
||||||
rendered: render_markdown(&updated.body),
|
body: None,
|
||||||
}.to_string(),
|
rendered: &Template {
|
||||||
last_updated: &last_updated(
|
title: &updated.title,
|
||||||
updated.article_id,
|
rendered: render_markdown(&updated.body),
|
||||||
&Local.from_utc_datetime(&updated.created),
|
}.to_string(),
|
||||||
updated.author.as_ref().map(|x| &**x)
|
last_updated: &last_updated(
|
||||||
),
|
updated.article_id,
|
||||||
}).expect("Should never fail"))
|
&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),
|
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> {
|
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);
|
let base_slug = ::slug::slugify(title);
|
||||||
|
|
||||||
|
@ -485,6 +475,15 @@ mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use db;
|
use db;
|
||||||
|
|
||||||
|
impl UpdateResult {
|
||||||
|
pub fn unwrap(self) -> models::ArticleRevision {
|
||||||
|
match self {
|
||||||
|
UpdateResult::Success(x) => x,
|
||||||
|
_ => panic!("Expected success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! init {
|
macro_rules! init {
|
||||||
($state:ident) => {
|
($state:ident) => {
|
||||||
let db = db::test_connection();
|
let db = db::test_connection();
|
||||||
|
|
Loading…
Reference in a new issue