Hello , I want to move subtasks from parent to another using forge , but the problem is when i click on the moving icon , there's no change . I don't know why , here is the code of my forge app : 
import ForgeUI, { useProductContext, IssuePanel, render, Fragment, Text, Button, useState, useEffect, Table, Head, Cell, Row, Link, TextField, Form, Select, Option, ModalDialog } from '@forge/ui';
import api, { route } from '@forge/api';
const PAGE_SIZE = 3; 
const fetchChildIssues = async (issueKey) => {
  const response = await api.asApp().requestJira(route`/rest/api/3/search?jql=parent=${issueKey}`);
  const data = await response.json();
  return data.issues || []; // Ensure data.issues is handled properly
};
  
  const fetchLinkedIssues = async (issueKey) => {
    const response = await api.asApp().requestJira(route`/rest/api/3/search?jql=issue in linkedIssues(${issueKey})`);
    const data = await response.json();
    return data.issues || [];
  };
  
  const fetchIssueTypes = async (projectId) => {
    const response = await api.asApp().requestJira(route`/rest/api/3/issuetype`);
    const data = await response.json();
    console.log("Issue Types Response:", data); 
    return data.issueTypes ? data.issueTypes.filter((issueType) => issueType.subtask) : [];
  };
  
  const createSubtask = async (parentKey, summary, assignee, priority, issueTypeId) => {
    const projectResponse = await api.asApp().requestJira(route`/rest/api/3/issue/${parentKey}`);
    const projectData = await projectResponse.json();
    const projectId = projectData.fields.project.id;
  
    const response = await api.asApp().requestJira(route`/rest/api/3/issue`, {
      method: "POST",
      body: JSON.stringify({
        fields: {
          project: { id: projectId },
          parent: { key: parentKey },
          summary: summary,
          assignee: { id: assignee },
          priority: { id: priority },
          issuetype: { id: issueTypeId },
        },
      }),
    });
    return response.json();
  };
  
  const fetchUsers = async () => {
    const response = await api.asApp().requestJira(route`/rest/api/3/user/search?query=`);
    const data = await response.json();
    return data.map((user) => ({ id: user.accountId, displayName: user.displayName }));
  };
  
  const fetchPriorities = async () => {
    const response = await api.asApp().requestJira(route`/rest/api/3/priority`);
    const data = await response.json();
    return data;
  };
  
  const deleteIssue = async (issueKey) => {
    await api.asApp().requestJira(route`/rest/api/3/issue/${issueKey}`, {
      method: "DELETE",
    });
  };
  
  // Fonction pour récupérer les détails d'une issue par sa clé
