diff --git a/superset-frontend/src/pages/SavedQueryList/index.tsx b/superset-frontend/src/pages/SavedQueryList/index.tsx index a65e6bcdf0b05..40b3b766ee3f8 100644 --- a/superset-frontend/src/pages/SavedQueryList/index.tsx +++ b/superset-frontend/src/pages/SavedQueryList/index.tsx @@ -224,25 +224,33 @@ function SavedQueryList({ menuData.buttons = subMenuButtons; // Action methods - const openInSqlLab = (id: number, openInNewWindow: boolean) => { - if (openInNewWindow) { - window.open(`/sqllab?savedQueryId=${id}`); - } else { - history.push(`/sqllab?savedQueryId=${id}`); - } - }; - const copyQueryLink = useCallback( - (id: number) => { - copyTextToClipboard(() => - Promise.resolve(`${window.location.origin}/sqllab?savedQueryId=${id}`), - ) - .then(() => { - addSuccessToast(t('Link Copied!')); - }) - .catch(() => { - addDangerToast(t('Sorry, your browser does not support copying.')); + async (savedQuery: SavedQueryObject) => { + try { + const payload = { + dbId: savedQuery.db_id, + name: savedQuery.label, + schema: savedQuery.schema, + sql: savedQuery.sql, + autorun: false, + templateParams: null, + }; + + const response = await SupersetClient.post({ + endpoint: '/api/v1/sqllab/permalink', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload), }); + + const { key } = response.json; + const permalink = `${window.location.origin}/sqllab/p/${key}`; + + await navigator.clipboard.writeText(permalink); + addSuccessToast(t('Link Copied!')); + } catch (error) { + console.error('Error generating permalink:', error); + addDangerToast(t('There was an error generating the permalink.')); + } }, [addDangerToast, addSuccessToast], ); @@ -393,7 +401,7 @@ function SavedQueryList({ }; const handleEdit = ({ metaKey }: MouseEvent) => openInSqlLab(original.id, Boolean(metaKey)); - const handleCopy = () => copyQueryLink(original.id); + const handleCopy = () => copyQueryLink(original); const handleExport = () => handleBulkSavedQueryExport([original]); const handleDelete = () => setQueryCurrentlyDeleting(original); diff --git a/superset/queries/saved_queries/api.py b/superset/queries/saved_queries/api.py index 9246d7b98872d..7a089cfaa2b8c 100644 --- a/superset/queries/saved_queries/api.py +++ b/superset/queries/saved_queries/api.py @@ -23,11 +23,8 @@ from flask import g, request, Response, send_file from flask_appbuilder.api import expose, protect, rison, safe from flask_appbuilder.models.sqla.interface import SQLAInterface -from flask_appbuilder.security.decorators import has_access_api from flask_babel import ngettext -from sqlalchemy.exc import SQLAlchemyError -from superset import db, security_manager from superset.commands.importers.exceptions import ( IncorrectFormatError, NoValidFilesFoundError, @@ -202,99 +199,6 @@ def pre_update(self, item: SavedQuery) -> None: class SavedQueryRestApi(BaseSupersetModelRestApi): datamodel = SQLAInterface(SavedQuery) - @has_access_api - @expose("/", methods=["GET"]) - @protect() - @safe - @statsd_metrics - def get(self, pk: int, **kwargs: Any) -> Response: - """ - Retrieve a specific saved query. - - --- - get: - summary: Retrieve a specific saved query - description: > - Fetches the details of a saved query based on its primary key (ID). - The endpoint ensures that only the query owner or users with the - appropriate permissions ('can_read') can access the saved query. - parameters: - - in: path - name: pk - required: true - schema: - type: integer - description: The primary key (ID) of the saved query to retrieve. - responses: - 200: - description: Details of the saved query - content: - application/json: - schema: - type: object - properties: - database: - type: object - description: The database associated with the query. - result: - type: object - description: Details of the saved query. - 401: - $ref: '#/components/responses/401' - 403: - $ref: '#/components/responses/403' - 404: - $ref: '#/components/responses/404' - 500: - $ref: '#/components/responses/500' - """ - try: - saved_query = db.session.query(SavedQuery).get(pk) - if not saved_query: - return self.response_404() - - is_owner = saved_query.user_id == g.user.id - has_access = security_manager.can_access("can_read", "SavedQuery") - if not is_owner and not has_access: - return self.response_403() - - response_data = { - "database": { - "id": saved_query.db_id, - "database_name": saved_query.database.database_name - if saved_query.database - else None, - }, - "result": { - "id": saved_query.id, - "changed_on": saved_query.changed_on.isoformat() - if saved_query.changed_on - else None, - "database": { - "id": saved_query.db_id, - "database_name": saved_query.database.database_name - if saved_query.database - else None, - }, - "sql": saved_query.sql, - "label": saved_query.label, - "schema": saved_query.schema, - "description": saved_query.description, - **({"rows": saved_query.rows} if saved_query.rows else {}), - **( - {"last_run": saved_query.last_run.isoformat()} - if saved_query.last_run - else {} - ), - }, - } - - return self.response(200, **response_data) - - except SQLAlchemyError as ex: - logger.error("Error fetching saved query %s: %s", pk, ex) - return self.response_500() - @expose("/", methods=("DELETE",)) @protect() @safe