mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			137 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
| import getDefaultMonacoLanguages from 'lib/monaco-languages';
 | |
| import { useState } from 'react';
 | |
| import { useAsync } from 'react-use';
 | |
| import SwaggerUI from 'swagger-ui-react';
 | |
| 
 | |
| import { createTheme, monacoLanguageRegistry, SelectableValue } from '@grafana/data';
 | |
| import { Trans } from '@grafana/i18n';
 | |
| import { Stack, Select, UserIcon, UserView, Button } from '@grafana/ui';
 | |
| import { setMonacoEnv } from 'app/core/monacoEnv';
 | |
| import { ThemeProvider } from 'app/core/utils/ConfigProvider';
 | |
| import grafanaIconSvg from 'img/grafana_icon.svg';
 | |
| 
 | |
| import { NamespaceContext, WrappedPlugins } from './plugins';
 | |
| 
 | |
| export const Page = () => {
 | |
|   const theme = createTheme({ colors: { mode: 'light' } });
 | |
|   const [url, setURL] = useState<SelectableValue<string>>();
 | |
|   const urls = useAsync(async () => {
 | |
|     const v2 = { label: 'Grafana API (OpenAPI v2)', key: 'openapi2', value: 'public/api-merged.json' };
 | |
|     const v3 = { label: 'Grafana API (OpenAPI v3)', key: 'openapi3', value: 'public/openapi3.json' };
 | |
|     const urls: Array<SelectableValue<string>> = [v2, v3];
 | |
| 
 | |
|     const rsp = await fetch('openapi/v3');
 | |
|     const apis = await rsp.json();
 | |
|     for (const [key, val] of Object.entries<any>(apis.paths)) {
 | |
|       const parts = key.split('/');
 | |
|       if (parts.length === 3) {
 | |
|         urls.push({
 | |
|           key: `${parts[1]}-${parts[2]}`,
 | |
|           label: `${parts[1]}/${parts[2]}`,
 | |
|           value: val.serverRelativeURL.substring(1), // remove initial slash
 | |
|         });
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     let idx = 0;
 | |
|     const urlParams = new URLSearchParams(window.location.search);
 | |
|     const api = urlParams.get('api');
 | |
|     if (api) {
 | |
|       urls.forEach((url, i) => {
 | |
|         if (url.key === api) {
 | |
|           idx = i;
 | |
|         }
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     monacoLanguageRegistry.setInit(getDefaultMonacoLanguages);
 | |
|     setMonacoEnv();
 | |
| 
 | |
|     setURL(urls[idx]); // Remove to start at the generic landing page
 | |
|     return urls;
 | |
|   });
 | |
| 
 | |
|   const [userView, setUserView] = useState<UserView>();
 | |
| 
 | |
|   const namespace = useAsync(async () => {
 | |
|     const response = await fetch('api/frontend/settings');
 | |
|     if (!response.ok) {
 | |
|       console.warn('No settings found');
 | |
|       return 'default';
 | |
|     }
 | |
|     const val = await response.json();
 | |
|     return val.namespace;
 | |
|   });
 | |
| 
 | |
|   useAsync(async () => {
 | |
|     const response = await fetch('api/user');
 | |
|     if (!response.ok) {
 | |
|       console.warn('No user found, show login button');
 | |
|       return;
 | |
|     }
 | |
|     const val = await response.json();
 | |
|     setUserView({
 | |
|       user: {
 | |
|         name: val.email || val.login,
 | |
|         avatarUrl: val.avatarUrl,
 | |
|       },
 | |
|       lastActiveAt: new Date(),
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   return (
 | |
|     <div>
 | |
|       <ThemeProvider value={theme}>
 | |
|         <NamespaceContext.Provider value={namespace.value}>
 | |
|           <div style={{ backgroundColor: '#000', padding: '10px' }}>
 | |
|             <Stack justifyContent={'space-between'}>
 | |
|               <img height="40" src={grafanaIconSvg} alt="Grafana" />
 | |
|               <Select
 | |
|                 options={urls.value}
 | |
|                 isClearable={false /* TODO -- when we allow a landing page, this can be true */}
 | |
|                 onChange={(v) => {
 | |
|                   const url = new URL(window.location.href);
 | |
|                   url.hash = '';
 | |
|                   if (v?.key) {
 | |
|                     url.searchParams.set('api', v.key);
 | |
|                   } else {
 | |
|                     url.searchParams.delete('api');
 | |
|                   }
 | |
|                   window.history.pushState(null, '', url);
 | |
|                   setURL(v);
 | |
|                 }}
 | |
|                 value={url}
 | |
|                 isLoading={urls.loading}
 | |
|               />
 | |
|               <div style={{ marginTop: '5px' }}>
 | |
|                 {userView ? (
 | |
|                   <UserIcon userView={userView} />
 | |
|                 ) : (
 | |
|                   <a href="/login">
 | |
|                     <Button variant="primary">
 | |
|                       <Trans i18nKey="swagger.login">Login</Trans>
 | |
|                     </Button>
 | |
|                   </a>
 | |
|                 )}
 | |
|               </div>
 | |
|             </Stack>
 | |
|           </div>
 | |
| 
 | |
|           {url?.value && (
 | |
|             <SwaggerUI
 | |
|               url={url.value}
 | |
|               presets={[WrappedPlugins]}
 | |
|               deepLinking={true}
 | |
|               tryItOutEnabled={true}
 | |
|               queryConfigEnabled={false}
 | |
|               persistAuthorization={false}
 | |
|               displayOperationId
 | |
|             />
 | |
|           )}
 | |
|           {!url?.value && <div>...{/** TODO, we can make an api docs loading page here */}</div>}
 | |
|         </NamespaceContext.Provider>
 | |
|       </ThemeProvider>
 | |
|     </div>
 | |
|   );
 | |
| };
 |