Não consigo fazer o JS no meu componente compilar. Erro de sintaxe: campo privado deve ser usado em uma classe envolvente

No final do dia, preciso de um botão de novo tópico no corpo da lista de tópicos no tema central do Discourse. Todos os engenheiros reclamam que não gostam do botão “Iniciar nova conversa” estar apenas no final da lista de tópicos dentro de cada categoria. Eles não querem usar a opção do menu “novo tópico” no topo, pois isso não inicia o tópico na categoria em que eles estão atualmente.

Já executei isso através do Llama 3.1 405B, bem como do GPT-4 via ask.discourse.com, mas não consigo obter uma versão de JavaScript que compile. Estou constantemente recebendo o erro de compilação: Compile error: SyntaxError: Private field must be used in an enclosing class

Também recebo um erro no registro de widgets, mas isso ocorre porque o widget personalizado nunca é criado devido ao erro de compilação do JS.

Estou usando o tema Discourse Central.

Dado este cabeçalho:
"<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>"

Com esta seção de cabeçalho:

"<script>
    {{#if currentUser}}
     <div>
      {{custom-new-topic-button}}
     </div>
   {{/if}}
</script>"

E este CSS:

".topic-list-body::before {
    content: "";
    display: block;
    position: relative; /* Importante para permitir o posicionamento absoluto dentro */
  }
  
  .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;
  }"

Esse era meu código original. A recomendação mais recente é:

<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

Consegui fazer funcionar. @sam Esgotei minhas chamadas diárias para perguntar… desculpe por isso. E então corri para o nosso LLAMA 405 B e, após muita discussão, consegui um código funcional. Não consigo imaginar quanto dinheiro isso teria me custado. Posso ouvir de outras pessoas no fórum: “ei, idiota, havia uma configuração para fazer isso naquele local”. Mas este foi um exercício divertido de revisão contínua de prompts para obter código funcional.

Algumas das chaves são dizer (lembre-se que algumas delas podem estar imprecisas porque sou desenvolvedor de JavaScript e desenvolvedor de Discourse há apenas dois dias no total.)

Este é um fórum hospedado pelo Discourse e não tenho acesso ao sistema operacional
Este é um plugin, então você não pode referenciar o Discourse diretamente.
Você não pode referenciar o Ember diretamente
Se você for usar isso, certifique-se de vinculá-lo a self

Em seguida, vá para os traços funcionais que você deseja.

<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('Categoria não encontrada');
        return;
      }

      const currentUser = this.currentUser;
      if (!currentUser) {
        console.error('Usuário atual não encontrado');
        return;
      }

      const canCreateTopic = currentUser.can_create_topic;
      if (canCreateTopic === undefined) {
        console.error('Não é possível criar tópico não definido');
        return;
      }

      console.log('categoria:', 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; // Usa o elemento do componente como contêiner
        }

        console.log('contêiner:', 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 = 'Novo Tópico';

          const self = this; // Armazena o contexto do 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ão adicionado');
        }
      }
    }
  });
</script>

Falei cedo demais, essa versão tinha um problema de didRender que não queria postar em nenhuma categoria além da primeira. O Llama consertou isso.

<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('Categoria não encontrada');
        return;
      }

      const currentUser = this.currentUser;
      if (!currentUser) {
        console.error('Usuário atual não encontrado');
        return;
      }

      const canCreateTopic = currentUser.can_create_topic;
      if (canCreateTopic === undefined) {
        console.error('Não é possível criar tópico não definido');
        return;
      }

      console.log('categoria:', 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; // Usa o elemento do componente como contêiner
        }

        console.log('contêiner:', 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ão adicionado');
        }

        newTopicButton.setAttribute('data-category-id', category.id);
        newTopicButton.textContent = 'Novo Tópico';

        const self = this; // Armazena o contexto do 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 você resolveu seu problema, como eu costumo fazer ao compor pedidos de ajuda.

New Topic Header Button - #67 by patrickemin forneceria um exemplo e pode ser exatamente o que você procura.

Além disso, diga aos seus engenheiros que eles podem pressionar a tecla c para compor uma mensagem.

3 curtidas

No Central, o botão para iniciar uma nova conversa fica na parte inferior da lista de tópicos. Todos queriam um botão na parte superior. Posso mudá-lo para um pequeno sinal de mais, mas estas duas capturas de tela o mostram.


1 curtida

@pfaffman Tentei o novo botão de cabeçalho de tópico como primeira tentativa. No entanto, isso não combina bem com o novo tema Discourse Central.

Widgets estão desaparecendo. Não é uma boa ideia usar a API de widgets.

Use Componentes Glimmer.

2 curtidas

Teremos que remover um monte de conteúdo antigo de “AI rags” também, além de esperar que os modelos de widget de postagem sejam ajustados. Até mesmo ask.discourse.com foi direcionado para a rota de widgets. O que substituirá os widgets? Vou ver se consigo fazer um modelo gerar código que leve isso em consideração. A propósito, a maior parte do meu exercício é ver se consigo fazer um modelo fazer esse trabalho, já que não sei praticamente nada sobre js :slight_smile:

Eu conheço esse sentimento.

Componentes Glimmer. Em algum lugar existe um tópico decente descrevendo-os.

Mas aqui está um exemplo para criar o componente:

E aqui está uma maneira javascript de inseri-lo:

A outra maneira de inseri-lo é a maneira que está ficando antiga de criar um conector que então insere o componente, mas a vantagem da maneira do inicializador é que você pode então passar o plugin outlet desejado para o inicializador para que você possa ter uma configuração que muda onde ele é exibido.

Eu acho que você quer encontrar um exemplo de algo que chama shouldDisplay (ou algo assim) se você quiser que ele seja exibido apenas às vezes (como se estivessem logados).

4 curtidas

Meu código final que o llama cuspiu ontem à noite não usou widgets, mas também não usou glimmer. Vou mexer com o glimmer mais tarde hoje


<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('Categoria não encontrada');
        return;
      }

      const currentUser = this.currentUser;
      if (!currentUser) {
        console.error('Usuário atual não encontrado');
        return;
      }

      const canCreateTopic = currentUser.can_create_topic;
      if (canCreateTopic === undefined) {
        console.error('Não é possível criar tópico não definido');
        return;
      }

      console.log('categoria:', 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; // Usa o elemento do componente como contêiner
        }

        console.log('contêiner:', 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ão adicionado');
        }

        newTopicButton.setAttribute('data-category-id', category.id);
        newTopicButton.textContent = 'Novo Tópico';

        const self = this; // Armazena o contexto do 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>

Observação: A Lista de Tópicos atualmente não é convertida para Glimmer.

No entanto, se você estiver anexando Componentes a Plugin Outlets, deverá usar Glimmer.

Se você tiver que anexar a um widget, poderá usar RenderGlimmer para conseguir isso.

Exemplo aqui:

Imploro que você não confie demais em LLMs sem aprender os fundamentos por si mesmo primeiro, pois você precisa ser o controle de qualidade final do que o LLM está produzindo.

Você também precisa arquitetar a solução corretamente.

Leia mais sobre EmberJS aqui:

3 curtidas

Obrigado. Com certeza estudarei mais, pois sou novato em discourse e js.

Eu trabalho para uma empresa de IA, então este também foi um exercício em engenharia de prompt.

3 curtidas

Legal, então você terá uma boa ideia de seus pontos fortes e fracos.

Eu escrevi o primeiro Bot de IA para o Discourse chamado Chatbot, então também tenho alguma visão.

2 curtidas

Adicionará uma orientação especial ao prompt do sistema para garantir que “perguntar” nunca recomende o uso de widgets

5 curtidas