mirror of
https://github.com/discourse/discourse.git
synced 2026-08-01 00:58:31 -05:00
WIP: Additional simplified category improvements (#37338)
* Change the simplified category upcoming change to Experimental so admins can try it out * Delete unused preview-related code for the category UI * Preserve category permissions when switching between public & private access toggle <img width="329" height="245" alt="image" src="https://github.com/user-attachments/assets/729ba0f9-5e1c-4e71-8b4f-8c26d59bae45" /> --------- Co-authored-by: Régis Hanol <regis@hanol.fr>
This commit is contained in:
co-authored by
Régis Hanol
parent
ce66d301ed
commit
d9805c8635
@@ -4236,5 +4236,5 @@ experimental:
|
||||
hidden: true
|
||||
client: true
|
||||
upcoming_change:
|
||||
status: "conceptual"
|
||||
status: "experimental"
|
||||
impact: "feature,staff"
|
||||
|
||||
@@ -11,8 +11,6 @@ import categoryBadge from "discourse/helpers/category-badge";
|
||||
import icon from "discourse/helpers/d-icon";
|
||||
import { uniqueItemsFromArray } from "discourse/lib/array-tools";
|
||||
import { AUTO_GROUPS, CATEGORY_TEXT_COLORS } from "discourse/lib/constants";
|
||||
import discourseDebounce from "discourse/lib/debounce";
|
||||
import { INPUT_DELAY } from "discourse/lib/environment";
|
||||
import getURL from "discourse/lib/get-url";
|
||||
import Category from "discourse/models/category";
|
||||
import PermissionType from "discourse/models/permission-type";
|
||||
@@ -28,13 +26,13 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
|
||||
@tracked categoryVisibilityState = null;
|
||||
@tracked userModifiedPermissions = false;
|
||||
|
||||
uncategorizedSiteSettingLink = getURL(
|
||||
"/admin/site_settings/category/all_results?filter=allow_uncategorized_topics"
|
||||
);
|
||||
customizeTextContentLink = getURL(
|
||||
"/admin/customize/site_texts?q=uncategorized"
|
||||
);
|
||||
#previousPermissions = null;
|
||||
|
||||
get parentIsRestricted() {
|
||||
const parentId = this.args.transientData.parent_category_id;
|
||||
@@ -71,15 +69,27 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
}
|
||||
|
||||
set isPrivateCategory(value) {
|
||||
// Yes, is private
|
||||
if (value) {
|
||||
this.args.category.set("permissions", []);
|
||||
// If the user toggles between private and public we
|
||||
// need to restore whatever previous private permissions were set.
|
||||
if (this.#previousPermissions) {
|
||||
this.#setCategoryPermissions(this.#previousPermissions);
|
||||
} else {
|
||||
this.#setCategoryPermissions([]);
|
||||
}
|
||||
} else {
|
||||
// No, is public
|
||||
this.#previousPermissions = [...this.args.category.permissions];
|
||||
|
||||
const site = this.args.category.site;
|
||||
const everyoneGroup = site.groups.find(
|
||||
(g) => g.id === AUTO_GROUPS.everyone.id
|
||||
);
|
||||
|
||||
this.args.category.set("permissions", [
|
||||
// By default everyone has full permissions for public categories
|
||||
// to see and create posts and topics.
|
||||
this.#setCategoryPermissions([
|
||||
{
|
||||
group_name: everyoneGroup?.name || "everyone",
|
||||
group_id: AUTO_GROUPS.everyone.id,
|
||||
@@ -128,8 +138,7 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
});
|
||||
|
||||
this.userModifiedPermissions = true;
|
||||
this.args.category.set("permissions", newPermissions);
|
||||
this.args.updatePreview?.({});
|
||||
this.#setCategoryPermissions(newPermissions);
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -161,8 +170,7 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
});
|
||||
|
||||
this.userModifiedPermissions = true;
|
||||
this.args.category.set("permissions", newPermissions);
|
||||
this.args.updatePreview?.({});
|
||||
this.#setCategoryPermissions(newPermissions);
|
||||
}
|
||||
|
||||
get allowSubCategoriesAsParent() {
|
||||
@@ -229,7 +237,7 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
}
|
||||
|
||||
@action
|
||||
onVisibilityChange(value) {
|
||||
onChangeVisibility(value) {
|
||||
this.categoryVisibilityState = value;
|
||||
this.userModifiedPermissions = true;
|
||||
if (value === "public") {
|
||||
@@ -237,9 +245,6 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
} else if (value === "group_restricted") {
|
||||
this.isPrivateCategory = true;
|
||||
}
|
||||
|
||||
// Trigger preview update to show restricted status
|
||||
this.args.updatePreview?.({});
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -250,7 +255,7 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
const everyoneGroup = site.groups.find(
|
||||
(g) => g.id === AUTO_GROUPS.everyone.id
|
||||
);
|
||||
this.args.category.set("permissions", [
|
||||
this.#setCategoryPermissions([
|
||||
{
|
||||
group_name: everyoneGroup?.name || "everyone",
|
||||
group_id: AUTO_GROUPS.everyone.id,
|
||||
@@ -279,13 +284,13 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
permission_type: p.permission_type,
|
||||
}));
|
||||
|
||||
this.args.category.set("permissions", newPermissions);
|
||||
this.#setCategoryPermissions(newPermissions);
|
||||
} else {
|
||||
const everyoneGroup = site.groups.find(
|
||||
(g) => g.id === AUTO_GROUPS.everyone.id
|
||||
);
|
||||
|
||||
this.args.category.set("permissions", [
|
||||
this.#setCategoryPermissions([
|
||||
{
|
||||
group_name: everyoneGroup?.name || "everyone",
|
||||
group_id: AUTO_GROUPS.everyone.id,
|
||||
@@ -300,8 +305,6 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
async onParentCategorySet(value, { set, name, index }) {
|
||||
await set(name, value, { index });
|
||||
await this.onParentCategoryChange(value);
|
||||
|
||||
this.args.updatePreview?.({ parent_category_id: value });
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -343,39 +346,27 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
await set("color", color);
|
||||
|
||||
if (color) {
|
||||
const whiteDiff = this.colorDifference(color, CATEGORY_TEXT_COLORS[0]);
|
||||
const blackDiff = this.colorDifference(color, CATEGORY_TEXT_COLORS[1]);
|
||||
const whiteDiff = this.#colorDifference(color, CATEGORY_TEXT_COLORS[0]);
|
||||
const blackDiff = this.#colorDifference(color, CATEGORY_TEXT_COLORS[1]);
|
||||
const colorIndex = whiteDiff > blackDiff ? 0 : 1;
|
||||
|
||||
this.args.form.set("text_color", CATEGORY_TEXT_COLORS[colorIndex]);
|
||||
|
||||
this.args.updatePreview?.({
|
||||
color,
|
||||
text_color: CATEGORY_TEXT_COLORS[colorIndex],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async onNameChange(value, { set, name, index }) {
|
||||
await set(name, value, { index });
|
||||
discourseDebounce(this, this._updateNamePreview, value, INPUT_DELAY);
|
||||
}
|
||||
|
||||
_updateNamePreview(value) {
|
||||
this.args.updatePreview?.({ name: value });
|
||||
}
|
||||
|
||||
@action
|
||||
async onIconSet(value, { set, name, index }) {
|
||||
await set(name, value, { index });
|
||||
this.args.updatePreview?.({ icon: value, style_type: "icon" });
|
||||
}
|
||||
|
||||
@action
|
||||
async onEmojiSet(value, { set, name, index }) {
|
||||
await set(name, value, { index });
|
||||
this.args.updatePreview?.({ emoji: value, style_type: "emoji" });
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -395,24 +386,6 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
} else if (value === "emoji" && currentEmoji) {
|
||||
updateData.emoji = currentEmoji;
|
||||
}
|
||||
|
||||
this.args.updatePreview?.(updateData);
|
||||
}
|
||||
|
||||
colorDifference(color1, color2) {
|
||||
const r1 = parseInt(color1.substr(0, 2), 16);
|
||||
const g1 = parseInt(color1.substr(2, 2), 16);
|
||||
const b1 = parseInt(color1.substr(4, 2), 16);
|
||||
|
||||
const r2 = parseInt(color2.substr(0, 2), 16);
|
||||
const g2 = parseInt(color2.substr(2, 2), 16);
|
||||
const b2 = parseInt(color2.substr(4, 2), 16);
|
||||
|
||||
const rDiff = Math.max(r1, r2) - Math.min(r1, r2);
|
||||
const gDiff = Math.max(g1, g2) - Math.min(g1, g2);
|
||||
const bDiff = Math.max(b1, b2) - Math.min(b1, b2);
|
||||
|
||||
return rDiff + gDiff + bDiff;
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -483,6 +456,26 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
return `edit-category-tab edit-category-tab-general ${isActive}`;
|
||||
}
|
||||
|
||||
#colorDifference(color1, color2) {
|
||||
const r1 = parseInt(color1.substr(0, 2), 16);
|
||||
const g1 = parseInt(color1.substr(2, 2), 16);
|
||||
const b1 = parseInt(color1.substr(4, 2), 16);
|
||||
|
||||
const r2 = parseInt(color2.substr(0, 2), 16);
|
||||
const g2 = parseInt(color2.substr(2, 2), 16);
|
||||
const b2 = parseInt(color2.substr(4, 2), 16);
|
||||
|
||||
const rDiff = Math.max(r1, r2) - Math.min(r1, r2);
|
||||
const gDiff = Math.max(g1, g2) - Math.min(g1, g2);
|
||||
const bDiff = Math.max(b1, b2) - Math.min(b1, b2);
|
||||
|
||||
return rDiff + gDiff + bDiff;
|
||||
}
|
||||
|
||||
#setCategoryPermissions(permissions) {
|
||||
this.args.category.set("permissions", permissions);
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class={{this.panelClass}}>
|
||||
{{#if this.showWarning}}
|
||||
@@ -651,7 +644,7 @@ export default class UpsertCategoryGeneral extends Component {
|
||||
>
|
||||
<@form.ConditionalContent
|
||||
@activeName={{this.categoryVisibility}}
|
||||
@onChange={{this.onVisibilityChange}}
|
||||
@onChange={{this.onChangeVisibility}}
|
||||
as |cc|
|
||||
>
|
||||
<cc.Conditions as |Condition|>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { action, getProperties } from "@ember/object";
|
||||
import { and } from "@ember/object/computed";
|
||||
import { next } from "@ember/runloop";
|
||||
import { service } from "@ember/service";
|
||||
import { TrackedObject } from "@ember-compat/tracked-built-ins";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { AUTO_GROUPS } from "discourse/lib/constants";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
@@ -49,26 +48,6 @@ const FIELD_LIST = [
|
||||
"mailinglist_mirror",
|
||||
];
|
||||
|
||||
const PREVIEW_FIELD_MAP = {
|
||||
name: "previewName",
|
||||
color: "previewColor",
|
||||
text_color: "previewTextColor",
|
||||
style_type: "previewStyleType",
|
||||
emoji: "previewEmoji",
|
||||
icon: "previewIcon",
|
||||
parent_category_id: "previewParentCategoryId",
|
||||
};
|
||||
|
||||
const PREVIEW_DEFAULTS = {
|
||||
previewName: "",
|
||||
previewColor: "",
|
||||
previewTextColor: "",
|
||||
previewStyleType: "",
|
||||
previewEmoji: "",
|
||||
previewIcon: "",
|
||||
previewParentCategoryId: null,
|
||||
};
|
||||
|
||||
const SHOW_ADVANCED_TABS_KEY = "category_edit_show_advanced_tabs";
|
||||
|
||||
export default class EditCategoryTabsController extends Controller {
|
||||
@@ -83,7 +62,6 @@ export default class EditCategoryTabsController extends Controller {
|
||||
showAdvancedTabs =
|
||||
this.keyValueStore.getItem(SHOW_ADVANCED_TABS_KEY) === "true";
|
||||
@tracked selectedTab = "general";
|
||||
@tracked previewData = new TrackedObject(PREVIEW_DEFAULTS);
|
||||
@trackedArray panels = [];
|
||||
saving = false;
|
||||
deleting = false;
|
||||
@@ -135,22 +113,6 @@ export default class EditCategoryTabsController extends Controller {
|
||||
return i18n("category.create");
|
||||
}
|
||||
|
||||
@action
|
||||
updatePreview(data) {
|
||||
Object.entries(PREVIEW_FIELD_MAP).forEach(([key, previewField]) => {
|
||||
if (data[key] !== undefined) {
|
||||
this.previewData[previewField] = data[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
resetPreview() {
|
||||
Object.entries(PREVIEW_DEFAULTS).forEach(([key, value]) => {
|
||||
this.previewData[key] = value;
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
setSelectedTab(tab) {
|
||||
this.selectedTab = tab;
|
||||
|
||||
@@ -17,7 +17,5 @@ export default class EditCategoryTabs extends DiscourseRoute {
|
||||
});
|
||||
|
||||
controller.setSelectedTab(selectedTab);
|
||||
|
||||
controller.resetPreview();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@ export default class NewCategory extends DiscourseRoute {
|
||||
setupController(controller) {
|
||||
super.setupController(...arguments);
|
||||
|
||||
controller.resetPreview();
|
||||
controller.selectedTab = "general";
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@ export default <template>
|
||||
@registerValidator={{@controller.registerValidator}}
|
||||
@transientData={{transientData}}
|
||||
@form={{form}}
|
||||
@updatePreview={{@controller.updatePreview}}
|
||||
@setSelectedTab={{@controller.setSelectedTab}}
|
||||
/>
|
||||
{{/let}}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 48 KiB |
Reference in New Issue
Block a user