Merge branch 'main' into ux/automatically-mobile-buttons-admin-header

This commit is contained in:
Martin Brennan 2024-10-02 13:20:30 +10:00
commit ef89dbadb2
No known key found for this signature in database
GPG Key ID: BD981EFEEC8F5675
29 changed files with 606 additions and 627 deletions

View File

@ -135,7 +135,7 @@ GEM
dry-initializer (3.1.1)
email_reply_trimmer (0.1.13)
erubi (1.13.0)
excon (0.111.0)
excon (0.112.0)
execjs (2.9.1)
exifr (1.4.0)
extralite-bundle (2.8.2)
@ -480,7 +480,7 @@ GEM
rack (>= 1.1)
rubocop (>= 1.52.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rspec (3.0.5)
rubocop-rspec (3.1.0)
rubocop (~> 1.61)
rubocop-rspec_rails (2.30.0)
rubocop (~> 1.61)

View File

@ -0,0 +1,77 @@
import Component from "@glimmer/component";
import { hash } from "@ember/helper";
import { LinkTo } from "@ember/routing";
import concatClass from "discourse/helpers/concat-class";
import dIcon from "discourse-common/helpers/d-icon";
import i18n from "discourse-common/helpers/i18n";
import {
DangerButton,
DefaultButton,
PrimaryButton,
} from "admin/components/admin-page-action-button";
export default class AdminSectionLandingItem extends Component {
get title() {
if (this.args.titleLabelTranslated) {
return this.args.titleLabelTranslated;
} else if (this.args.titleLabel) {
return i18n(this.args.titleLabel);
}
}
get description() {
if (this.args.descriptionLabelTranslated) {
return this.args.descriptionLabelTranslated;
} else if (this.args.descriptionLabel) {
return i18n(this.args.descriptionLabel);
}
}
get tagline() {
if (this.args.taglineLabelTranslated) {
return this.args.taglineLabelTranslated;
} else if (this.args.taglineLabel) {
return i18n(this.args.taglineLabel);
}
}
<template>
<div
class={{concatClass "admin-section-landing-item" (if @icon "-has-icon")}}
...attributes
>
{{#if @imageUrl}}
<img class="admin-section-landing-item__image" src={{@imageUrl}} />
{{/if}}
{{#if @icon}}
<div class="admin-section-landing-item__icon">
{{dIcon @icon}}
</div>
{{/if}}
<div class="admin-section-landing-item__content">
{{#if this.tagline}}
<h4 class="admin-section-landing-item__tagline">{{this.tagline}}</h4>
{{/if}}
{{#if @titleRoute}}
<LinkTo @route={{@titleRoute}}><h3
class="admin-section-landing-item__title"
>{{this.title}}</h3></LinkTo>
{{else}}
<h3 class="admin-section-landing-item__title">{{this.title}}</h3>
{{/if}}
<p
class="admin-section-landing-item__description"
>{{this.description}}</p>
</div>
<div class="admin-section-landing-item__buttons">
{{yield
(hash Primary=PrimaryButton Default=DefaultButton Danger=DangerButton)
to="buttons"
}}
</div>
</div>
</template>
}

View File

@ -0,0 +1,7 @@
const AdminSectionLandingWrapper = <template>
<div class="admin-section-landing-wrapper" ...attributes>
{{yield}}
</div>
</template>;
export default AdminSectionLandingWrapper;

View File

@ -236,5 +236,13 @@ export default function () {
path: "/whats-new",
resetNamespace: true,
});
this.route(
"adminSection",
{ path: "/section", resetNamespace: true },
function () {
this.route("account");
}
);
});
}

View File

@ -0,0 +1,26 @@
<AdminPageHeader
@titleLabel="admin.section_landing_pages.account.title"
@hideTabs={{true}}
>
<:breadcrumbs>
<DBreadcrumbsItem
@path="/admin/section/account"
@label={{i18n "admin.section_landing_pages.account.title"}}
/>
</:breadcrumbs>
</AdminPageHeader>
<AdminSectionLandingWrapper>
<AdminSectionLandingItem
@icon="box-archive"
@titleLabel="admin.section_landing_pages.account.backups.title"
@descriptionLabel="admin.section_landing_pages.account.backups.description"
@titleRoute="admin.backups"
/>
<AdminSectionLandingItem
@icon="gift"
@titleLabel="admin.section_landing_pages.account.whats_new.title"
@descriptionLabel="admin.section_landing_pages.account.whats_new.description"
@titleRoute="admin.whatsNew"
/>
</AdminSectionLandingWrapper>

View File

@ -29,7 +29,7 @@
"@types/qunit": "^2.19.10",
"@types/rsvp": "^4.0.9",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~5.11.0",
"ember-cli": "~5.12.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@ -38,7 +38,7 @@
"@types/qunit": "^2.19.10",
"@types/rsvp": "^4.0.9",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~5.11.0",
"ember-cli": "~5.12.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@ -18,7 +18,7 @@
"ember-this-fallback": "^0.4.0"
},
"devDependencies": {
"ember-cli": "~5.11.0",
"ember-cli": "~5.12.0",
"webpack": "^5.95.0"
},
"engines": {

View File

@ -26,7 +26,7 @@
"@glimmer/component": "^1.1.2",
"@glimmer/syntax": "^0.92.3",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~5.11.0",
"ember-cli": "~5.12.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@ -49,7 +49,7 @@ export default class ReviewableItem extends Component {
@service siteSettings;
@service currentUser;
@service composer;
@optionalService("admin-tools") adminTools;
@optionalService adminTools;
updating = null;
editing = false;

View File

@ -2,7 +2,6 @@ import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import { service } from "@ember/service";
import optionalService from "discourse/lib/optional-service";
import { bind } from "discourse-common/utils/decorators";
export default class TopicTimeline extends Component {
@ -13,8 +12,6 @@ export default class TopicTimeline extends Component {
@tracked docked = false;
@tracked dockedBottom = false;
adminTools = optionalService();
constructor() {
super(...arguments);

View File

@ -15,7 +15,7 @@ export default class UserController extends Controller.extend(CanCheckEmails) {
@service currentUser;
@service router;
@service dialog;
@optionalService("admin-tools") adminTools;
@optionalService adminTools;
@controller("user-notifications") userNotifications;

View File

@ -2,8 +2,16 @@ import { computed } from "@ember/object";
import { getOwner } from "@ember/owner";
import { dasherize } from "@ember/string";
export default function (name) {
return computed(function (defaultName) {
export default function (target, name, descriptor) {
name ??= target;
const decorator = computed(function (defaultName) {
return getOwner(this).lookup(`service:${name || dasherize(defaultName)}`);
});
if (descriptor) {
return decorator(target, name, descriptor);
} else {
return decorator;
}
}

View File

@ -47,11 +47,11 @@
"@ember/string": "^4.0.0",
"@ember/test-helpers": "^4.0.4",
"@ember/test-waiters": "^3.1.0",
"@embroider/compat": "^3.6.1",
"@embroider/core": "^3.4.16",
"@embroider/macros": "^1.13.1",
"@embroider/compat": "^3.6.2",
"@embroider/core": "^3.4.17",
"@embroider/macros": "^1.16.7",
"@embroider/router": "^2.1.8",
"@embroider/webpack": "^4.0.5",
"@embroider/webpack": "^4.0.6",
"@floating-ui/dom": "^1.6.11",
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
@ -84,7 +84,7 @@
"ember-auto-import": "^2.8.1",
"ember-buffered-proxy": "^2.1.1",
"ember-cached-decorator-polyfill": "^1.0.2",
"ember-cli": "~5.11.0",
"ember-cli": "~5.12.0",
"ember-cli-app-version": "^7.0.0",
"ember-cli-babel": "^8.2.0",
"ember-cli-deprecation-workflow": "^3.0.2",

View File

@ -0,0 +1,59 @@
import Component from "@ember/component";
import Service from "@ember/service";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import optionalService from "discourse/lib/optional-service";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
class FooService extends Service {
name = "foo";
}
class BarService extends Service {
name = "bar";
}
const EmberObjectComponent = Component.extend({
name: "",
layout: hbs`<span class="ember-object-component">{{this.foo.name}} {{this.baz.name}}</span>`,
foo: optionalService(),
baz: optionalService("bar"),
});
class NativeComponent extends Component {
@optionalService foo;
@optionalService("bar") baz;
name = "";
layout = hbs`<span class="native-component">{{this.foo.name}} {{this.baz.name}}</span>`;
}
module("Unit | Utils | optional-service", function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () {
this.registry.register("service:foo", FooService);
this.registry.register("service:bar", BarService);
});
test("optionalService works in EmberObject classes", async function (assert) {
this.registry.register(
"component:ember-object-component",
EmberObjectComponent
);
await render(hbs`<EmberObjectComponent />`);
assert.dom(".ember-object-component").hasText("foo bar");
});
test("optionalService works in native classes", async function (assert) {
this.registry.register("component:native-component", NativeComponent);
await render(hbs`<NativeComponent />`);
assert.dom(".native-component").hasText("foo bar");
});
});

View File

@ -29,7 +29,7 @@
"@types/qunit": "^2.19.10",
"@types/rsvp": "^4.0.9",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~5.11.0",
"ember-cli": "~5.12.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@ -30,7 +30,7 @@
"@types/qunit": "^2.19.10",
"@types/rsvp": "^4.0.9",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~5.11.0",
"ember-cli": "~5.12.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@ -30,7 +30,7 @@
"@types/qunit": "^2.19.10",
"@types/rsvp": "^4.0.9",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~5.11.0",
"ember-cli": "~5.12.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@ -1094,6 +1094,7 @@ a.inline-editable-field {
@import "common/admin/admin_report_stacked_line_chart";
@import "common/admin/admin_report_table";
@import "common/admin/admin_report_inline_table";
@import "common/admin/admin_section_landing_page";
@import "common/admin/admin_page_header";
@import "common/admin/admin_intro";
@import "common/admin/admin_emojis";

View File

@ -0,0 +1,71 @@
.admin-section-landing-wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(16em, 1fr));
gap: 1em 2em;
margin-top: 1em;
padding-top: 1em;
.admin-section-landing-item {
display: grid;
grid-template-rows: subgrid;
grid-template-columns: 1fr;
grid-row: span 2;
gap: 0;
margin-bottom: 2em;
@include breakpoint("mobile-extra-large", min-width) {
margin-bottom: 2em;
}
&.-has-icon {
grid-template-columns: 1fr 8fr;
.admin-section-landing-item__buttons {
grid-column: 2;
}
}
&__content {
grid-row: 1;
}
&__tagline {
font-size: var(--font-down-1);
font-weight: normal;
color: var(--primary-high);
margin: 0;
letter-spacing: 0.1px;
}
&__title {
margin: 0;
line-height: var(--line-height-medium);
}
&__description {
color: var(--primary-high);
margin: 0.25em 0 0.5em;
line-height: var(--line-height-large);
align-self: start;
@include breakpoint("mobile-extra-large", min-width) {
max-width: 17em;
}
}
&__icon {
font-size: var(--font-up-3);
color: var(--primary-low-mid);
grid-row: 1;
}
&__buttons {
grid-row: 2;
grid-column: 1;
}
button {
justify-self: start;
}
}
}

View File

@ -0,0 +1,6 @@
# frozen_string_literal: true
class Admin::SectionController < Admin::AdminController
def show
end
end

View File

@ -5563,6 +5563,16 @@ en:
spam: "Spam settings"
staff_action_logs: "Staff Action Logs"
section_landing_pages:
account:
title: "Account"
backups:
title: "Backups"
description: "Take a backup of your site's data"
whats_new:
title: "What's New"
description: "Discover new releases and improvements to Discourse"
config_areas:
about:
header: "About your site"

View File

@ -403,6 +403,7 @@ Discourse::Application.routes.draw do
end
end
get "section/:section_id" => "section#show", :constraints => AdminConstraint.new
resources :admin_notices, only: %i[destroy], constraints: AdminConstraint.new
end # admin namespace

View File

@ -39,7 +39,7 @@ module CategoryGuardian
def can_see_category?(category)
return false unless category
return true if is_admin?
return true if is_admin? && !SiteSetting.suppress_secured_categories_from_admin
return true if !category.read_restricted
return true if is_staged? && category.email_in.present? && category.email_in_allow_strangers
secure_category_ids.include?(category.id)

View File

@ -224,7 +224,7 @@ module TopicGuardian
def can_see_topic_ids(topic_ids: [], hide_deleted: true)
topic_ids = topic_ids.compact
return topic_ids if is_admin?
return topic_ids if is_admin? && !SiteSetting.suppress_secured_categories_from_admin
return [] if topic_ids.blank?
default_scope = Topic.unscoped.where(id: topic_ids)
@ -268,7 +268,7 @@ module TopicGuardian
def can_see_topic?(topic, hide_deleted = true)
return false unless topic
return true if is_admin?
return true if is_admin? && !SiteSetting.suppress_secured_categories_from_admin
return false if hide_deleted && topic.deleted_at && !can_see_deleted_topics?(topic.category)
if topic.private_message?

View File

@ -26,9 +26,9 @@
"jsdoc": "^4.0.0",
"lefthook": "^1.7.18",
"licensee": "^11.1.0",
"lint-to-the-future": "^2.0.0",
"lint-to-the-future": "^2.1.0",
"lint-to-the-future-ember-template": "^1.1.1",
"lint-to-the-future-eslint": "^2.0.1",
"lint-to-the-future-eslint": "^2.1.2",
"magnific-popup": "1.1.0",
"moment": "2.30.1",
"moment-timezone": "0.5.45",

View File

@ -14,7 +14,6 @@ import { modifier } from "ember-modifier";
import { eq, not } from "truth-helpers";
import DButton from "discourse/components/d-button";
import concatClass from "discourse/helpers/concat-class";
import optionalService from "discourse/lib/optional-service";
import { applyValueTransformer } from "discourse/lib/transformer";
import { updateUserStatusOnMention } from "discourse/lib/update-user-status-on-mention";
import isZoomed from "discourse/lib/zoom-check";
@ -65,7 +64,6 @@ export default class ChatMessage extends Component {
@service router;
@service toasts;
@service modal;
@optionalService adminTools;
@tracked isActive = false;

File diff suppressed because it is too large Load Diff

View File

@ -291,6 +291,8 @@ RSpec.describe TopicGuardian do
list = guardian.filter_allowed_categories(list)
expect(list.count).to eq(0)
expect(guardian.can_see?(private_topic)).to eq(false)
end
end
end