Aiuto nel trovare perché l'elenco degli argomenti non si aggiorna dopo aver cliccato sull'avviso di nuovo argomento/risposta

Sul sito del creatore di temi stavo cercando di rimuovere gli argomenti degli utenti ignorati dall’elenco degli argomenti, ecco il mio codice

api.modifyClass("component:topic-list", {
      @on("didReceiveAttrs")
      removeIgnoredUsers() {
        this.topics = this.topics.filter(
          topic => !ignored.includes(topic.posters[0].user.username)
        );
      }
});

Funziona sia su mobile che su desktop come previsto, ma ho scoperto che causa anche il mancato aggiornamento dell’elenco degli argomenti dopo aver fatto clic sull’avviso di nuovo argomento/risposta.

Ho una registrazione dello schermo che riproduce questo bug.

Nel video, stavo guardando la visualizzazione mobile sul mio desktop e creando una nuova risposta a ‘test new topic alert 3’ dal mio cellulare, quindi ho fatto clic sull’avviso sul desktop, nel caso normale, l’argomento aggiornato dovrebbe apparire in cima agli argomenti, ma in questo caso non lo fa.

Pensavo che il metodo che ho usato sopra fosse attivato erroneamente, ma non viene chiamato quando si fa clic su un avviso di argomento.

Qualcuno ha suggerimenti sul perché si è verificato questo bug? Molte grazie.

Aggiornamento: ho scoperto che causa anche il mancato funzionamento del caricamento automatico di più argomenti durante lo scorrimento nella visualizzazione mobile.

2 Mi Piace

Se rimuovi il codice sopra che non mostra gli utenti ignorati, il problema è risolto? Se è risolto, la mia ipotesi è che il tuo codice stia filtrando gli argomenti di tutti gli utenti (o di più utenti di quanto dovrebbe), il che fa sì che non vengano visualizzati.

Non so da dove venga popolato ignored, ma potrebbe essere popolato con il nome utente dell’utente che ha creato il nuovo argomento che ha mostrato l’avviso in alto. Forse viene popolato con utenti che non dovrebbero essere ignorati? Puoi registrare i valori presenti in ignored?

2 Mi Piace

Penso che non sia così poiché questo problema si è verificato solo su mobile/visualizzazione mobile. (non è stato aggiornato e non è stato possibile caricare altro)

Ho impostato manualmente const ignored = ['david', 'pekka_gaiser', 'sam']; per testare sul sito del creatore del tema, dato che presumo di non aver raggiunto il livello di fiducia che può utilizzare la funzione di ignorare o che fosse disabilitata.

E l’argomento che ho aggiornato è un argomento che ho creato.

1 Mi Piace

Strano, a meno che il problema non sia specificamente in quel codice. Se cambi il codice in:

api.modifyClass("component:topic-list", {
      @on("didReceiveAttrs")
      removeIgnoredUsers() {
        this.topics = this.topics.filter(() => true);
      }
});

il problema persiste? Se persiste, il problema è probabilmente altrove.

2 Mi Piace

No, il bug è sparito se cambio il blocco con quello che fornisci. Pensavo che forse la funzione di filtro interrompesse il ciclo di aggiornamento dei dati dell’argomento, ma questo bug si verifica solo su dispositivi mobili, non riesco a capire cosa causi la differenza tra desktop e mobile…

1 Mi Piace

Allora l’unica cosa a cui riesco a pensare è che la variabile ignored venga popolata erroneamente come ho detto in precedenza. Forse da qualche altra parte viene modificato il valore. Prova a cambiare il codice in:

api.modifyClass("component:topic-list", {
      @on("didReceiveAttrs")
      removeIgnoredUsers() {
        const ignored2 = ['david', 'pekka_gaiser', 'sam'];
        this.topics = this.topics.filter(
          topic => !ignored2.includes(topic.posters[0].user.username)
        );
      }
});

Nel codice sopra ho inserito la variabile ignored nello stesso scope in cui viene applicato il filtro e ho cambiato il nome della variabile per evitare modifiche non intenzionali ai valori dell’array (ad esempio, se da qualche parte viene chiamato ignored.push(...), potrebbe cambiarne i valori altrove).

1 Mi Piace

Quando fai qualcosa del genere

this.topics = something_else

Stai ridefinendo quella proprietà con qualcos’altro. Va bene se nient’altro sta osservando quella proprietà, ma in questo caso, diverse cose stanno osservando l’array topics.

Ad esempio

Se fai questo su un’installazione di sviluppo, Ember genererà errori nella console come segue.

.

Quindi, il punto chiave qui è fare qualcosa di simile invece.

this.set("topics", something_else)

fino a quando il decoratore @tracked non arriverà in Discourse.

Quindi, se provi qualcosa del genere

api.modifyClass("component:topic-list", {
  @on("didReceiveAttrs")
  removeIgnoredUsers() {
    const filtered = this.topics.filter(
      topic => !ignored.includes(topic.posters[0].user.username)
    );
    this.set("topics", filtered);
  }
});

Dovrebbe funzionare sia su desktop che su mobile nel tema creator.