const fetchIssueByKey = async (issueKey) => {
  const response = await api.asApp().requestJira(route`/rest/api/3/issue/${issueKey}`);
  if (!response.ok) {
    throw new Error(`Failed to fetch issue ${issueKey}: ${response.statusText}`);
  }
  return await response.json();
};
// Fonction pour mettre à jour l'issue avec un nouveau parent
const updateParentIssue = async (issueKey, newParentKey) => {
  const issue = await fetchIssueByKey(issueKey);
  const updatePayload = {
    fields: {
      parent: { key: newParentKey }
    }
  };
  
  const response = await api.asApp().requestJira(route`/rest/api/3/issue/${issueKey}`, {
    method: 'PUT',
    body: JSON.stringify(updatePayload),
    headers: {
      'Content-Type': 'application/json'
    }
  });
  if (!response.ok) {
    throw new Error(`Failed to update issue ${issueKey}: ${response.statusText}`);
  }
};
const MoveSubtaskModal = ({ issueKey, onClose, handleMoveSubtask }) => {
  const [newParentKey, setNewParentKey] = useState('');
  const [error, setError] = useState(null);
  const handleSubmit = async () => {
    try {
      await handleMoveSubtask(issueKey, newParentKey);
      onClose();
    } catch (error) {
      setError(error.message);
    }
  };
  return (
    <ModalDialog header="Déplacer la sous-tâche vers un nouveau parent" onClose={onClose}>
      <Form onSubmit={handleSubmit}>
        <Text content="Entrez la clé du nouveau parent pour déplacer cette sous-tâche :" />
        <TextField name="newParentKey" label="Clé du nouveau parent" value={newParentKey} onChange={setNewParentKey} />
        {error && <Text content={`Erreur : ${error}`} />}
        <Button text="Déplacer" type="submit" />
      </Form>
    </ModalDialog>
  );
};
const Panel = () => {
  const { platformContext: { issueKey } } = useProductContext();
  const [childIssues, setChildIssues] = useState([]);
  const [linkedIssues, setLinkedIssues] = useState([]);
  const [filteredChildIssues, setFilteredChildIssues] = useState([]);
  const [filteredLinkedIssues, setFilteredLinkedIssues] = useState([]);
  const [isPanelVisible, setPanelVisible] = useState(true);
  const [currentPage, setCurrentPage] = useState(1);
  const [parentIssueStatus, setParentIssueStatus] = useState('');
  const [issueTypes, setIssueTypes] = useState([]);
  const [users, setUsers] = useState([]);
  const [priorities, setPriorities] = useState([]);
  const [isCreating, setIsCreating] = useState(false);
  const [isFormVisible, setFormVisible] = useState(false);
  const [showConfirmationDialog, setShowConfirmationDialog] = useState(false);
  const [issueToDelete, setIssueToDelete] = useState(null);
  const [selectedIssue, setSelectedIssue] = useState(null);
  const [isModalOpen, setModalOpen] = useState(false);
  const handleMoveSubtask = async (issueKey, newParentKey) => {
    try {
      await updateParentIssue(issueKey, newParentKey);
      const updatedChildIssues = await fetchChildIssues(issueKey);
      setChildIssues(updatedChildIssues);
      setFilteredChildIssues(updatedChildIssues.slice(0, PAGE_SIZE));
      setModalOpen(false);
    } catch (error) {
      console.error('Error handling move subtask:', error);
    }
  };
  useEffect(async () => {
    try {
      const childIssues = await fetchChildIssues(issueKey);
      const linkedIssues = await fetchLinkedIssues(issueKey);
      setChildIssues(childIssues);
      setLinkedIssues(linkedIssues);
      setFilteredChildIssues(childIssues.slice(0, PAGE_SIZE));
      setFilteredLinkedIssues(linkedIssues.slice(0, PAGE_SIZE));
      const response = await api.asApp().requestJira(route`/rest/api/3/issue/${issueKey}`);
      const data = await response.json();
      const parentStatus = data.fields.status.name;
      setParentIssueStatus(parentStatus);
      const issueTypes = await fetchIssueTypes(data.fields.project.id);
      setIssueTypes(issueTypes);
      const users = await fetchUsers();
      setUsers(users);
      const priorities = await fetchPriorities();
      setPriorities(priorities);
    } catch (error) {
      console.error('Error during useEffect:', error);
    }
  }, [issueKey]);
  
    const handleFilter = (formData, issues, setFilteredIssues) => {
      const query = formData.query.toLowerCase();
      const filtered = issues.filter(
        (issue) =>
          issue.fields.summary.toLowerCase().includes(query) ||
          (issue.fields.assignee && issue.fields.assignee.displayName.toLowerCase().includes(query)) ||
          issue.fields.status.name.toLowerCase().includes(query) ||
          issue.key.toLowerCase().includes(query)
      );
      setFilteredIssues(filtered.slice(0, PAGE_SIZE));
      setCurrentPage(1);
    };
  
    const handleDeleteIssue = async (issueKey) => {
        setIssueToDelete(issueKey);
        setShowConfirmationDialog(true);
      };
    
      const confirmDeleteIssue = async () => {
        try {
          await deleteIssue(issueToDelete);
          setShowConfirmationDialog(false);
          const updatedChildIssues = await fetchChildIssues(issueKey);
          const updatedLinkedIssues = await fetchLinkedIssues(issueKey);
          setChildIssues(updatedChildIssues);
          setLinkedIssues(updatedLinkedIssues);
          setFilteredChildIssues(updatedChildIssues.slice(0, PAGE_SIZE));
          setFilteredLinkedIssues(updatedLinkedIssues.slice(0, PAGE_SIZE));
          setCurrentPage(1);
        } catch (error) {
          console.error("Error confirming issue deletion:", error);
        }
      };
    
      const cancelDeleteIssue = () => {
        setShowConfirmationDialog(false);
        setIssueToDelete(null);
      };
    
      const handleIssueClick = (issue) => {
        setSelectedIssue(issue);
    };
    const closeIssueDetail = () => {
        setSelectedIssue(null);
    };
  
    const handlePageChange = (pageNumber, issues, setFilteredIssues) => {
      const startIndex = (pageNumber - 1) * PAGE_SIZE;
      const endIndex = startIndex + PAGE_SIZE;
      setFilteredIssues(issues.slice(startIndex, endIndex));
      setCurrentPage(pageNumber);
    };
  
    const handleCreateButtonClick = () => {
      setFormVisible(true); // Définit l'état pour afficher le formulaire lorsqu'on clique sur "Créer"
    };
  
    const handleCreateSubtask = async (formData) => {
      const { summary, assignee, priority, issueTypeId } = formData;
      setIsCreating(true);
      await createSubtask(issueKey, summary, assignee, priority, issueTypeId);
      const childIssues = await fetchChildIssues(issueKey);
      setChildIssues(childIssues);
      setFilteredChildIssues(childIssues.slice(0, PAGE_SIZE));
      setIsCreating(false);
      setFormVisible(false); // Après création, masque le formulaire
    };
  
    const canCreateSubtask = parentIssueStatus !== "Terminé";
  
    return (
      <Fragment>
        <Button text={isPanelVisible ? "Masquer les tickets enfants et liés" : "Afficher les tickets enfants et liés"} onClick={() => setPanelVisible(!isPanelVisible)} />
        {isPanelVisible && (
          <Fragment>
            {canCreateSubtask && (
              <Fragment>
                <Text content="**Créer une sous-tâche:**" />
                {!isFormVisible && ( // Affiche le bouton de création uniquement si le formulaire n'est pas déjà visible
                  <Button text="Créer" onClick={handleCreateButtonClick} />
                )}
                {isFormVisible && ( // Affiche le formulaire si isFormVisible est true
                  <Form onSubmit={handleCreateSubtask}>
                    <TextField name="summary" label="Résumé" isRequired />
                    <Select label="Type de sous-tâche" name="issueTypeId" isRequired>
                      {issueTypes.map((issueType) => (
                        <Option key={issueType.id} value={issueType.id} label={issueType.name} />
                      ))}
                    </Select>
                    <Select label="Assigné à" name="assignee" isRequired>
                      {users.map((user) => (
                        <Option key={user.id} value={user.id} label={user.displayName} />
                      ))}
                    </Select>
                    <Select label="Priorité" name="priority" isRequired>
                      {priorities.map((priority) => (
                        <Option key={priority.id} value={priority.id} label={priority.name} />
                      ))}
                    </Select>
                    <Button text="Créer" type="submit" isDisabled={isCreating} />
                  </Form>
                )}
              </Fragment>
            )}
  
            <Text content="**Tickets Enfants:**" />
            {filteredChildIssues.length === 0 && <Text>Aucun ticket enfant trouvé.</Text>}
            <Table>
              <Head>
                <Cell>
                  <Text>
                    <strong>Key</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Summary</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Status</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Assignee</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Priority</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Created</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Actions</strong>
                  </Text>
                </Cell>
              </Head>
              {filteredChildIssues.map((issue) => (
                <Row key={issue.id}>
                  <Cell>
                    <Text>
                      <Link href={`/browse/${issue.key}`}>{issue.key}</Link>
                    </Text>
                  </Cell>
                  <Cell>
                    <Text>{issue.fields.summary}</Text>
                  </Cell>
                  <Cell>
                    <Text>{issue.fields.status.name}</Text>
                  </Cell>
                  <Cell>
                    <Text>{issue.fields.assignee ? issue.fields.assignee.displayName : "Non assigné"}</Text>
                  </Cell>
                  <Cell>
                    <Text>{issue.fields.priority ? issue.fields.priority.name : "N/A"}</Text>
                  </Cell>
                  <Cell>
                    <Text>{new Date(issue.fields.created).toLocaleString()}</Text>
                  </Cell>
                  <Cell>
                    <Button text="🗑️" onClick={() => handleDeleteIssue(issue.key)} />
                    <Button text="Details" onClick={() => handleIssueClick(issue)} />
                    <Button text="🔄" onClick={() => setModalOpen(true)} />
                  </Cell>
                </Row>
              ))}
              
            </Table>
            {showConfirmationDialog && (
        <ModalDialog header="Confirm" onClose={cancelDeleteIssue}>
          <Text content={`Would you like to delete ticket ${issueToDelete} ?`} />
          <Button text="Yes" onClick={confirmDeleteIssue} />
          <Button text="No" onClick={cancelDeleteIssue} />
        </ModalDialog>
      )}
       {selectedIssue && (
                <ModalDialog header="Détails du ticket" onClose={closeIssueDetail}>
                    <Text content={`Key: ${selectedIssue.key}`} />
                    <Text content={`Summary: ${selectedIssue.fields.summary}`} />
                    <Text content={`Assignee: ${selectedIssue.fields.assignee ? selectedIssue.fields.assignee.displayName : "Unassigned"}`} />
                    <Text content={`Status: ${selectedIssue.fields.status.name}`} />
                    <Text content={`Priority: ${selectedIssue.fields.priority.name}`} />
                    <Text content={`Description: ${selectedIssue.fields.description ? selectedIssue.fields.description : "No description"}`} />
                    <Button text="Close" onClick={closeIssueDetail} />
                </ModalDialog>
            )}
         {isModalOpen && (
        <MoveSubtaskModal
          issueKey={issueKey}
          onClose={() => setModalOpen(false)}
          handleMoveSubtask={handleMoveSubtask}
        />
      )}
            {childIssues.length > PAGE_SIZE && (
              <Fragment>
                {Array.from({ length: Math.ceil(childIssues.length / PAGE_SIZE) }, (_, index) => (
                  <Button key={index + 1} text={index + 1} onClick={() => handlePageChange(index + 1, childIssues, setFilteredChildIssues)} style={{ marginRight: "5px" }} />
                ))}
              </Fragment>
            )}
            <Form onSubmit={(formData) => handleFilter(formData, childIssues, setFilteredChildIssues)}>
              <TextField name="query" label="Rechercher par Key, Summary, Status, Assignee" />
            </Form>
  
            <Fragment>
      {/* <Button text="Déplacer le sous-tâche" onClick={handleOpenModal} /> */}
      {/* {isModalOpen && <MoveSubtaskModal issueKey={issueKey} onClose={handleCloseModal} />} */}
    </Fragment>
            <Text content="**Tickets Liés:**" />
            {filteredLinkedIssues.length === 0 && <Text>Aucun ticket lié trouvé.</Text>}
            <Table>
              <Head>
                <Cell>
                  <Text>
                    <strong>Key</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Summary</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Status</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Assignee</strong>
                  </Text>
                </Cell>
                <Cell>
                  <Text>
                    <strong>Actions</strong>
                  </Text>
                </Cell>
              </Head>
              {filteredLinkedIssues.map((issue) => (
                <Row key={issue.id}>
                  <Cell>
                    <Text>
                      <Link href={`/browse/${issue.key}`}>{issue.key}</Link>
                    </Text>
                  </Cell>
                  <Cell>
                    <Text>{issue.fields.summary}</Text>
                  </Cell>
                  <Cell>
                    <Text>{issue.fields.status.name}</Text>
                  </Cell>
                  <Cell>
                    <Text>{issue.fields.assignee ? issue.fields.assignee.displayName : "Non assigné"}</Text>
                  </Cell>
                  <Cell>
                    <Button text="🗑️" onClick={() => handleDeleteIssue(issue.key)} />
                  </Cell>
                </Row>
              ))}
            </Table>
            {linkedIssues.length > PAGE_SIZE && (
              <Fragment>
                {Array.from({ length: Math.ceil(linkedIssues.length / PAGE_SIZE) }, (_, index) => (
                  <Button key={index + 1} text={index + 1} onClick={() => handlePageChange(index + 1, linkedIssues, setFilteredLinkedIssues)} style={{ marginRight: "5px" }} />
                ))}
              </Fragment>
            )}
            <Form onSubmit={(formData) => handleFilter(formData, linkedIssues, setFilteredLinkedIssues)}>
              <TextField name="query" label="Rechercher par Key, Summary, Status, Assignee" />
            </Form>
  
            {/* Links to JXL views */}
            <Text content="**View in JXL:**" />
          </Fragment>
        )}
      </Fragment>
    );
  };
  
  export const panel = render(
    <IssuePanel>
      <Panel />
    </IssuePanel>
  );
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.