mirror of
https://github.com/discourse/discourse.git
synced 2025-01-18 18:52:45 +08:00
DEV: Migrate publish page modal to Glimmer and DModal (#22663)
This PR migrates the publish page modal to a Glimmer component and DModal. Most of the code is lift-and-shift. However, the component state getters were implemented using meta-programming in the original controller. They have all been inlined here for clarity, searchability, etc.
This commit is contained in:
parent
20ec7ac174
commit
c2e90f8c07
|
@ -0,0 +1,105 @@
|
||||||
|
<DModal
|
||||||
|
@closeModal={{@closeModal}}
|
||||||
|
@title={{i18n "topic.publish_page.title"}}
|
||||||
|
class="publish-page-modal"
|
||||||
|
>
|
||||||
|
<:body>
|
||||||
|
{{#if this.unpublished}}
|
||||||
|
<p>{{i18n "topic.publish_page.unpublished"}}</p>
|
||||||
|
{{else}}
|
||||||
|
<ConditionalLoadingSpinner @condition={{this.initializing}}>
|
||||||
|
<p class="publish-description">{{i18n
|
||||||
|
"topic.publish_page.description"
|
||||||
|
}}</p>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<div class="controls">
|
||||||
|
<label>{{i18n "topic.publish_page.slug"}}</label>
|
||||||
|
<TextField
|
||||||
|
@value={{this.publishedPage.slug}}
|
||||||
|
@onChange={{this.checkSlug}}
|
||||||
|
@onChangeImmediate={{this.startCheckSlug}}
|
||||||
|
@disabled={{this.existing}}
|
||||||
|
@class="publish-slug"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<label>{{i18n "topic.publish_page.public"}}</label>
|
||||||
|
|
||||||
|
<p class="description">
|
||||||
|
<Input
|
||||||
|
@type="checkbox"
|
||||||
|
@checked={{readonly this.publishedPage.public}}
|
||||||
|
{{on "click" this.onChangePublic}}
|
||||||
|
/>
|
||||||
|
{{i18n "topic.publish_page.public_description"}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="publish-url">
|
||||||
|
<ConditionalLoadingSpinner @condition={{this.checking}} />
|
||||||
|
|
||||||
|
{{#if this.existing}}
|
||||||
|
<div class="current-url">
|
||||||
|
{{i18n "topic.publish_page.publish_url"}}
|
||||||
|
<div>
|
||||||
|
<a
|
||||||
|
href={{this.publishedPage.url}}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>{{this.publishedPage.url}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{#if this.showUrl}}
|
||||||
|
<div class="valid-slug">
|
||||||
|
{{i18n "topic.publish_page.preview_url"}}
|
||||||
|
<div class="example-url">{{this.publishedPage.url}}</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.invalid}}
|
||||||
|
{{i18n "topic.publish_page.invalid_slug"}}
|
||||||
|
<span class="invalid-slug">{{this.reason}}.</span>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ConditionalLoadingSpinner>
|
||||||
|
{{/if}}
|
||||||
|
</:body>
|
||||||
|
<:footer>
|
||||||
|
{{#if this.showUnpublish}}
|
||||||
|
<DButton
|
||||||
|
@label="topic.publish_page.unpublish"
|
||||||
|
@icon="trash-alt"
|
||||||
|
@class="btn-danger"
|
||||||
|
@isLoading={{this.unpublishing}}
|
||||||
|
@action={{this.unpublish}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
@class="close-publish-page"
|
||||||
|
@icon="times"
|
||||||
|
@label="close"
|
||||||
|
@action={{@closeModal}}
|
||||||
|
/>
|
||||||
|
{{else if this.unpublished}}
|
||||||
|
<DButton
|
||||||
|
@label="topic.publish_page.publishing_settings"
|
||||||
|
@action={{this.startNew}}
|
||||||
|
/>
|
||||||
|
{{else}}
|
||||||
|
<DButton
|
||||||
|
@label="topic.publish_page.publish"
|
||||||
|
@class="btn-primary publish-page"
|
||||||
|
@icon="file"
|
||||||
|
@disabled={{this.disabled}}
|
||||||
|
@isLoading={{this.saving}}
|
||||||
|
@action={{this.publish}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</:footer>
|
||||||
|
</DModal>
|
|
@ -0,0 +1,165 @@
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
|
const States = {
|
||||||
|
initializing: "initializing",
|
||||||
|
checking: "checking",
|
||||||
|
valid: "valid",
|
||||||
|
invalid: "invalid",
|
||||||
|
saving: "saving",
|
||||||
|
new: "new",
|
||||||
|
existing: "existing",
|
||||||
|
unpublishing: "unpublishing",
|
||||||
|
unpublished: "unpublished",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class PublishPageModal extends Component {
|
||||||
|
@service store;
|
||||||
|
|
||||||
|
@tracked state = States.initializing;
|
||||||
|
@tracked reason = null;
|
||||||
|
@tracked publishedPage = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
this.store
|
||||||
|
.find("published_page", this.args.model.id)
|
||||||
|
.then((page) => {
|
||||||
|
this.state = States.existing;
|
||||||
|
this.publishedPage = page;
|
||||||
|
})
|
||||||
|
.catch(this.startNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
get initializing() {
|
||||||
|
return this.state === States.initializing;
|
||||||
|
}
|
||||||
|
|
||||||
|
get checking() {
|
||||||
|
return this.state === States.checking;
|
||||||
|
}
|
||||||
|
|
||||||
|
get valid() {
|
||||||
|
return this.state === States.valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
get invalid() {
|
||||||
|
return this.state === States.invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
get saving() {
|
||||||
|
return this.state === States.saving;
|
||||||
|
}
|
||||||
|
|
||||||
|
get new() {
|
||||||
|
return this.state === States.new;
|
||||||
|
}
|
||||||
|
|
||||||
|
get existing() {
|
||||||
|
return this.state === States.existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
get unpublishing() {
|
||||||
|
return this.state === States.unpublishing;
|
||||||
|
}
|
||||||
|
|
||||||
|
get unpublished() {
|
||||||
|
return this.state === States.unpublished;
|
||||||
|
}
|
||||||
|
|
||||||
|
get disabled() {
|
||||||
|
return this.state !== States.valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showUrl() {
|
||||||
|
return (
|
||||||
|
this.state === States.valid ||
|
||||||
|
this.state === States.saving ||
|
||||||
|
this.state === States.existing
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get showUnpublish() {
|
||||||
|
return this.state === States.existing || this.state === States.unpublishing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
startCheckSlug() {
|
||||||
|
if (this.state === States.existing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = States.checking;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
checkSlug() {
|
||||||
|
if (this.state === States.existing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return ajax("/pub/check-slug", {
|
||||||
|
data: { slug: this.publishedPage.slug },
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.valid_slug) {
|
||||||
|
this.state = States.valid;
|
||||||
|
} else {
|
||||||
|
this.state = States.invalid;
|
||||||
|
this.reason = result.reason;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
unpublish() {
|
||||||
|
this.state = States.unpublishing;
|
||||||
|
return this.publishedPage
|
||||||
|
.destroyRecord()
|
||||||
|
.then(() => {
|
||||||
|
this.state = States.unpublished;
|
||||||
|
this.args.model.set("publishedPage", null);
|
||||||
|
})
|
||||||
|
.catch((result) => {
|
||||||
|
this.state = States.existing;
|
||||||
|
popupAjaxError(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
publish() {
|
||||||
|
this.state = States.saving;
|
||||||
|
|
||||||
|
return this.publishedPage
|
||||||
|
.update(this.publishedPage.getProperties("slug", "public"))
|
||||||
|
.then(() => {
|
||||||
|
this.state = States.existing;
|
||||||
|
this.args.model.set("publishedPage", this.publishedPage);
|
||||||
|
})
|
||||||
|
.catch((errResult) => {
|
||||||
|
popupAjaxError(errResult);
|
||||||
|
this.state = States.existing;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
startNew() {
|
||||||
|
this.state = States.new;
|
||||||
|
this.publishedPage = this.store.createRecord(
|
||||||
|
"published_page",
|
||||||
|
this.args.model.getProperties("id", "slug", "public")
|
||||||
|
);
|
||||||
|
this.checkSlug();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
onChangePublic(event) {
|
||||||
|
this.publishedPage.set("public", event.target.checked);
|
||||||
|
|
||||||
|
if (this.showUnpublish) {
|
||||||
|
this.publish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,130 +0,0 @@
|
||||||
import { action, computed } from "@ember/object";
|
|
||||||
import { equal, not } from "@ember/object/computed";
|
|
||||||
import Controller from "@ember/controller";
|
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
|
||||||
import { ajax } from "discourse/lib/ajax";
|
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
||||||
|
|
||||||
const States = {
|
|
||||||
initializing: "initializing",
|
|
||||||
checking: "checking",
|
|
||||||
valid: "valid",
|
|
||||||
invalid: "invalid",
|
|
||||||
saving: "saving",
|
|
||||||
new: "new",
|
|
||||||
existing: "existing",
|
|
||||||
unpublishing: "unpublishing",
|
|
||||||
unpublished: "unpublished",
|
|
||||||
};
|
|
||||||
|
|
||||||
const StateHelpers = {};
|
|
||||||
Object.keys(States).forEach((name) => {
|
|
||||||
StateHelpers[name] = equal("state", name);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, StateHelpers, {
|
|
||||||
state: null,
|
|
||||||
reason: null,
|
|
||||||
publishedPage: null,
|
|
||||||
disabled: not("valid"),
|
|
||||||
|
|
||||||
showUrl: computed("state", function () {
|
|
||||||
return (
|
|
||||||
this.state === States.valid ||
|
|
||||||
this.state === States.saving ||
|
|
||||||
this.state === States.existing
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
|
|
||||||
showUnpublish: computed("state", function () {
|
|
||||||
return this.state === States.existing || this.state === States.unpublishing;
|
|
||||||
}),
|
|
||||||
|
|
||||||
onShow() {
|
|
||||||
this.set("state", States.initializing);
|
|
||||||
|
|
||||||
this.store
|
|
||||||
.find("published_page", this.model.id)
|
|
||||||
.then((page) => {
|
|
||||||
this.setProperties({ state: States.existing, publishedPage: page });
|
|
||||||
})
|
|
||||||
.catch(this.startNew);
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
startCheckSlug() {
|
|
||||||
if (this.state === States.existing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.set("state", States.checking);
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
checkSlug() {
|
|
||||||
if (this.state === States.existing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return ajax("/pub/check-slug", {
|
|
||||||
data: { slug: this.publishedPage.slug },
|
|
||||||
}).then((result) => {
|
|
||||||
if (result.valid_slug) {
|
|
||||||
this.set("state", States.valid);
|
|
||||||
} else {
|
|
||||||
this.setProperties({ state: States.invalid, reason: result.reason });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
unpublish() {
|
|
||||||
this.set("state", States.unpublishing);
|
|
||||||
return this.publishedPage
|
|
||||||
.destroyRecord()
|
|
||||||
.then(() => {
|
|
||||||
this.set("state", States.unpublished);
|
|
||||||
this.model.set("publishedPage", null);
|
|
||||||
})
|
|
||||||
.catch((result) => {
|
|
||||||
this.set("state", States.existing);
|
|
||||||
popupAjaxError(result);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
publish() {
|
|
||||||
this.set("state", States.saving);
|
|
||||||
|
|
||||||
return this.publishedPage
|
|
||||||
.update(this.publishedPage.getProperties("slug", "public"))
|
|
||||||
.then(() => {
|
|
||||||
this.set("state", States.existing);
|
|
||||||
this.model.set("publishedPage", this.publishedPage);
|
|
||||||
})
|
|
||||||
.catch((errResult) => {
|
|
||||||
popupAjaxError(errResult);
|
|
||||||
this.set("state", States.existing);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
startNew() {
|
|
||||||
this.setProperties({
|
|
||||||
state: States.new,
|
|
||||||
publishedPage: this.store.createRecord(
|
|
||||||
"published_page",
|
|
||||||
this.model.getProperties("id", "slug", "public")
|
|
||||||
),
|
|
||||||
});
|
|
||||||
this.checkSlug();
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
onChangePublic(isPublic) {
|
|
||||||
this.publishedPage.set("public", isPublic);
|
|
||||||
|
|
||||||
if (this.showUnpublish) {
|
|
||||||
this.publish();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -11,6 +11,7 @@ import showModal from "discourse/lib/show-modal";
|
||||||
import TopicFlag from "discourse/lib/flag-targets/topic-flag";
|
import TopicFlag from "discourse/lib/flag-targets/topic-flag";
|
||||||
import PostFlag from "discourse/lib/flag-targets/post-flag";
|
import PostFlag from "discourse/lib/flag-targets/post-flag";
|
||||||
import HistoryModal from "discourse/components/modal/history";
|
import HistoryModal from "discourse/components/modal/history";
|
||||||
|
import PublishPageModal from "discourse/components/modal/publish-page";
|
||||||
|
|
||||||
const SCROLL_DELAY = 500;
|
const SCROLL_DELAY = 500;
|
||||||
|
|
||||||
|
@ -112,9 +113,8 @@ const TopicRoute = DiscourseRoute.extend({
|
||||||
@action
|
@action
|
||||||
showPagePublish() {
|
showPagePublish() {
|
||||||
const model = this.modelFor("topic");
|
const model = this.modelFor("topic");
|
||||||
showModal("publish-page", {
|
this.modal.show(PublishPageModal, {
|
||||||
model,
|
model,
|
||||||
title: "topic.publish_page.title",
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
<DModalBody>
|
|
||||||
{{#if this.unpublished}}
|
|
||||||
<p>{{i18n "topic.publish_page.unpublished"}}</p>
|
|
||||||
{{else}}
|
|
||||||
<ConditionalLoadingSpinner @condition={{this.initializing}}>
|
|
||||||
<p class="publish-description">{{i18n
|
|
||||||
"topic.publish_page.description"
|
|
||||||
}}</p>
|
|
||||||
|
|
||||||
<form>
|
|
||||||
<div class="controls">
|
|
||||||
<label>{{i18n "topic.publish_page.slug"}}</label>
|
|
||||||
<TextField
|
|
||||||
@value={{this.publishedPage.slug}}
|
|
||||||
@onChange={{action "checkSlug"}}
|
|
||||||
@onChangeImmediate={{action "startCheckSlug"}}
|
|
||||||
@disabled={{this.existing}}
|
|
||||||
@class="publish-slug"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<label>{{i18n "topic.publish_page.public"}}</label>
|
|
||||||
|
|
||||||
<p class="description">
|
|
||||||
<Input
|
|
||||||
@type="checkbox"
|
|
||||||
@checked={{readonly this.publishedPage.public}}
|
|
||||||
{{on "click" (action "onChangePublic" value="target.checked")}}
|
|
||||||
/>
|
|
||||||
{{i18n "topic.publish_page.public_description"}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="publish-url">
|
|
||||||
<ConditionalLoadingSpinner @condition={{this.checking}} />
|
|
||||||
|
|
||||||
{{#if this.existing}}
|
|
||||||
<div class="current-url">
|
|
||||||
{{i18n "topic.publish_page.publish_url"}}
|
|
||||||
<div>
|
|
||||||
<a
|
|
||||||
href={{this.publishedPage.url}}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>{{this.publishedPage.url}}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
{{#if this.showUrl}}
|
|
||||||
<div class="valid-slug">
|
|
||||||
{{i18n "topic.publish_page.preview_url"}}
|
|
||||||
<div class="example-url">{{this.publishedPage.url}}</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.invalid}}
|
|
||||||
{{i18n "topic.publish_page.invalid_slug"}}
|
|
||||||
<span class="invalid-slug">{{this.reason}}.</span>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</ConditionalLoadingSpinner>
|
|
||||||
{{/if}}
|
|
||||||
</DModalBody>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
{{#if this.showUnpublish}}
|
|
||||||
<DButton
|
|
||||||
@label="topic.publish_page.unpublish"
|
|
||||||
@icon="trash-alt"
|
|
||||||
@class="btn-danger"
|
|
||||||
@isLoading={{this.unpublishing}}
|
|
||||||
@action={{action "unpublish"}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DButton
|
|
||||||
@class="close-publish-page"
|
|
||||||
@icon="times"
|
|
||||||
@label="close"
|
|
||||||
@action={{action "closeModal"}}
|
|
||||||
/>
|
|
||||||
{{else if this.unpublished}}
|
|
||||||
<DButton
|
|
||||||
@label="topic.publish_page.publishing_settings"
|
|
||||||
@action={{action "startNew"}}
|
|
||||||
/>
|
|
||||||
{{else}}
|
|
||||||
<DButton
|
|
||||||
@label="topic.publish_page.publish"
|
|
||||||
@class="btn-primary publish-page"
|
|
||||||
@icon="file"
|
|
||||||
@disabled={{this.disabled}}
|
|
||||||
@isLoading={{this.saving}}
|
|
||||||
@action={{action "publish"}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
Loading…
Reference in New Issue
Block a user