Tuttavia…

Se provi questo su un’installazione di sviluppo, vedrai un altro errore.

Quindi questo dovrebbe dirti qualcosa. L’array topics viene utilizzato in molti posti diversi. Quindi non è una buona idea pasticciarci - specialmente poiché il tuo caso d’uso è principalmente visivo e non ci sono implicazioni di sicurezza coinvolte.

Ecco cosa suggerisco: fai un passo indietro e prova un approccio diverso. Invece di cercare di modificare l’array, fai qualcosa di molto più semplice. Se un utente ignorato ha creato l’argomento, aggiungi una classe CSS e nascondilo con CSS.

Lo fai con qualcosa del genere - ho lasciato alcuni commenti se vuoi seguirli, ma puoi eliminarli quando sei pronto per usarli.

Questo va nel file initializer:

import { apiInitializer } from "discourse/lib/api";
import discourseComputed from "discourse-common/utils/decorators";

export default apiInitializer("0.11.1", api => {
  // imposta un id per le tue modifiche
  const PLUGIN_ID = "hide-ignored-op-topics";

  // Il nome della classe che vuoi aggiungere. Lo spazio all'inizio è obbligatorio
  const IGNORED_TOPIC_CLASS_STRING = " ignored-op-topic";

  // ottieni l'utente corrente
  const user = api.getCurrentUser();

  // non loggato, esci
  if (!user) {
    return;
  }

  // ottieni un elenco di utenti ignorati
  const ignored = user.ignored_users;

  // funzione helper per evitare duplicazioni di codice
  const addIgnoredTopicClass = context => {
    // ottieni le classi dal core / altri plugin e temi
    let classList = context._super(...arguments);

    // crea la tua condizione
    const shouldAddClass = ignored.includes(
      context.topic.posters[0].user.username
    );

    // aggiungi la classe ignorata se la condizione è vera
    if (shouldAddClass) {
      classList += IGNORED_TOPIC_CLASS_STRING;
    }

    // restituisci la classList più le modifiche, se presenti
    return classList;
  };

  // aggiungi la classe alla lista degli argomenti predefinita, come nella pagina "latest"
  api.modifyClass("component:topic-list-item", {
    pluginId: PLUGIN_ID,
    @discourseComputed()
    unboundClassNames() {
      return addIgnoredTopicClass(this);
    }
  });

  // fai lo stesso per la lista degli argomenti della pagina delle categorie
  api.modifyClass("component:latest-topic-list-item", {
    pluginId: PLUGIN_ID,
    @discourseComputed()
    unboundClassNames() {
      return addIgnoredTopicClass(this);
    }
  });
});

e questo va in /common/common.css

// non usiamo display: none; qui perché non vogliamo interferire con load-more
.ignored-op-topic {
  height: 0;
  width: 0;
  position: fixed;
  bottom: 0;
}
2 Mi Piace

Grazie, il secondo metodo funziona.

È possibile aggiungere una classe aggiuntiva all’elemento figlio del componente?

Ad esempio, vorrei nascondere l’avatar dell’utente ignorato nell’elenco degli avatar desktop sul lato destro del titolo dell’argomento, aggiungendo una classe all’elemento dell’elenco degli argomenti, sarà possibile aggiungere una classe a un componente avatar?

Il metodo unboundClassNames() che abbiamo utilizzato sopra è responsabile delle classi aggiunte all’elemento del componente. In altre parole, gli elementi HTML .topic-list-item o .latest-topic-list-item. Puoi vederlo qui

e qui

Ember prende qualsiasi stringa restituita da quel metodo e la aggiunge come attributo class all’elemento stesso.

Dovrai usare qualcos’altro se vuoi aggiungere classi ai figli di quell’elemento.

Ogni poster nella proprietà posters ha una proprietà chiamata extras. Questa proprietà viene utilizzata come flag per le classi aggiuntive da aggiungere all’avatar quando viene renderizzato.

È impostato qui

e consumato qui

Quindi, puoi aggiungere classi agli avatar nell’elenco degli argomenti in base a una condizione se estendi quella proprietà.

Puoi usare il decoratore @on quando il componente riceve i suoi attributi per chiamare un metodo per farlo. Poiché stiamo già modificando quelle classi del componente, possiamo incorporare quel nuovo comportamento nel codice sopra.

Ecco cosa otteniamo

nell’inizializzatore

import { apiInitializer } from "discourse/lib/api";
import discourseComputed, { on } from "discourse-common/utils/decorators";

export default apiInitializer("0.11.1", (api) => {
  const PLUGIN_ID = "hide-ignored-op-topics";
  const IGNORED_TOPIC_CLASS_STRING = " ignored-op-topic";
  const IGNORED_AVATAR_CLASS_STRING = " ignored-user-avatar";

  const user = api.getCurrentUser();

  if (!user) {
    return;
  }

  const ignoredUsers = user.ignored_users;

  function isIgnoredUser(poster) {
    return ignoredUsers.includes(poster.user.username);
  }

  function addIgnoredTopicClass() {
    let classList = this._super(...arguments);
    
    const topicCreator = this.topic.posters[0];

    if (isIgnoredUser(topicCreator)) {
      classList += IGNORED_TOPIC_CLASS_STRING;
    }

    return classList;
  }

  function addIgnoredAvatarClass() {
    this.topic.posters.forEach((poster) => {
      if (isIgnoredUser(poster)) {
        // default raw topic-lists
        poster.extras += IGNORED_AVATAR_CLASS_STRING;

        // categories page topic lists
        poster.user.set("extras", IGNORED_AVATAR_CLASS_STRING);
      }
    });
  }

  api.modifyClass("component:topic-list-item", {
    pluginId: PLUGIN_ID,

    @discourseComputed()
    unboundClassNames() {
      return addIgnoredTopicClass.call(this);
    },

    @on("didReceiveAttrs")
    ignoredAvatarClass() {
      addIgnoredAvatarClass.call(this);
    },
  });

  api.modifyClass("component:latest-topic-list-item", {
    pluginId: PLUGIN_ID,

    @discourseComputed()
    unboundClassNames() {
      return addIgnoredTopicClass.call(this);
    },

    @on("didReceiveAttrs")
    ignoredAvatarClass() {
      addIgnoredAvatarClass.call(this);
    },
  });
});

Questo dovrebbe darti una classe CSS ignored-op-topic sugli elementi dell’elenco degli argomenti avviati da un utente ignorato e una classe CSS ignored-user-avatar su ogni avatar di utente ignorato nella colonna dei poster.

Abbiamo già il CSS per .ignored-op-topic da sopra.

// non usiamo display: none; qui perché non vogliamo interferire con load-more
.ignored-op-topic {
  height: 0;
  width: 0;
  position: fixed;
  bottom: 0;
}

Ora, vuoi nascondere gli avatar degli utenti ignorati nella colonna dell’elenco degli argomenti.

Non farlo. Questo creerà molta confusione.

Cosa succede se un utente ignorato risponde a un argomento, questo viene aggiornato, ma hai nascosto il suo avatar? Sembrerebbe che qualcun altro abbia appena aggiornato l’argomento.

Inoltre, c’è un solo avatar nella pagina delle categorie accanto ai titoli degli argomenti. Cosa succede se l’ultimo utente che ha risposto è un utente ignorato? Nessun avatar?

Puoi vedere come tali casi creerebbero un’esperienza spiacevole per i tuoi utenti.

Invece di nascondere gli avatar degli utenti ignorati, puoi sostituirli con un’icona SVG. Tutti gli utenti ignorati avranno lo stesso avatar. Puoi farlo con CSS

.ignored-user-avatar {
  background: white;
  border: 1px solid transparent;
  box-sizing: border-box;
  opacity: 0.5;
  content: svg-uri(
    '\u003csvg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"\u003e\u003cpath d="m256 0c141.385 0 256 114.615 256 256s-114.615 256-256 256-256-114.615-256-256 114.615-256 256-256zm0 105c-83.262 0-151 67.74-151 151s67.737 151 151 151 151-67.736 151-151-67.74-151-151-151zm-52.816 130.621a22.119 22.119 0 1 0 0-44.237 22.119 22.119 0 0 0 0 44.237zm127.749-22.121a22.116 22.116 0 0 0 -22.12-22.12 22.119 22.119 0 1 0 22.12 22.12zm-40.233 70.79a9.439 9.439 0 0 0 -13.35-13.347l-21.35 21.357-21.352-21.357a9.438 9.438 0 1 0 -13.348 13.347l21.352 21.352-21.352 21.358a9.438 9.438 0 1 0 13.347 13.347l21.353-21.355 21.351 21.351a9.439 9.439 0 0 0 13.349-13.343l-21.352-21.354z"/\u003e\u003c/svg\u003e'\n  );
}

e renderizzerà così

e lo stesso su latest-topic-list-item. Cambia l’SVG con qualsiasi icona tu voglia usare.

Detto questo…

Ho risposto alla tua domanda perché è una buona opportunità per parlare della personalizzazione dell’elenco degli argomenti e di come farlo. Tuttavia, ho molte riserve sul tuo caso d’uso. La necessità di nascondere gli avatar degli utenti ignorati indica un problema sottostante. È una cosa dire

“questa persona scrive di argomenti che non mi interessano. La ignorerò per ridurre il rumore.”

ma è una cosa completamente diversa dire

“anche vedere l’avatar di questa persona scatena una risposta emotiva. Non voglio mai più vedere il suo avatar.”

Conosci la tua community più di chiunque altro… ma è probabilmente qualcosa che vale la pena approfondire.

4 Mi Piace

Capito. Stavo cercando di imitare la funzione di blocco come Mastodon o Twitter il più possibile, in modo che quando ignori un utente non vedrai mai più contenuti da lui. Concordo sul fatto che la maggior parte delle community potrebbe non aver mai bisogno di questo tipo di funzione. Dato che i miei utenti lo chiedono, vorrei fare del mio meglio.

1 Mi Piace