DEV: convert grant badge modal to component API (#23378)
* DEV: convert grant-badge to use component modal API * DEV: add system test for grant badge modal happy path
This commit is contained in:
parent
29439af375
commit
d28f113ce0
|
@ -0,0 +1,34 @@
|
|||
<DModal
|
||||
@bodyClass="grant-badge"
|
||||
@closeModal={{@closeModal}}
|
||||
@flash={{this.flash}}
|
||||
@flashType={{this.flashType}}
|
||||
@title={{i18n "admin.badges.grant_badge"}}
|
||||
class="grant-badge-modal"
|
||||
{{did-insert this.loadBadges}}
|
||||
>
|
||||
<:body>
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
||||
{{#if this.noGrantableBadges}}
|
||||
<p>{{i18n "admin.badges.no_badges"}}</p>
|
||||
{{else}}
|
||||
<p>
|
||||
<ComboBox
|
||||
@value={{this.selectedBadgeId}}
|
||||
@content={{this.grantableBadges}}
|
||||
@onChange={{action (mut this.selectedBadgeId)}}
|
||||
@options={{hash filterable=true none="badges.none"}}
|
||||
/>
|
||||
</p>
|
||||
{{/if}}
|
||||
</ConditionalLoadingSpinner>
|
||||
</:body>
|
||||
<:footer>
|
||||
<DButton
|
||||
@disabled={{this.buttonDisabled}}
|
||||
@action={{this.performGrantBadge}}
|
||||
@label="admin.badges.grant"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</:footer>
|
||||
</DModal>
|
|
@ -0,0 +1,80 @@
|
|||
import { action } from "@ember/object";
|
||||
import Component from "@ember/component";
|
||||
import Badge from "discourse/models/badge";
|
||||
import GrantBadgeController from "discourse/mixins/grant-badge-controller";
|
||||
import I18n from "I18n";
|
||||
import UserBadge from "discourse/models/user-badge";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { extractError } from "discourse/lib/ajax-error";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
|
||||
export default class GrantBadgeModal extends Component.extend(
|
||||
GrantBadgeController
|
||||
) {
|
||||
loading = true;
|
||||
saving = false;
|
||||
selectedBadgeId = null;
|
||||
flash = null;
|
||||
flashType = null;
|
||||
allBadges = [];
|
||||
userBadges = [];
|
||||
|
||||
@discourseComputed("model.selectedPost")
|
||||
post() {
|
||||
return this.get("model.selectedPost");
|
||||
}
|
||||
|
||||
@discourseComputed("saving", "selectedBadgeGrantable")
|
||||
buttonDisabled(saving, selectedBadgeGrantable) {
|
||||
return saving || !selectedBadgeGrantable;
|
||||
}
|
||||
|
||||
@action
|
||||
async loadBadges() {
|
||||
this.set("loading", true);
|
||||
try {
|
||||
const allBadges = await Badge.findAll();
|
||||
const userBadges = await UserBadge.findByUsername(
|
||||
this.get("post.username")
|
||||
);
|
||||
this.setProperties({
|
||||
allBadges,
|
||||
userBadges,
|
||||
});
|
||||
} catch (e) {
|
||||
this.setProperties({
|
||||
flash: extractError(e),
|
||||
flashType: "error",
|
||||
});
|
||||
} finally {
|
||||
this.set("loading", false);
|
||||
}
|
||||
}
|
||||
@action
|
||||
async performGrantBadge() {
|
||||
try {
|
||||
this.set("saving", true);
|
||||
const username = this.get("post.username");
|
||||
const newBadge = await this.grantBadge(
|
||||
this.selectedBadgeId,
|
||||
username,
|
||||
getURL(this.get("post.url"))
|
||||
);
|
||||
this.set("selectedBadgeId", null);
|
||||
this.setProperties({
|
||||
flash: I18n.t("badges.successfully_granted", {
|
||||
username,
|
||||
badge: newBadge.get("badge.name"),
|
||||
}),
|
||||
flashType: "success",
|
||||
});
|
||||
} catch (e) {
|
||||
this.setProperties({
|
||||
flash: extractError(e),
|
||||
flashType: "error",
|
||||
});
|
||||
} finally {
|
||||
this.set("saving", false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import Badge from "discourse/models/badge";
|
||||
import GrantBadgeController from "discourse/mixins/grant-badge-controller";
|
||||
import I18n from "I18n";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import UserBadge from "discourse/models/user-badge";
|
||||
import { all } from "rsvp";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { flashAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, GrantBadgeController, {
|
||||
topicController: controller("topic"),
|
||||
loading: true,
|
||||
saving: false,
|
||||
selectedBadgeId: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.allBadges = [];
|
||||
this.userBadges = [];
|
||||
},
|
||||
|
||||
@discourseComputed("topicController.selectedPosts")
|
||||
post() {
|
||||
return this.get("topicController.selectedPosts")[0];
|
||||
},
|
||||
|
||||
@discourseComputed("post")
|
||||
badgeReason(post) {
|
||||
const url = post.get("url");
|
||||
const protocolAndHost =
|
||||
window.location.protocol + "//" + window.location.host;
|
||||
|
||||
return url.startsWith("/") ? protocolAndHost + url : url;
|
||||
},
|
||||
|
||||
@discourseComputed("saving", "selectedBadgeGrantable")
|
||||
buttonDisabled(saving, selectedBadgeGrantable) {
|
||||
return saving || !selectedBadgeGrantable;
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.set("loading", true);
|
||||
|
||||
all([
|
||||
Badge.findAll(),
|
||||
UserBadge.findByUsername(this.get("post.username")),
|
||||
]).then(([allBadges, userBadges]) => {
|
||||
this.setProperties({
|
||||
allBadges,
|
||||
userBadges,
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
grantBadge() {
|
||||
this.set("saving", true);
|
||||
|
||||
this.grantBadge(
|
||||
this.selectedBadgeId,
|
||||
this.get("post.username"),
|
||||
this.badgeReason
|
||||
)
|
||||
.then((newBadge) => {
|
||||
this.set("selectedBadgeId", null);
|
||||
this.flash(
|
||||
I18n.t("badges.successfully_granted", {
|
||||
username: this.get("post.username"),
|
||||
badge: newBadge.get("badge.name"),
|
||||
}),
|
||||
"success"
|
||||
);
|
||||
}, flashAjaxError(this))
|
||||
.finally(() => this.set("saving", false));
|
||||
},
|
||||
},
|
||||
});
|
|
@ -17,6 +17,7 @@ import ChangeTimestampModal from "discourse/components/modal/change-timestamp";
|
|||
import EditTopicTimerModal from "discourse/components/modal/edit-topic-timer";
|
||||
import FeatureTopicModal from "discourse/components/modal/feature-topic";
|
||||
import FlagModal from "discourse/components/modal/flag";
|
||||
import GrantBadgeModal from "discourse/components/modal/grant-badge";
|
||||
import MoveToTopicModal from "discourse/components/modal/move-to-topic";
|
||||
import RawEmailModal from "discourse/components/modal/raw-email";
|
||||
|
||||
|
@ -200,9 +201,11 @@ const TopicRoute = DiscourseRoute.extend({
|
|||
|
||||
@action
|
||||
showGrantBadgeModal() {
|
||||
showModal("grant-badge", {
|
||||
model: this.modelFor("topic"),
|
||||
title: "admin.badges.grant_badge",
|
||||
const topicController = this.controllerFor("topic");
|
||||
this.modal.show(GrantBadgeModal, {
|
||||
model: {
|
||||
selectedPost: topicController.selectedPosts[0],
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<DModalBody @class="grant-badge">
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
||||
{{#if this.noGrantableBadges}}
|
||||
<p>{{i18n "admin.badges.no_badges"}}</p>
|
||||
{{else}}
|
||||
<p>
|
||||
<ComboBox
|
||||
@value={{this.selectedBadgeId}}
|
||||
@content={{this.grantableBadges}}
|
||||
@onChange={{action (mut this.selectedBadgeId)}}
|
||||
@options={{hash filterable=true none="badges.none"}}
|
||||
/>
|
||||
</p>
|
||||
{{/if}}
|
||||
</ConditionalLoadingSpinner>
|
||||
</DModalBody>
|
||||
|
||||
<div class="modal-footer">
|
||||
<DButton
|
||||
@disabled={{this.buttonDisabled}}
|
||||
@action={{action "grantBadge"}}
|
||||
@label="admin.badges.grant"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</div>
|
|
@ -6,3 +6,8 @@ Fabricator(:badge) do
|
|||
name { sequence(:name) { |i| "Badge #{i}" } }
|
||||
badge_type
|
||||
end
|
||||
|
||||
Fabricator(:manually_grantable_badge, from: :badge) do
|
||||
system false
|
||||
query nil
|
||||
end
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe "Granting Badges", type: :system do
|
||||
before { SiteSetting.enable_badges = true }
|
||||
|
||||
context "when in topic" do
|
||||
fab!(:post) { Fabricate(:post, raw: "This is some post to bookmark") }
|
||||
fab!(:admin) { Fabricate(:admin) }
|
||||
fab!(:badge_to_grant) { Fabricate(:manually_grantable_badge) }
|
||||
fab!(:other_badge) { Fabricate(:manually_grantable_badge) }
|
||||
let(:user) { post.user }
|
||||
let(:topic) { post.topic }
|
||||
let(:topic_page) { PageObjects::Pages::Topic.new }
|
||||
let(:badge_modal) { PageObjects::Modals::Badge.new }
|
||||
|
||||
before { sign_in(admin) }
|
||||
|
||||
def visit_topic_and_open_badge_modal(post)
|
||||
topic_page.visit_topic(topic)
|
||||
topic_page.expand_post_actions(post)
|
||||
topic_page.expand_post_admin_actions(post)
|
||||
topic_page.click_post_admin_action_button(post, :grant_badge)
|
||||
end
|
||||
|
||||
it "grants badge with the correct badge reason which links the right post" do
|
||||
visit_topic_and_open_badge_modal(post)
|
||||
badge_modal.select_badge(badge_to_grant.name)
|
||||
badge_modal.grant
|
||||
|
||||
expect(badge_modal).to have_success_flash_visible
|
||||
granted_badge = UserBadge.last
|
||||
expect(granted_badge.badge_id).to eq badge_to_grant.id
|
||||
expect(granted_badge.post_id).to eq post.id
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Modals
|
||||
class Badge < PageObjects::Pages::Base
|
||||
GRANTABLE_BADGES_DROPDOWN = ".select-kit"
|
||||
|
||||
def modal
|
||||
find(".grant-badge-modal")
|
||||
end
|
||||
def select_badge(badge_name)
|
||||
within(modal) do
|
||||
grantable_badges_dropdown.expand
|
||||
grantable_badges_dropdown.select_row_by_name(badge_name)
|
||||
end
|
||||
end
|
||||
|
||||
def grant
|
||||
within(modal) { find(".modal-footer .btn").click }
|
||||
end
|
||||
|
||||
def has_success_flash_visible?
|
||||
within(modal) { has_css?(".alert-success") }
|
||||
end
|
||||
|
||||
def grantable_badges_dropdown
|
||||
@grantable_badges_dropdown ||=
|
||||
PageObjects::Components::SelectKit.new(GRANTABLE_BADGES_DROPDOWN)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -87,6 +87,19 @@ module PageObjects
|
|||
end
|
||||
end
|
||||
|
||||
def expand_post_admin_actions(post)
|
||||
post_by_number(post).find(".show-post-admin-menu").click
|
||||
end
|
||||
|
||||
def click_post_admin_action_button(post, button)
|
||||
element_klass = ".popup-menu-button"
|
||||
case button
|
||||
when :grant_badge
|
||||
element_klass += ".grant-badge"
|
||||
end
|
||||
post_by_number(post).find(element_klass).click
|
||||
end
|
||||
|
||||
def click_topic_footer_button(button)
|
||||
find_topic_footer_button(button).click
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue