No puedo hacer que el js en mi componente compile Error de sintaxis: El campo privado debe ser usado en una clase envolvente

Al final del día, necesito un botón de nuevo tema en el cuerpo de la lista de temas en el tema central de Discourse. Todos los ingenieros se quejan de que no les gusta que el botón de iniciar nueva conversación esté solo en la parte inferior de la lista de temas dentro de cada categoría. No quieren usar la opción del menú de nuevo tema en la parte superior porque eso no inicia el tema en la categoría en la que se encuentran actualmente.

He ejecutado esto a través de Llama 3.1 405B, así como GPT4 a través de ask.discourse.com, pero no puedo obtener una versión de JavaScript que compile. Constantemente obtengo un error de compilación: SyntaxError: Private field must be used in an enclosing class

También obtengo un error de registro de widgets, pero eso se debe a que el widget personalizado nunca se crea debido al error de compilación de JavaScript.

Estoy usando el tema Discourse Central.

Dado este encabezado:
"<script type=\"text/discourse-plugin\" version=\"0.8.18\">
  api.createWidget('custom-new-topic-button', {
    tagName: 'div.custom-new-topic-button',

    buildKey: () => `custom-new-topic-button`,

    html() {
      return [
        this.attach('button', {
          className: 'btn btn-primary',
          action: 'createNewTopic',
          contents: 'New Topic'
        })
      ];
    },

    click() {
      const composerController = this.container.lookup("controller:composer");
      const currentCategory = this.container.lookup("controller:navigation/category").get("model.id");

      composerController.open({
        action: require("discourse/models/composer").default.CREATE_TOPIC,
        draftKey: require("discourse/models/composer").default.DRAFT,
        categoryId: currentCategory,
      });

      return false;
    },
  });

  api.decorateWidget('topic-list:before', (helper) => {
    if (api.getCurrentUser()) {
      helper.appendChild(helper.createWidget('custom-new-topic-button'));
    }
  });
</script>"

con esta sección de encabezado
"<script>
    {{#if currentUser}}
     <div class="topic-list-body-new-topic">
      {{custom-new-topic-button}}
     </div>
   {{/if}}
</script>

y este CSS

.topic-list-body::before {
    content: "";
    display: block;
    position: relative; /* Important to allow absolute positioning within */
  }
  
  .topic-list-body-new-topic {
    position: absolute;
    top: 0;
    left: 0;
    padding: 10px;
    background: #f2f3f5;
    border-bottom: 1px solid #ccc;
  }
  .custom-new-topic-button .btn.btn-primary {
    background-color: #007bff;
    border-color: #007bff;
    color: #fff;
  }

Ese fue mi código original, la última recomendación es

<script type="text/discourse-plugin" version="0.8.18">
  api.createWidget('custom-new-topic-button', {
    tagName: 'div.custom-new-topic-button',

    buildKey() {
      return 'custom-new-topic-button';
    },

    defaultState() {
      return {};
    },

    html() {
      return [
        this.attach('button', {
          className: 'btn btn-primary',
          action: 'createNewTopic',
          contents: 'New Topic'
        })
      ];
    },

    createNewTopic() {
      const composerController = this.container.lookup("controller:composer");
      const currentCategory = this.container.lookup("controller:navigation/category").get("model.id");
      const Composer = require("discourse/models/composer").default;

      composerController.open({
        action: Composer.CREATE_TOPIC,
        draftKey: Composer.DRAFT,
        categoryId: currentCategory,
      });

      return false;
    },
  });

  api.decorateWidget('topic-list:before', (helper) => {
    if (api.getCurrentUser()) {
      helper.appendChild(helper.createWidget('custom-new-topic-button'));
    }
  });
</script>

@steven.webster @vasanth.mohan

Lo he conseguido. @sam Agoté mis llamadas diarias para preguntar… lo siento por eso. Y luego corrí hacia nuestro LLAMA 405 B y después de un montón de idas y venidas, obtuve código funcional. No puedo imaginar cuánto dinero me habría costado. Puede que escuche de otras personas en el foro, “oye, idiota, había una configuración para hacer esto en esta ubicación”. Pero este fue un ejercicio divertido de revisión continua de indicaciones para obtener código funcional.

Algunas de las claves son decir (ten en cuenta que algunas de estas pueden ser inexactas porque he sido desarrollador de JavaScript y desarrollador de Discourse durante aproximadamente 2 días en total):

Este es un foro alojado por Discourse y no tengo acceso al sistema operativo.
Este es un plugin, por lo que no puedes referenciar Discourse directamente.
No puedes referenciar Ember directamente.
Si vas a usar esto, asegúrate de vincularlo a self.

Y luego ve a los rasgos funcionales que desees.

<script type="text/discourse-plugin" version="1.24.0">
  api.modifyClass('component:topic-list', {
    pluginId: 'your-plugin-id',

    didRender: function() {
      const category = this.get('category');
      if (!category) {
        console.error('Categoría no encontrada');
        return;
      }

      const currentUser = this.currentUser;
      if (!currentUser) {
        console.error('Usuario actual no encontrado');
        return;
      }

      const canCreateTopic = currentUser.can_create_topic;
      if (canCreateTopic === undefined) {
        console.error('No se puede crear el tema no definido');
        return;
      }

      console.log('categoría:', category);
      console.log('canCreateTopic:', canCreateTopic);

      if (category && canCreateTopic) {
        const topicListBody = document.querySelector('.topic-list-body');
        const listContainer = document.querySelector('.list-container');
        const topicList = document.querySelector('.topic-list');

        let container = topicListBody || listContainer || topicList;

        if (!container) {
          container = this.element; // Usar el elemento del componente como contenedor
        }

        console.log('contenedor:', container);

        const existingButton = container.querySelector('.new-topic-button');
        if (!existingButton) {
          const newTopicButton = document.createElement('a');
          newTopicButton.href = '#';
          newTopicButton.className = 'new-topic-button';
          newTopicButton.setAttribute('data-category-id', category.id);
          newTopicButton.textContent = 'Nuevo Tema';

          const self = this; // Almacenar el contexto del componente
          newTopicButton.onclick = (e) => {
            e.preventDefault();
            const router = api.container.lookup('router:main');
            const url = router.generate('new-topic', { queryParams: { category: category.slug } });
            router.transitionTo(url);
          };


          container.prepend(newTopicButton);
          console.log('botón agregado');
        }
      }
    }
  });
</script>

Me precipité al decir que esa versión tenía un problema de didRender que no quería publicar en ninguna categoría que no fuera la primera. Llama lo arregló.

<script type="text/discourse-plugin" version="1.24.0">
  api.modifyClass('component:topic-list', {
    pluginId: 'your-plugin-id',

    didRender: function() {
      const category = this.get('category');
      if (!category) {
        console.error('Categoría no encontrada');
        return;
      }

      const currentUser = this.currentUser;
      if (!currentUser) {
        console.error('Usuario actual no encontrado');
        return;
      }

      const canCreateTopic = currentUser.can_create_topic;
      if (canCreateTopic === undefined) {
        console.error('No se definió si se puede crear un tema');
        return;
      }

      console.log('categoría:', category);
      console.log('canCreateTopic:', canCreateTopic);

      if (category && canCreateTopic) {
        const topicListBody = document.querySelector('.topic-list-body');
        const listContainer = document.querySelector('.list-container');
        const topicList = document.querySelector('.topic-list');

        let container = topicListBody || listContainer || topicList;

        if (!container) {
          container = this.element; // Usar el elemento del componente como contenedor
        }

        console.log('contenedor:', container);

        let newTopicButton = container.querySelector('.new-topic-button');
        if (!newTopicButton) {
          newTopicButton = document.createElement('a');
          newTopicButton.href = '#';
          newTopicButton.className = 'new-topic-button';
          container.prepend(newTopicButton);
          console.log('botón añadido');
        }

        newTopicButton.setAttribute('data-category-id', category.id);
        newTopicButton.textContent = 'Nuevo Tema';

        const self = this; // Almacenar el contexto del componente
        newTopicButton.onclick = (e) => {
          e.preventDefault();
          const router = api.container.lookup('router:main');
          const url = router.generate('new-topic', { queryParams: { category: category.slug } });
          router.transitionTo(url);
        };
      }
    }
  });
</script>

Parece que has resuelto tu problema, como suelo hacer al redactar solicitudes de ayuda.

New Topic Header Button - #67 by patrickemin te proporcionaría un ejemplo y puede ser exactamente lo que buscas.

Además, dile a tus ingenieros que pueden presionar la tecla c para redactar un mensaje.

3 Me gusta

En Central, el botón para iniciar una nueva conversación se encuentra en la parte inferior de la lista de temas. Todos querían un botón en la parte superior. Puede que lo cambie a un pequeño signo más, pero estas dos capturas de pantalla lo muestran.


1 me gusta

@pfaffman Intenté usar el nuevo botón de encabezado de tema como primer intento. Sin embargo, eso no funciona bien con el nuevo tema de Discourse Central.

Los widgets desaparecerán. No es una buena idea usar la API de widgets.

Usa componentes Glimmer.

2 Me gusta

Tendremos que eliminar un montón de contenido antiguo de los trapos de IA y también esperar a que los modelos de widgets posteriores se ajusten. Incluso ask.discourse.com se dirigió a la ruta de los widgets. ¿Qué reemplazará a los widgets? Veré si puedo conseguir que un modelo genere código que tenga eso en cuenta. Por cierto, la mayor parte de mi ejercicio es ver si puedo conseguir que un modelo haga este trabajo, ya que no sé prácticamente nada de js :slight_smile:

Entiendo la sensación.

Componentes Glimmer. En algún lugar hay un tema decente que los describe.

Pero aquí tienes un ejemplo para crear el componente:

Y aquí tienes una forma de javascript para insertarlo:

La otra forma de insertarlo es la forma que se está volviendo anticuada de crear un conector que luego inserta el componente, pero la ventaja de la forma del inicializador es que puedes pasar el outlet del plugin deseado al inicializador para que puedas tener una configuración que cambie dónde se muestra.

Creo que quieres encontrar un ejemplo de algo que llame a shouldDisplay (o algo parecido) si quieres que se muestre solo a veces (como si estuvieran conectados).

4 Me gusta

Mi código final que obtuve de Llama anoche no usó widgets, pero tampoco usó Glimmer. Jugaré con Glimmer más tarde hoy.

<script type="text/discourse-plugin" version="1.24.0">
  api.modifyClass('component:topic-list', {
    pluginId: 'your-plugin-id',

    didRender: function() {
      const category = this.get('category');
      if (!category) {
        console.error('Categoría no encontrada');
        return;
      }

      const currentUser = this.currentUser;
      if (!currentUser) {
        console.error('Usuario actual no encontrado');
        return;
      }

      const canCreateTopic = currentUser.can_create_topic;
      if (canCreateTopic === undefined) {
        console.error('No se definió si se puede crear un tema');
        return;
      }

      console.log('categoría:', category);
      console.log('canCreateTopic:', canCreateTopic);

      if (category && canCreateTopic) {
        const topicListBody = document.querySelector('.topic-list-body');
        const listContainer = document.querySelector('.list-container');
        const topicList = document.querySelector('.topic-list');

        let container = topicListBody || listContainer || topicList;

        if (!container) {
          container = this.element; // Usar el elemento del componente como contenedor
        }

        console.log('contenedor:', container);

        let newTopicButton = container.querySelector('.new-topic-button');
        if (!newTopicButton) {
          newTopicButton = document.createElement('a');
          newTopicButton.href = '#';
          newTopicButton.className = 'new-topic-button';
          container.prepend(newTopicButton);
          console.log('botón agregado');
        }

        newTopicButton.setAttribute('data-category-id', category.id);
        newTopicButton.textContent = 'Nuevo Tema';

        const self = this; // Almacenar el contexto del componente
        newTopicButton.onclick = (e) => {
          e.preventDefault();
          const router = api.container.lookup('router:main');
          const url = router.generate('new-topic', { queryParams: { category: category.slug } });
          router.transitionTo(url);
        };
      }
    }
  });

</script>

Advertencia: La lista de temas actualmente no se convierte a Glimmer.

Sin embargo, si está adjuntando Componentes a Plugin Outlets, debe usar Glimmer.

Si tiene que adjuntar a un widget, puede usar RenderGlimmer para lograrlo.

Ejemplo aquí:

Le imploro que no confíe demasiado en los LLM sin aprender los conceptos básicos por sí mismo primero, ya que usted debe ser el control de calidad definitivo de lo que el LLM está produciendo.

También necesita arquitectar la solución correctamente.

Lea más sobre EmberJS aquí:

3 Me gusta

Gracias. Definitivamente estudiaré más, ya que soy completamente nuevo en discourse y js.

Trabajo para una empresa de IA, así que este también fue un ejercicio de ingeniería de prompts.

3 Me gusta

Genial, así tendrás una buena idea de sus fortalezas y debilidades.

Escribí el primer bot de IA para Discourse llamado Chatbot, así que también tengo algo de conocimiento.

2 Me gusta

Se agregará una guía especial al prompt del sistema para asegurar que “ask” nunca recomiende el uso de widgets.

5 Me gusta