Commit a2b3da27 by Tobias Skarhed Committed by GitHub

Migration: Create org (#22542)

* Add NewOrgPage

* Remove filrs

* Remove import

* Remove comments

* Get navModel from Redux

* Add DTO

* Get nav model from state

* Change error display

* Add async await and check if org is available

* Fix null strict null error

* Update public/app/features/org/NewOrgPage.tsx

Co-Authored-By: Dominik Prokop <dominik.prokop@grafana.com>

Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
parent f2742d4a
...@@ -16,9 +16,21 @@ export interface NavModelItem { ...@@ -16,9 +16,21 @@ export interface NavModelItem {
showOrgSwitcher?: boolean; showOrgSwitcher?: boolean;
} }
/**
* Interface used to describe different kinds of page titles and page navigation. Navmodels are usually generated in the backend and stored in Redux.
*/
export interface NavModel { export interface NavModel {
/**
* Main page. that wraps the navigation. Generate the `children` property generate tabs when used with the Page component.
*/
main: NavModelItem; main: NavModelItem;
/**
* This is the current active tab/navigation.
*/
node: NavModelItem; node: NavModelItem;
/**
* Describes breadcrumbs that are used in places such as data source settings., folder page and plugins page.
*/
breadcrumbs?: NavModelItem[]; breadcrumbs?: NavModelItem[];
} }
......
import angular from 'angular';
import config from 'app/core/config';
import { getBackendSrv } from '@grafana/runtime';
import { NavModelSrv } from 'app/core/core';
export class NewOrgCtrl {
/** @ngInject */
constructor($scope: any, $http: any, navModelSrv: NavModelSrv) {
$scope.navModel = navModelSrv.getNav('admin', 'global-orgs', 0);
$scope.newOrg = { name: '' };
$scope.createOrg = () => {
getBackendSrv()
.post('/api/orgs/', $scope.newOrg)
.then((result: any) => {
getBackendSrv()
.post('/api/user/using/' + result.orgId)
.then(() => {
window.location.href = config.appSubUrl + '/org';
});
});
};
}
}
angular.module('grafana.controllers').controller('NewOrgCtrl', NewOrgCtrl);
import React, { FC } from 'react';
import { getBackendSrv } from '@grafana/runtime';
import Page from 'app/core/components/Page/Page';
import { Forms } from '@grafana/ui';
import { getConfig } from 'app/core/config';
import { StoreState } from 'app/types';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import { NavModel } from '@grafana/data';
import { getNavModel } from '../../core/selectors/navModel';
const createOrg = async (newOrg: { name: string }) => {
const result = await getBackendSrv().post('/api/orgs/', newOrg);
await getBackendSrv().post('/api/user/using/' + result.orgId);
window.location.href = getConfig().appSubUrl + '/org';
};
const validateOrg = async (orgName: string) => {
try {
await getBackendSrv().get(`api/orgs/name/${encodeURI(orgName)}`);
} catch (error) {
if (error.status === 404) {
error.isHandled = true;
return true;
}
return 'Something went wrong';
}
return 'Organization already exists';
};
interface PropsWithState {
navModel: NavModel;
}
interface CreateOrgFormDTO {
name: string;
}
export const NewOrgPage: FC<PropsWithState> = ({ navModel }) => {
return (
<Page navModel={navModel}>
<Page.Contents>
<h3 className="page-sub-heading">New Organization</h3>
<p className="playlist-description">
Each organization contains their own dashboards, data sources and configuration, and cannot be shared between
orgs. While users may belong to more than one, multiple organization are most frequently used in multi-tenant
deployments.{' '}
</p>
<Forms.Form<CreateOrgFormDTO> onSubmit={createOrg}>
{({ register, errors }) => {
return (
<>
<Forms.Field
label="Organization name"
invalid={!!errors.name}
error={errors.name && errors.name.message}
>
<Forms.Input
size="md"
placeholder="Org. name"
name="name"
ref={register({
required: 'Organization name is required',
validate: async orgName => await validateOrg(orgName),
})}
/>
</Forms.Field>
<Forms.Button type="submit">Create</Forms.Button>
</>
);
}}
</Forms.Form>
</Page.Contents>
</Page>
);
};
const mapStateToProps = (state: StoreState) => {
return { navModel: getNavModel(state.navIndex, 'global-orgs') };
};
export default hot(module)(connect(mapStateToProps)(NewOrgPage));
import './SelectOrgCtrl'; import './SelectOrgCtrl';
import './NewOrgCtrl';
<page-header model="navModel"></page-header>
<div class="page-container page-body" ng-form="playlistEditForm">
<h3 class="page-sub-heading">
New Organization
</h3>
<p class="playlist-description">Each organization contains their own dashboards, data sources and configuration, and cannot be shared between orgs. While users may belong to more than one, multiple organization are most frequently used in multi-tenant deployments. </p>
<form>
<div class="gf-form-group">
<div class="gf-form">
<span class="gf-form-label width-10">Org. name</span>
<input type="text" ng-model="newOrg.name" required class="gf-form-input max-width-21" placeholder="organization name">
</div>
<br>
<div class="gf-form-buttons-row">
<button type="submit" class="btn btn-primary" ng-click="createOrg()">Create</button>
</div>
</div>
</form>
</div>
<footer />
...@@ -219,8 +219,10 @@ export function setupAngularRoutes($routeProvider: route.IRouteProvider, $locati ...@@ -219,8 +219,10 @@ export function setupAngularRoutes($routeProvider: route.IRouteProvider, $locati
}, },
}) })
.when('/org/new', { .when('/org/new', {
templateUrl: 'public/app/features/org/partials/newOrg.html', template: '<react-container />',
controller: 'NewOrgCtrl', resolve: {
component: () => SafeDynamicImport(import(/* webpackChunkName: "NewOrgPage" */ 'app/features/org/NewOrgPage')),
},
}) })
.when('/org/users', { .when('/org/users', {
template: '<react-container />', template: '<react-container />',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment