أواجه خطأ عرض مستمرًا عند محاولة عرض مكون Glimmer (.gjs) كنافذة منبثقة باستخدام this.modal.show(). يتم تشغيل النافذة المنبثقة من مكون GJS آخر تمت إضافته إلى قائمة المشاركات عبر محول القيمة post-menu-buttons. أقوم بتشغيل Discourse v3.5.0.beta3-dev
أحاول إضافة زر إلى قائمة المشاركات باستخدام api.registerValueTransformer("post-menu-buttons", ...). يجب أن يؤدي النقر على هذا الزر إلى فتح نافذة منبثقة يحددها مكون GJS منفصل (FeedbackFormModal) باستخدام this.modal.show(FeedbackFormModal, ...).
عند النقر على الزر واستدعاء this.modal.show(), يتعطل التطبيق مع الخطأ التالي، ويبدو أنه يحدث أثناء عملية عرض FeedbackFormModal
حدث خطأ:
- أثناء العرض:
- المستوى الأعلى
التطبيق
(مكون قالب فقط غير معروف)
DiscourseRoot
ModalContainer
FeedbackFormModal
DModal
conditional-in-element:ConditionalInElement
(مكون قالب فقط غير معروف) index.js:3970:18
حدث خطأ: 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 // قد يختلف رقم السطر قليلاً
_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 ...
});
Button Component (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>
}
Modal Component (assets/javascripts/discourse/components/feedback-form-modal.gjs - Ultra-Simplified)
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>
}
بالنظر إلى أن الخطأ Attempted to use a value as a helper... undefined لا يزال مستمرًا حتى عند عرض قالب مكون GJS مبسط للغاية (يحتوي فقط على مكونات أساسية مستوردة مثل <DModal>/<DButton> والمساعدات المضمنة مثل if) عبر this.modal.show() الذي تم تشغيله من مكون تمت إضافته عبر registerValueTransformer("post-menu-buttons", ...), فما الذي يمكن أن يسبب هذا؟
هل هناك مشكلة معروفة أو قيد مع حل نطاق المساعد/المكون في النوافذ المنبثقة التي يتم تشغيلها بهذه الطريقة في إصدارات Discourse الحديثة (خاصة 3.5.0.beta3-dev)؟ هل هناك أنماط بديلة موصى بها لعرض نماذج النوافذ المنبثقة من أزرار قائمة المشاركات في GJS؟
أي إرشادات ستكون محل تقدير كبير!

