Skip to content

Commit 1340edd

Browse files
AntoineJTclaude
andcommitted
fix(config): mark every unset field as default, including empty lists
The /config "default" marker keyed on isDefault, which was true only for an unset field that *declares* a defaultValue — so an unset list with no default (e.g. thread-creator's channels) showed "—" with no marker. Key it on !isSet instead: any field the admin hasn't set is flagged. This also makes the marker the exact complement of the reset picker (set ⟺ resettable ⟺ no marker). The now-unused isDefault is removed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 22fa01c commit 1340edd

5 files changed

Lines changed: 9 additions & 52 deletions

File tree

docs/site/en/guide/localization.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ The schema's `defaultValue` stays the English fallback. Defaults are **not persi
6363

6464
Only `STRING` fields are localized this way. Enum defaults are stored identifiers (not display text) and are returned verbatim, as are numbers, booleans and lists.
6565

66-
In the `/config` panel, a value still served by its default is flagged with a `config.defaultSuffix` marker (`_(default)_`), so an admin can tell at a glance what has actually been set. `ConfigProvider.isDefault(key)` exposes the same distinction in code.
66+
In the `/config` panel, any field the admin hasn't set — showing a default, or nothing for a field without one — is flagged with a `config.defaultSuffix` marker (`_(default)_`), so they can tell at a glance what has actually been changed. `ConfigProvider.isSet(key)` exposes the same distinction in code.
6767

6868
> [!NOTE]
6969
> Guilds whose config predates this mechanism keep whatever default was already

docs/site/fr/guide/localisation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Le `defaultValue` du schéma reste le repli anglais. Les défauts ne sont **pas
6363

6464
Seuls les champs `STRING` sont localisés ainsi. Les défauts d'enum sont des identifiants stockés (pas du texte affichable) et sont renvoyés tels quels, comme les nombres, booléens et listes.
6565

66-
Dans le panneau `/config`, une valeur encore servie par son défaut est signalée par un marqueur `config.defaultSuffix` (`_(par défaut)_`), pour voir d'un coup d'œil ce qui a réellement été configuré. `ConfigProvider.isDefault(key)` expose la même distinction côté code.
66+
Dans le panneau `/config`, tout champ que l'admin n'a pas défini — affichant un défaut, ou rien pour un champ qui n'en a pas — est signalé par un marqueur `config.defaultSuffix` (`_(par défaut)_`), pour voir d'un coup d'œil ce qui a réellement été modifié. `ConfigProvider.isSet(key)` expose la même distinction côté code.
6767

6868
> [!NOTE]
6969
> Les serveurs dont la config est antérieure à ce mécanisme conservent le défaut

src/core/utils/core-messages.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,11 @@ export const configurationMessage = <TSchema extends ConfigSchema>(
165165
const optDesc = config.t("config." + key + ".description", {
166166
defaultValue: option.description,
167167
});
168-
// Flag values still served by their schema default, so an admin can tell
169-
// at a glance what they have actually set versus what is just the default.
168+
// Flag any field the admin hasn't set (showing a default — or nothing, for
169+
// a field without one), so they can tell at a glance what they've changed.
170170
const renderedValue =
171171
renderCurrentValue(option, value, config.locale) +
172-
(config.isDefault(key) ? config.t("config.defaultSuffix") : "");
172+
(config.isSet(key) ? "" : config.t("config.defaultSuffix"));
173173
section.addTextDisplayComponents((text) =>
174174
text.setContent(
175175
config.t("config.option", {

src/lib/config.test.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -263,36 +263,6 @@ describe("ConfigProvider default resolution", () => {
263263
expect(provider.get("greeting")).toBeUndefined();
264264
});
265265

266-
describe("isDefault", () => {
267-
it("is true for an unset field that declares a default", () => {
268-
const provider = new ConfigProvider(module, empty, "fr");
269-
expect(provider.isDefault("note")).toBe(true);
270-
});
271-
272-
it("is false once a value is stored", () => {
273-
const provider = new ConfigProvider(
274-
module,
275-
{ note: "stored" } as ConfigData<typeof schema>,
276-
"fr"
277-
);
278-
expect(provider.isDefault("note")).toBe(false);
279-
});
280-
281-
it("is false for an unset field without a default", () => {
282-
const provider = new ConfigProvider(module, empty, "fr");
283-
expect(provider.isDefault("greeting")).toBe(false);
284-
});
285-
286-
it("treats a cleared value (null) as explicitly set, not default", () => {
287-
const provider = new ConfigProvider(
288-
module,
289-
{ note: null } as unknown as ConfigData<typeof schema>,
290-
"fr"
291-
);
292-
expect(provider.isDefault("note")).toBe(false);
293-
});
294-
});
295-
296266
describe("isSet", () => {
297267
it("is false when nothing is stored (default in use)", () => {
298268
const provider = new ConfigProvider(module, empty, "fr");

src/lib/config.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -268,23 +268,10 @@ export class ConfigProvider<TSchema extends ConfigSchema> {
268268
}
269269

270270
/**
271-
* Whether `get(key)` is currently serving the schema default rather than a
272-
* stored value — true only when nothing is stored and the entry declares a
273-
* default. A cleared value (`null`) counts as explicitly set, not default.
274-
* Lets the UI flag which values the admin has actually chosen.
275-
*/
276-
isDefault<TKey extends keyof TSchema>(key: TKey): boolean {
277-
if (this.data[key] !== undefined) {
278-
return false;
279-
}
280-
return this.module.config[key]?.defaultValue !== undefined;
281-
}
282-
283-
/**
284-
* Whether `key` holds an explicitly stored value (including a `null` clear) —
285-
* i.e. something a reset could remove to fall back to the default. Distinct
286-
* from `!isDefault`: a field with neither a stored value nor a default is not
287-
* "set" yet not "default" either.
271+
* Whether `key` holds an explicitly stored value (including a `null` clear).
272+
* Its negation means the admin has not set the field: `get(key)` is serving a
273+
* default — or simply nothing, for a field without one. The UI flags such
274+
* values as "default" and a reset only ever touches set fields.
288275
*/
289276
isSet<TKey extends keyof TSchema>(key: TKey): boolean {
290277
return this.data[key] !== undefined;

0 commit comments

Comments
 (0)