mirror of https://github.com/grafana/grafana.git
ShortURL: Use RTK Query with the new k8s api (#111261)
This commit is contained in:
parent
c97a7bc2ce
commit
0ab7488305
|
|
@ -19,6 +19,20 @@ jest.mock('@grafana/runtime', () => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('app/store/store', () => ({
|
||||||
|
dispatch: jest.fn((action) => {
|
||||||
|
// Return the mocked result directly
|
||||||
|
return Promise.resolve({
|
||||||
|
data: {
|
||||||
|
metadata: {
|
||||||
|
name: 'bewyw48durgu8d',
|
||||||
|
namespace: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
Object.assign(navigator, {
|
Object.assign(navigator, {
|
||||||
clipboard: {
|
clipboard: {
|
||||||
|
|
@ -29,6 +43,9 @@ beforeEach(() => {
|
||||||
|
|
||||||
document.execCommand = jest.fn();
|
document.execCommand = jest.fn();
|
||||||
config.featureToggles.useKubernetesShortURLsAPI = false;
|
config.featureToggles.useKubernetesShortURLsAPI = false;
|
||||||
|
|
||||||
|
// Clear any caches between tests
|
||||||
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createShortLink', () => {
|
describe('createShortLink', () => {
|
||||||
|
|
@ -40,9 +57,19 @@ describe('createShortLink', () => {
|
||||||
|
|
||||||
describe('createShortLink using k8s API', () => {
|
describe('createShortLink using k8s API', () => {
|
||||||
it('creates short link', async () => {
|
it('creates short link', async () => {
|
||||||
|
// Mock window.location for k8s API test
|
||||||
|
const mockLocation = {
|
||||||
|
protocol: 'https:',
|
||||||
|
host: 'www.test.grafana.com',
|
||||||
|
};
|
||||||
|
Object.defineProperty(window, 'location', {
|
||||||
|
value: mockLocation,
|
||||||
|
writable: true,
|
||||||
|
});
|
||||||
|
|
||||||
config.featureToggles.useKubernetesShortURLsAPI = true;
|
config.featureToggles.useKubernetesShortURLsAPI = true;
|
||||||
const shortUrl = await createShortLink('d/edhmipji89b0gb/welcome?orgId=1&from=now-6h&to=now&timezone=browser');
|
const shortUrl = await createShortLink('d/edhmipji89b0gb/welcome?orgId=1&from=now-6h&to=now&timezone=browser');
|
||||||
expect(shortUrl).toBe('www.test.grafana.com/goto/bewyw48durgu8d?orgId=1');
|
expect(shortUrl).toBe('https://www.test.grafana.com/goto/bewyw48durgu8d?orgId=1');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import { getDashboardUrl } from 'app/features/dashboard-scene/utils/getDashboard
|
||||||
import { dispatch } from 'app/store/store';
|
import { dispatch } from 'app/store/store';
|
||||||
|
|
||||||
import { ShortURL } from '../../../../apps/shorturl/plugin/src/generated/shorturl/v1alpha1/shorturl_object_gen';
|
import { ShortURL } from '../../../../apps/shorturl/plugin/src/generated/shorturl/v1alpha1/shorturl_object_gen';
|
||||||
import { BASE_URL as k8sShortURLBaseAPI } from '../../api/clients/shorturl/v1alpha1/baseAPI';
|
import { generatedAPI } from '../../api/clients/shorturl/v1alpha1/endpoints.gen';
|
||||||
|
import { extractErrorMessage } from '../../api/utils';
|
||||||
import { ShareLinkConfiguration } from '../../features/dashboard-scene/sharing/ShareButton/utils';
|
import { ShareLinkConfiguration } from '../../features/dashboard-scene/sharing/ShareButton/utils';
|
||||||
|
|
||||||
import { copyStringToClipboard } from './explore';
|
import { copyStringToClipboard } from './explore';
|
||||||
|
|
@ -32,30 +33,48 @@ function getRelativeURLPath(url: string) {
|
||||||
return path.startsWith('/') ? path.substring(1, path.length) : path;
|
return path.startsWith('/') ? path.substring(1, path.length) : path;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createShortLink = memoizeOne(async function (path: string) {
|
// Memoized legacy API call - preserves original behavior
|
||||||
try {
|
const createShortLinkLegacy = memoizeOne(async (path: string): Promise<string> => {
|
||||||
if (config.featureToggles.useKubernetesShortURLsAPI) {
|
|
||||||
// TODO: this is not ideal, we should use the RTK API but we can't call a hook from here and
|
|
||||||
// this util function is being called from several places, will require a bigger refactor including some code that
|
|
||||||
// is deprecated.
|
|
||||||
const k8sShortUrl: ShortURL = await getBackendSrv().post(`${k8sShortURLBaseAPI}/shorturls`, {
|
|
||||||
spec: {
|
|
||||||
path: getRelativeURLPath(path),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return buildShortUrl(k8sShortUrl);
|
|
||||||
} else {
|
|
||||||
// Old short URL API
|
|
||||||
const shortLink = await getBackendSrv().post(`/api/short-urls`, {
|
const shortLink = await getBackendSrv().post(`/api/short-urls`, {
|
||||||
path: getRelativeURLPath(path),
|
path: getRelativeURLPath(path),
|
||||||
});
|
});
|
||||||
return shortLink.url;
|
return shortLink.url;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createShortLink = async function (path: string) {
|
||||||
|
try {
|
||||||
|
if (config.featureToggles.useKubernetesShortURLsAPI) {
|
||||||
|
// Use RTK API - it handles caching/failures/retries automatically
|
||||||
|
const result = await dispatch(
|
||||||
|
generatedAPI.endpoints.createShortUrl.initiate({
|
||||||
|
shortUrl: {
|
||||||
|
spec: {
|
||||||
|
path: getRelativeURLPath(path),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if ('data' in result && result.data) {
|
||||||
|
return buildShortUrl(result.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('error' in result) {
|
||||||
|
const errorMessage = extractErrorMessage(result.error);
|
||||||
|
throw new Error(errorMessage || 'Failed to create short URL');
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Failed to create short URL');
|
||||||
|
} else {
|
||||||
|
// Old API - use memoized function (preserves original behavior)
|
||||||
|
return await createShortLinkLegacy(path);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error when creating shortened link: ', err);
|
console.error('Error when creating shortened link: ', err);
|
||||||
dispatch(notifyApp(createErrorNotification('Error generating shortened link')));
|
dispatch(notifyApp(createErrorNotification('Error generating shortened link')));
|
||||||
|
throw err; // Re-throw so callers know it failed
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a ClipboardItem for the shortened link. This is used due to clipboard issues in Safari after making async calls.
|
* Creates a ClipboardItem for the shortened link. This is used due to clipboard issues in Safari after making async calls.
|
||||||
|
|
@ -70,17 +89,18 @@ const createShortLinkClipboardItem = (path: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createAndCopyShortLink = async (path: string) => {
|
export const createAndCopyShortLink = async (path: string) => {
|
||||||
|
try {
|
||||||
if (typeof ClipboardItem !== 'undefined' && navigator.clipboard.write) {
|
if (typeof ClipboardItem !== 'undefined' && navigator.clipboard.write) {
|
||||||
navigator.clipboard.write([createShortLinkClipboardItem(path)]);
|
await navigator.clipboard.write([createShortLinkClipboardItem(path)]);
|
||||||
dispatch(notifyApp(createSuccessNotification('Shortened link copied to clipboard')));
|
dispatch(notifyApp(createSuccessNotification('Shortened link copied to clipboard')));
|
||||||
} else {
|
} else {
|
||||||
const shortLink = await createShortLink(path);
|
const shortLink = await createShortLink(path);
|
||||||
if (shortLink) {
|
|
||||||
copyStringToClipboard(shortLink);
|
copyStringToClipboard(shortLink);
|
||||||
dispatch(notifyApp(createSuccessNotification('Shortened link copied to clipboard')));
|
dispatch(notifyApp(createSuccessNotification('Shortened link copied to clipboard')));
|
||||||
} else {
|
|
||||||
dispatch(notifyApp(createErrorNotification('Error generating shortened link')));
|
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// createShortLink already handles error notifications, just log
|
||||||
|
console.error('Error in createAndCopyShortLink:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue