mirror of
https://github.com/discourse/discourse.git
synced 2025-06-07 11:54:44 +08:00
DEV: Convert auth-token
modal to component-based API (#23251)
<img width="744" alt="Screenshot 2023-08-24 at 6 41 15 PM" src="https://github.com/discourse/discourse/assets/50783505/a5df1a15-fbb0-43a9-acce-742ef484d70a">
This commit is contained in:
@ -0,0 +1,51 @@
|
|||||||
|
<DModal
|
||||||
|
@title={{i18n "user.auth_tokens.was_this_you"}}
|
||||||
|
@closeModal={{@closeModal}}
|
||||||
|
>
|
||||||
|
<:body>
|
||||||
|
<div>
|
||||||
|
<p>{{i18n "user.auth_tokens.was_this_you_description"}}</p>
|
||||||
|
<p>{{html-safe (i18n "user.second_factor.extended_description")}}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>{{i18n "user.auth_tokens.details"}}</h3>
|
||||||
|
<ul>
|
||||||
|
<li>{{d-icon "far-clock"}} {{format-date @model.seen_at}}</li>
|
||||||
|
<li>{{d-icon "map-marker-alt"}} {{@model.location}}</li>
|
||||||
|
<li>{{d-icon @model.icon}}
|
||||||
|
{{i18n
|
||||||
|
"user.auth_tokens.browser_and_device"
|
||||||
|
browser=@model.browser
|
||||||
|
device=@model.device
|
||||||
|
}}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if this.latestPost}}
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
{{i18n "user.auth_tokens.latest_post"}}
|
||||||
|
{{! when this.fetchActivity is called, the modal focus is reset }}
|
||||||
|
{{! allowing you to tab behind the modal, so we need to refocus }}
|
||||||
|
<a href {{on "click" this.toggleExpanded}} {{auto-focus}}>
|
||||||
|
{{d-icon (if this.expanded "caret-up" "caret-down")}}
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
{{#if this.expanded}}
|
||||||
|
<blockquote>{{html-safe this.latestPost.cooked}}</blockquote>
|
||||||
|
{{else}}
|
||||||
|
<blockquote>{{html-safe this.latestPost.excerpt}}</blockquote>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</:body>
|
||||||
|
<:footer>
|
||||||
|
<DButton
|
||||||
|
class="btn-primary"
|
||||||
|
@action={{@closeModal}}
|
||||||
|
@icon="lock"
|
||||||
|
@label="user.auth_tokens.secure_account"
|
||||||
|
/>
|
||||||
|
<DModalCancel @close={{@closeModal}} />
|
||||||
|
</:footer>
|
||||||
|
</DModal>
|
@ -0,0 +1,34 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { userPath } from "discourse/lib/url";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
|
||||||
|
export default class AuthTokenComponent extends Component {
|
||||||
|
@service currentUser;
|
||||||
|
|
||||||
|
@tracked expanded = false;
|
||||||
|
@tracked latestPost = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
this.fetchActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async fetchActivity() {
|
||||||
|
const posts = await ajax(
|
||||||
|
userPath(`${this.currentUser.username_lower}/activity.json`)
|
||||||
|
);
|
||||||
|
if (posts.length > 0) {
|
||||||
|
this.latestPost = posts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleExpanded(event) {
|
||||||
|
event?.preventDefault();
|
||||||
|
this.expanded = !this.expanded;
|
||||||
|
}
|
||||||
|
}
|
@ -1,48 +0,0 @@
|
|||||||
import Controller from "@ember/controller";
|
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
|
||||||
import { ajax } from "discourse/lib/ajax";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { next } from "@ember/runloop";
|
|
||||||
import { userPath } from "discourse/lib/url";
|
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
|
||||||
expanded: false,
|
|
||||||
|
|
||||||
onShow() {
|
|
||||||
ajax(
|
|
||||||
userPath(`${this.get("currentUser.username_lower")}/activity.json`)
|
|
||||||
).then((posts) => {
|
|
||||||
if (posts.length > 0) {
|
|
||||||
this.set("latest_post", posts[0]);
|
|
||||||
// slightly hacky, but default d-modal focus gets reset
|
|
||||||
document.querySelector(".d-modal .modal-close")?.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
toggleExpanded(event) {
|
|
||||||
event?.preventDefault();
|
|
||||||
this.set("expanded", !this.expanded);
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
highlightSecure() {
|
|
||||||
this.send("closeModal");
|
|
||||||
|
|
||||||
next(() => {
|
|
||||||
const $prefPasswordDiv = $(".pref-password");
|
|
||||||
|
|
||||||
$prefPasswordDiv.addClass("highlighted");
|
|
||||||
$prefPasswordDiv.on("animationend", () =>
|
|
||||||
$prefPasswordDiv.removeClass("highlighted")
|
|
||||||
);
|
|
||||||
|
|
||||||
window.scrollTo({
|
|
||||||
top: $prefPasswordDiv.offset().top,
|
|
||||||
behavior: "smooth",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
@ -5,15 +5,17 @@ import discourseComputed from "discourse-common/utils/decorators";
|
|||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import logout from "discourse/lib/logout";
|
import logout from "discourse/lib/logout";
|
||||||
import showModal from "discourse/lib/show-modal";
|
|
||||||
import { userPath } from "discourse/lib/url";
|
import { userPath } from "discourse/lib/url";
|
||||||
import CanCheckEmails from "discourse/mixins/can-check-emails";
|
import CanCheckEmails from "discourse/mixins/can-check-emails";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import AuthTokenModal from "discourse/components/modal/auth-token";
|
||||||
|
|
||||||
// Number of tokens shown by default.
|
// Number of tokens shown by default.
|
||||||
const DEFAULT_AUTH_TOKENS_COUNT = 2;
|
const DEFAULT_AUTH_TOKENS_COUNT = 2;
|
||||||
|
|
||||||
export default Controller.extend(CanCheckEmails, {
|
export default Controller.extend(CanCheckEmails, {
|
||||||
|
modal: service(),
|
||||||
passwordProgress: null,
|
passwordProgress: null,
|
||||||
subpageTitle: I18n.t("user.preferences_nav.security"),
|
subpageTitle: I18n.t("user.preferences_nav.security"),
|
||||||
showAllAuthTokens: false,
|
showAllAuthTokens: false,
|
||||||
@ -112,7 +114,7 @@ export default Controller.extend(CanCheckEmails, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
showToken(token) {
|
showToken(token) {
|
||||||
showModal("auth-token", { model: token });
|
this.modal.show(AuthTokenModal, { model: token });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,6 @@ import deprecated from "discourse-common/lib/deprecated";
|
|||||||
// don't cause unnecessary noise.
|
// don't cause unnecessary noise.
|
||||||
const KNOWN_LEGACY_MODALS = [
|
const KNOWN_LEGACY_MODALS = [
|
||||||
"associate-account-confirm",
|
"associate-account-confirm",
|
||||||
"auth-token",
|
|
||||||
"avatar-selector",
|
"avatar-selector",
|
||||||
"change-owner",
|
"change-owner",
|
||||||
"change-post-notice",
|
"change-post-notice",
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
<DModalBody @title="user.auth_tokens.was_this_you">
|
|
||||||
<div>
|
|
||||||
<p>{{i18n "user.auth_tokens.was_this_you_description"}}</p>
|
|
||||||
<p>{{html-safe (i18n "user.second_factor.extended_description")}}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h3>{{i18n "user.auth_tokens.details"}}</h3>
|
|
||||||
<ul style="list-style-type:none">
|
|
||||||
<li>{{d-icon "far-clock"}} {{format-date this.model.seen_at}}</li>
|
|
||||||
<li>{{d-icon "map-marker-alt"}} {{this.model.location}}</li>
|
|
||||||
<li>{{d-icon this.model.icon}}
|
|
||||||
{{i18n
|
|
||||||
"user.auth_tokens.browser_and_device"
|
|
||||||
browser=this.model.browser
|
|
||||||
device=this.model.device
|
|
||||||
}}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if this.latest_post}}
|
|
||||||
<div>
|
|
||||||
<h3>
|
|
||||||
{{i18n "user.auth_tokens.latest_post"}}
|
|
||||||
<a href {{on "click" this.toggleExpanded}}>{{d-icon
|
|
||||||
(if this.expanded "caret-up" "caret-down")
|
|
||||||
}}</a>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{{#if this.expanded}}
|
|
||||||
<blockquote>{{html-safe this.latest_post.cooked}}</blockquote>
|
|
||||||
{{else}}
|
|
||||||
<blockquote>{{html-safe this.latest_post.excerpt}}</blockquote>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</DModalBody>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<DButton
|
|
||||||
@class="btn-primary"
|
|
||||||
@action={{action "highlightSecure"}}
|
|
||||||
@icon="lock"
|
|
||||||
@label="user.auth_tokens.secure_account"
|
|
||||||
/>
|
|
||||||
<DModalCancel @close={{route-action "closeModal"}} />
|
|
||||||
</div>
|
|
@ -54,14 +54,6 @@ acceptance("User Preferences - Security", function (needs) {
|
|||||||
await authTokenDropdown.selectRowByValue("notYou");
|
await authTokenDropdown.selectRowByValue("notYou");
|
||||||
|
|
||||||
assert.strictEqual(count(".d-modal:visible"), 1, "modal should appear");
|
assert.strictEqual(count(".d-modal:visible"), 1, "modal should appear");
|
||||||
|
|
||||||
await click(".modal-footer .btn-primary");
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
count(".pref-password.highlighted"),
|
|
||||||
1,
|
|
||||||
"it should highlight password preferences"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Viewing user api keys", async function (assert) {
|
test("Viewing user api keys", async function (assert) {
|
||||||
|
Reference in New Issue
Block a user