### Apache Airflow version

main (development)

### What happened

Currently `extra_links` is a cached property that returns a list without any order since set is used. Since we have 3 links per operator this order gets shuffled during webserver restarts as reported by users. It would be good to have this sorted so that the order is predictable. This is already done in extra_links Airflow API output

https://github.com/apache/airflow/blob/d7899ecfafb20cc58f8fb43e287d1c6778b8fa9f/airflow/models/abstractoperator.py#L470-L472

https://github.com/apache/airflow/blob/d7899ecfafb20cc58f8fb43e287d1c6778b8fa9f/airflow/api_connexion/endpoints/extra_link_endpoint.py#L75-L78

### What you think should happen instead

extra link order should be predictable

### How to reproduce

1. Create an operator with 3 or more extra links.
2. Render the links in UI. 
3. Restart the webserver and check the extra link order.

### Operating System

Ubuntu

### Versions of Apache Airflow Providers

_No response_

### Deployment

Other

### Deployment details

_No response_

### Anything else

_No response_

### Are you willing to submit PR?

- [X] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)

"""Return mapped task groups this task belongs to.
        Groups are returned from the innermost to the outmost.
        :meta private:
        """
        parent = self.task_group
        while parent is not None:
            if isinstance(parent, MappedTaskGroup):
                yield parent
            parent = parent.task_group
    def add_to_taskgroup(self, task_group: TaskGroup) -> None:
        """Add the task to the given task group.
        :meta private:
        """
        if self.node_id not in task_group.children:
            task_group.add(self)
    def get_closest_mapped_task_group(self) -> MappedTaskGroup | None:
        """Get the mapped task group "closest" to this task in the DAG.
        :meta private:
        """
        return next(self.iter_mapped_task_groups(), None)
    def unmap(self, resolve: None | dict[str, Any] | tuple[Context, Session]) -> BaseOperator:
        """Get the "normal" operator from current abstract operator.
        MappedOperator uses this to unmap itself based on the map index. A non-
        mapped operator (i.e. BaseOperator subclass) simply returns itself.
        :meta private:
        """
        raise NotImplementedError()
    @property
    def priority_weight_total(self) -> int: