Glimmer 컴포넌트(.gjs)를 this.modal.show()를 사용하여 모달로 표시하려고 할 때 지속되는 렌더링 오류를 겪고 있습니다. 이 모달은 post-menu-buttons 값 변환기를 통해 게시글 메뉴에 추가된 다른 GJS 컴포넌트에서 트리거됩니다. 현재 Discourse v3.5.0.beta3-dev 버전을 사용 중입니다.
api.registerValueTransformer("post-menu-buttons", ...)를 사용하여 게시글 메뉴에 버튼을 추가하려고 합니다. 이 버튼을 클릭하면 this.modal.show(FeedbackFormModal, ...)를 사용하여 별도의 GJS 컴포넌트(FeedbackFormModal)로 정의된 모달이 열려야 합니다.
버튼이 클릭되고 this.modal.show()가 호출되면, FeedbackFormModal의 렌더링 과정 중 다음과 같은 오류로 인해 애플리케이션이 충돌합니다.
Error occurred:
- While rendering:
-top-level
application
(unknown template-only component)
DiscourseRoot
ModalContainer
FeedbackFormModal
DModal
conditional-in-element:ConditionalInElement
(unknown template-only component) index.js:3970:18
Error occurred: index.js:3377:16
Uncaught (in promise) Error: Attempted to use a value as a helper, but it was not an object or function. Helper definitions must be objects or functions with an associated helper manager. The value was: undefined
Ember 2
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:89256
Ember 2
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:90066
Ember 4
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:90164
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:89224
Ember 2
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:90163
Ember 2
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:90284
Ember 2
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:92117
Ember 12
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:94577
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:96288
Ember 34
show modal.js:73
openFeedbackModal leave-feedback-button.js:102 // Line number might differ slightly
_triggerAction d-button.gjs:138
Ember 10
FeedbackFormModal 템플릿을 임포트된 핵심 컴포넌트(<DModal>, <DButton>)와 표준 내장 헬퍼(if, on 등)만 포함하도록 최소한으로 줄여도 이 오류가 발생합니다.
참고를 위해 아래 코드를 첨부합니다:
plugin.rb
# frozen_string_literal: true
# name: my-plugin
module ::MyPlugin
# ... constants ...
end
require_relative "lib/my_plugin/engine"
after_initialize do
# Load Dependencies (using require_dependency and File.expand_path)
require_dependency File.expand_path('app/controllers/my_plugin/my_controller.rb', __dir__)
require_dependency File.expand_path('app/models/my_plugin/my_model.rb', __dir__)
# ... other dependencies ...
# Add methods to User (using class_eval as prepend failed)
::User.class_eval do
# Define helper methods like my_custom_stat, etc.
def my_custom_stat; # ... implementation ...; end
public :my_custom_stat
# ... other methods ...
end
# Prepend Guardian Extensions (if any)
# ::Guardian.prepend(MyPlugin::GuardianExtensions)
# Serializer modifications
reloadable_patch do |plugin|
# Add attributes to serializers, e.g.:
add_to_serializer(:post, :some_flag_for_button) do
# Logic to determine if button should show
true # Example
end
# ... other serializer additions ...
end
end
assets/javascripts/discourse/initializers/my-plugin-outlets.js
import { apiInitializer } from "discourse/lib/api";
import { hbs } from "ember-cli-htmlbars";
import LeaveFeedbackButton from "../components/leave-feedback-button"; // Button component
// ... import other components for other outlets ...
export default apiInitializer("1.13.0", (api) => {
// Use Value Transformer for Post Menu Button
api.registerValueTransformer("post-menu-buttons", ({ value: dag, context }) => {
const { post } = context;
// Logic to determine if button should render based on post.some_flag_for_button
const shouldRenderButton = post?.some_flag_for_button; // Example flag
if (shouldRenderButton) {
dag.add("leaveMyPluginFeedback", LeaveFeedbackButton, {
after: "like",
args: { post: post },
});
}
return dag;
});
// ... renderInOutlet for other UI elements ...
});
버튼 컴포넌트 (assets/javascripts/discourse/components/leave-feedback-button.gjs)
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import FeedbackFormModal from "./feedback-form-modal"; // The modal component
export default class LeaveFeedbackButton extends Component {
@service modal;
@service appEvents; // Used for error display
// Args: post
get buttonLabel() { return "Action Button"; } // Hardcoded
get buttonTitle() { return "Perform Action"; } // Hardcoded
@action
openFeedbackModal() {
console.log("Opening Modal...");
try {
// Simplified model for testing
const modelData = { post_id: this.args.post.id };
this.modal.show(FeedbackFormModal, { model: modelData });
} catch(e) {
console.error("Error showing modal", e);
this.appEvents.trigger("show:error", "Error opening modal.");
}
}
<template>
<DButton
class="btn-default my-plugin-btn"
@action={{this.openFeedbackModal}}
@icon="star" {{!-- Example icon --}}
@label={{this.buttonLabel}}
title={{this.buttonTitle}}
/>
</template>
}
모달 컴포넌트 (assets/javascripts/discourse/components/feedback-form-modal.gjs - 최소 단순화)
import Component from "@glimmer/component"; // Ensure this is imported
// Removed tracked, action, service etc. if not needed by simplified version
import DModal from "discourse/components/d-modal"; // Ensure this is imported
import DButton from "discourse/components/d-button"; // Ensure this is imported
import { on, preventDefault } from '@ember/modifier'; // Import built-ins if used
export default class FeedbackFormModal extends Component {
// Minimal JS needed for simplified template
// Example getter needed by template
get modalTitle() { return "My Modal Title"; } // Hardcoded
get cancelLabel() { return "Cancel"; }
get submitLabel() { return "Submit"; }
// Dummy action if needed by button
@action submitFeedback() { console.log("Dummy submit"); }
{{!-- ULTRA-SIMPLIFIED TEMPLATE THAT STILL CAUSES ERROR --}}
<template>
<DModal @title={{this.modalTitle}} @closeModal={{@closeModal}} class="feedback-form-modal">
<:body>
<p>--- MINIMAL MODAL TEST ---</p>
{{#if this.errorMessage}} {{!-- Using built-in 'if' --}}
<div class="alert alert-error" role="alert">{{this.errorMessage}}</div>
{{/if}}
</:body>
<:footer>
<DButton @action={{@closeModal}} class="btn-flat"> {{this.cancelLabel}} </DButton>
<DButton @action={{this.submitFeedback}} class="btn-primary" @icon={{if this.isSubmitting "spinner"}}> {{!-- Using built-in 'if' --}}
{{this.submitLabel}}
</DButton>
</:footer>
</DModal>
</template>
}
registerValueTransformer("post-menu-buttons", ...)를 통해 추가된 컴포넌트에서 트리거되는 this.modal.show()를 통해 초간단 GJS 컴포넌트 템플릿(임포트된 핵심 컴포넌트(<DModal>/<DButton>)와 if와 같은 내장 헬퍼만 포함)를 렌더링할 때도 Attempted to use a value as a helper... undefined 오류가 지속되는 점을 고려할 때, 이 문제의 원인은 무엇일 수 있을까요?
최근 Discourse 버전(특히 3.5.0.beta3-dev)에서 이 방식으로 트리거되는 모달의 헬퍼/컴포넌트 스코프 해석에 알려진 문제나 제한 사항이 있나요? GJS에서 게시글 메뉴 버튼으로 모달 폼을 표시하기 위한 권장되는 대안 패턴이 있을까요?
도움을 주시면 감사하겠습니다!

