console code refactor (#1688)

* Removed duplicate css
* Reorganised common code
This commit is contained in:
Rikin Kachhia 2019-03-06 17:00:25 +05:30 committed by GitHub
parent c35753932f
commit 06afb75f4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
138 changed files with 3410 additions and 4413 deletions

View File

@ -16,7 +16,7 @@ import {
} from './src/components/Services/Data/DataActions';
// import Event Tab parts
import eventRouter from './src/components/Services/EventTrigger/EventRouter';
import eventRouterUtils from './src/components/Services/EventTrigger/EventRouter';
import { eventReducer } from './src/components/Services/EventTrigger';
// import Remote Schema parts
@ -31,8 +31,8 @@ import mainState from './src/components/Main/State';
import { changeRequestHeader } from './src/components/ApiExplorer/Actions';
import { validateLogin } from './src/components/Main/Actions';
const filterQueryScss = require('./src/components/Services/Data/TableBrowseRows/FilterQuery.scss');
const tableScss = require('./src/components/Services/Data/TableCommon/Table.scss');
const filterQueryScss = require('./src/components/Common/FilterQuery/FilterQuery.scss');
const tableScss = require('./src/components/Common/TableCommon/Table.scss');
// export GraphiQL parts
export { GraphiQLWrapper };
@ -44,7 +44,7 @@ export { UPDATE_CURRENT_SCHEMA, UPDATE_DATA_HEADERS, ACCESS_KEY_ERROR };
export { dataHeaders };
// export Event Tab parts
export { eventRouter, eventReducer };
export { eventRouterUtils, eventReducer };
// export Remote Schema parts
export { getCustomResolverRouter, customResolverReducer };

View File

@ -13204,9 +13204,9 @@
"integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
},
"prettier": {
"version": "1.14.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz",
"integrity": "sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg=="
"version": "1.16.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz",
"integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g=="
},
"pretty-error": {
"version": "1.2.0",

View File

@ -69,7 +69,7 @@
"match-sorter": "^2.3.0",
"multireducer": "^1.0.2",
"piping": "^0.3.0",
"prettier": "^1.13.0",
"prettier": "^1.16.4",
"pretty-error": "^1.2.0",
"prop-types": "^15.6.0",
"query-string": "^6.1.0",

View File

@ -8,7 +8,8 @@ import Helmet from 'react-helmet';
class PageNotFound extends Component {
render() {
const lostImage = require('./404-logo.png');
const styles = require('./Styles.scss');
const styles = require('./PageNotFound.scss');
return (
<div className={styles.viewcontainer}>
<Helmet title="404 - Page Not Found | Hasura" />

View File

@ -14,13 +14,16 @@
.message {
padding: 50px 20%;
}
.message h1 {
font-size: 54px;
font-weight: bold;
}
.message p {
margin-left: 15px;
}
.message p > a {
font-weight: bold;
}
@ -29,12 +32,14 @@
.header {
background: #eee;
h2 {
margin: 0;
padding: 26px;
float: left;
line-height: 26px;
}
.nav {
padding: 20px;
float: left;

View File

@ -1,64 +1,73 @@
@import "../Common/Common.scss";
.display_inl {
display: inline-block;
}
.width_80 {
width: 80%;
}
.responseHeader
{
.responseHeader {
color: #788095;
font-weight: bold;
font-size: 14px;
}
.admin_token_align {
vertical-align: middle;
margin-left: 2px;
}
.marginBottom
{
.marginBottom {
margin-bottom: 15px;
}
.apiExplorerMini {
width: 80%;
}
.wrapperOnBoarding {
// width: 80% !important;
}
.panelGreyed {
opacity: 0.1;
}
.requestGreyed {
opacity: 0.1;
}
.panelInFocus {
}
.requestInFocus {
}
.cursorNotAllowed {
cursor: not-allowed;
}
.apiExplorerWrapper
{
.apiExplorerWrapper {
display: flex;
height: $mainContainerHeight;
.ApiRequestWrapperVH
{
.ApiRequestWrapperVH {
height: 100%;
width: 100%;
}
.apiCollectionWrapper
{
.apiCollectionWrapper {
background-color: #fff;
height: 100%;
overflow-y: auto;
// Changed it from overfllow-y: scroll
.apiCollectionTabWrapper
{
.apiCollectionTab
{
.apiCollectionTabWrapper {
.apiCollectionTab {
-webkit-padding-start: 0px;
-webkit-margin-before: 0;
-webkit-margin-after: 0;
@ -71,8 +80,8 @@
min-width: 240px;
background-color: #fff;
z-index: 10;
.apiCollectionTabList
{
.apiCollectionTabList {
list-style-type: none;
display: inline-block;
width: 50%;
@ -83,18 +92,18 @@
color: #D8D8D8;
cursor: pointer;
}
.activeApiCollectionTab
{
.activeApiCollectionTab {
border-bottom: 3px solid #ffca27;
color: #6B6B6B;
}
.apiCollectionTabList:focus
{
.apiCollectionTabList:focus {
outline: none;
}
}
.apiCollectionClearHistory
{
.apiCollectionClearHistory {
padding: 0 15px;
margin: 0;
border-bottom: 1px solid #e5e5e5;
@ -103,8 +112,8 @@
bottom: 0;
transform: translateX(-88%);
*/
.apiCollectionClearHistoryButton
{
.apiCollectionClearHistoryButton {
/*
float: right;
margin: 10px 0;
@ -121,126 +130,127 @@
border-top: 1px solid #ccc;
background-color: #fff;
z-index: 1;
i {
padding-right: 5px;
}
}
}
.apiPaddTop
{
.apiPaddTop {
padding-top: 46px !important;
}
.apiCollectionTabListDetails
{
.apiCollectionTabListDetails {
padding: 0 15px;
margin: 10px 0;
// padding-top: 46px;
.apiCollectionTabListHead
{
.apiCollectionTabListHead {
padding-left: 15px;
padding-bottom: 10px;
font-weight: bold;
font-size: 15px;
.serviceBaseDomain {
color: #bbb;
}
}
.add_ellipsis {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.apiCollectionGetPost
{
.apiCollectionGetWrapper
{
.apiCollectionGetPost {
.apiCollectionGetWrapper {
padding: 5px 0;
cursor: pointer;
.apiCollectionGet
{
.apiCollectionGet {
text-align: left;
color: #70CD00;
font-size: 12px;
font-weight: bold;
padding-left: 15px;
}
.apiCollectionGetDetailsWrapper
{
.apiCollectionGetDetailsWrapper {
display: flex;
align-items: center;
.apiCollectionGetDetails
{
.apiCollectionGetDetails {
word-wrap: break-word;
padding-right: 10px !important
}
.apiCollectionPostDetails
{
.apiCollectionPostDetails {
word-wrap: break-word;
padding-right: 10px !important
}
.apiRightArrowWrapper
{
.apiRightArrowWrapper {
padding-left: 5px;
}
}
.activeApiCollectionGetWrapperIcon
{
.activeApiCollectionGetWrapperIcon {
display: none;
}
}
.activeApiCollectionGetWrapper
{
.activeApiCollectionGetWrapper {
background-color: #FFF3D5;
border-radius: 4px;
.activeApiCollectionGetWrapperIcon
{
.activeApiCollectionGetWrapperIcon {
display: block;
}
}
.apiCollectionPostWrapper
{
.apiCollectionPostWrapper {
padding: 5px 0;
cursor: pointer;
.apiCollectionPost
{
.apiCollectionPost {
text-align: left;
color: #FD9540;
font-size: 12px;
font-weight: bold;
padding-left: 15px;
}
.apiCollectionGetDetailsWrapper
{
.apiCollectionGetDetailsWrapper {
display: flex;
align-items: center;
.apiCollectionGetDetails
{
.apiCollectionGetDetails {
word-wrap: break-word;
padding-right: 10px !important
}
.apiCollectionPostDetails
{
.apiCollectionPostDetails {
word-wrap: break-word;
padding-right: 10px !important
}
.apiRightArrowWrapper
{
.apiRightArrowWrapper {
padding-left: 5px;
}
}
.activeApiCollectionGetWrapperIcon
{
.activeApiCollectionGetWrapperIcon {
display: none;
}
}
.activeApiCollectionGetWrapper
{
.activeApiCollectionGetWrapper {
background-color: #FFF3D5;
border-radius: 4px;
.activeApiCollectionGetWrapperIcon
{
.activeApiCollectionGetWrapperIcon {
display: block;
}
}
@ -248,11 +258,13 @@
}
}
}
.apiContentPadd {
padding-top: 20px;
// padding-bottom: 10px;
// margin-bottom: -15px;
}
.closeHeader {
cursor: pointer;
padding-top: 8px;
@ -260,6 +272,7 @@
float: right;
display: inline-block;
}
.showAdminSecret {
cursor: pointer;
padding-top: 8px;
@ -268,8 +281,8 @@
float: left;
display: inline-block;
}
.apiRequestWrapper
{
.apiRequestWrapper {
.file_upload_wrapper {
width: 100%;
text-align: left;
@ -278,55 +291,55 @@
border: 1px solid #ccc;
background-color: #fff;
margin-bottom: 15px;
input[type="file"] {
display: inline-block;
width: 162px;
}
}
.apiRequestheader
{
.apiRequestheader {
font-weight: bold;
font-size: 18px;
padding-bottom: 10px;
color: #000;
}
.apiRequestContent
{
.apiRequestContent {
font-size: 14px;
a
{
a {
color: #FEC53D;
text-decoration: underline;
}
a:hover
{
a:hover {
color: #FEC53D;
text-decoration: underline;
}
code
{
code {
background-color: transparent;
border: 1px solid #767E93;
padding: 1px 4px !important;
color: #767E93;
}
}
.apiPostRequestWrapper
{
.apiPostRequestWrapper {
// padding: 20px 0;
// padding-top: 20px;
padding-top: 5px;
background-color: #f8fafb;
.inputGroupWrapper
{
.inputGroupWrapper {
-webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
border-radius: 5px;
.inputGroupBtn
{
button
{
.inputGroupBtn {
button {
width: 100px;
border: 0;
padding: 10px 12px;
@ -335,16 +348,16 @@
font-size: 14px;
font-weight: bold;
text-align: left;
.caret
{
.caret {
position: absolute;
right: 10px;
top: 16px;
}
}
}
.inputGroupInput
{
.inputGroupInput {
border: 0;
box-shadow: none;
padding: 10px 12px;
@ -352,10 +365,9 @@
background-color: #fff;
}
}
.sendBtn
{
button
{
.sendBtn {
button {
width: 100%;
text-align: center;
height: 39px;
@ -372,18 +384,17 @@
background-color: #F2B130;
}
}
/*
button:hover
{
button:hover {
border: 1px solid #F2B130;
background-color: #F2B130;
}
*/
}
.generateBtn
{
button
{
.generateBtn {
button {
width: 100%;
background-color: transparent;
text-align: center;
@ -393,97 +404,97 @@
font-weight: bold;
border-radius: 5px;
}
button:hover
{
button:hover {
border: 1px solid #606060;
background-color: #efefef;
}
}
}
.responseWrapper
{
.responseWrapper {
clear: both;
display: flex;
align-items: center;
.responseHeader
{
.responseHeader {
color: #788095;
font-weight: bold;
font-size: 14px;
.viewDetails
{
.viewDetails {
padding-left: 10px;
font-weight: normal;
color: #FFCA27;
}
.addAdminToken
{
.addAdminToken {
text-align: right;
padding-left: 15px;
}
}
.addAdminToken
{
.addAdminToken {
text-align: right;
padding-left: 15px;
}
}
}
.apiResponseWrapper
{
.apiResponseheaderWrapper
{
.apiResponseWrapper {
.apiResponseheaderWrapper {
border-bottom: 1px solid #ccc;
margin-bottom: 20px;
.apiResponseheader
{
.apiResponseheader {
font-weight: bold;
font-size: 14px;
padding-bottom: 10px;
// color: #000;
color: #788095
}
.statusDetails
{
.statusDetails {
display: inline-block;
float: right;
padding-left: 20px;
.statusView
{
.statusView {
padding-left: 5px;
font-weight: normal;
color: #FFCA27;
}
}
}
.helpTextWrapper
{
.helpTextWrapper {
padding: 15px;
border: 1px solid #ccc;
background-color: #fff;
clear: both;
margin-bottom: 20px;
i
{
i {
padding-right: 10px;
}
pre
{
pre {
margin-top: 10px;
border-radius: 0;
}
.copyBtn
{
.copyBtn {
padding: 9px;
}
}
.suggestionTextColor {
color: #111;
background-color: #ffd760;
border-color: #ffd760;
}
.noResponseWrapper
{
.noResponseWrapper {
width: 100%;
min-height: 200px;
background-color: #fff;
@ -495,20 +506,20 @@
align-items: center;
justify-content: center;
margin-bottom: 20px;
.noResponseContainer
{
.noResponseContainer {
width: 325px;
.noResponseHeader
{
.noResponseHeader {
font-size: 18px;
opacity: 0.6;
}
.barWrapper
{
.barWrapper {
padding-top: 15px;
text-align: center;
.bigBar
{
.bigBar {
width: 56%;
margin-right: 7px;
height: 20px;
@ -516,8 +527,8 @@
display: inline-block;
border-radius: 4px;
}
.mediumBar
{
.mediumBar {
width: 23%;
margin-right: 7px;
height: 20px;
@ -525,8 +536,8 @@
display: inline-block;
border-radius: 4px;
}
.smallBar
{
.smallBar {
width: 13%;
margin-right: 7px;
height: 20px;
@ -537,15 +548,15 @@
}
}
}
.responseHeader
{
.responseHeader {
padding-top: 15px;
color: #788095;
font-weight: bold;
font-size: 14px;
clear: both;
.viewDetails
{
.viewDetails {
padding-left: 10px;
font-weight: normal;
color: #FFCA27;
@ -555,35 +566,30 @@
}
// Common
.responseTable
{
.responseTable {
padding-top: 15px;
.tableBorder
{
.tableBorder {
background-color: #fff;
border: 1px solid #E3E5E5;
thead
{
tr
{
th
{
thead {
tr {
th {
border-bottom: 0px;
}
}
}
tbody
{
tr
{
td
{
tbody {
tr {
td {
border-top: 0;
// padding: 5px;
padding: 0px 5px;
min-width: 50px;
.responseTableInput
{
.responseTableInput {
background-color: transparent;
border: 0;
box-shadow: none;
@ -591,49 +597,50 @@
// padding: 0;
}
}
.headerPadd {
padding: 15px !important;
}
.borderTop
{
.borderTop {
border-top: 1px solid #ccc;
}
.tableTdLeft
{
.tableTdLeft {
padding-left: 5%;
}
.tableEnterKey
{
.tableEnterKey {
// padding: 10px 0;
padding: 0px 5px;
padding-left: 4.5%;
}
.tableLastTd
{
.tableLastTd {
padding-left: 5px !important;
}
}
}
}
.headerHeading {
background-color: #f5f5f5;
font-weight: bold;
padding-left: 15px;
}
}
.queryBuilderWrapper
{
.queryBuilderWrapper {
padding-bottom: 20px;
.queryBuilderTab
{
ul
{
.queryBuilderTab {
ul {
border: 1px solid #E7E7E7;
-webkit-padding-start: 0px;
-moz-padding-start: 0px;
display: inline-block;
li
{
li {
list-style-type: none;
display: inline-block;
padding: 12px 20px;
@ -644,19 +651,19 @@
background-color: #fff;
font-weight: bold;
}
li:focus
{
li:focus {
outline: none;
}
.activeQueryBuilderTab
{
.activeQueryBuilderTab {
background-color: #FFF050;
}
}
}
}
.AceEditorWrapper
{
.AceEditorWrapper {
-webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
@ -671,6 +678,7 @@
background-color: #fff;
// padding: 15px;
}
.queryBuilderLayoutSub {
padding: 20px;
}
@ -680,18 +688,18 @@
padding-top: 15px;
padding-left: 20px;
padding-bottom: 15px;
i {
padding-left: 5px;
}
}
.common_checkbox
{
.common_checkbox {
opacity: 0;
position: absolute;
.common_checkbox_label
{
.common_checkbox_label {
display: inline-block;
vertical-align: middle;
margin: 0px;
@ -700,13 +708,13 @@
position: relative;
}
}
.common_checkbox_label
{
.common_checkbox_label {
margin-bottom: 0px !important;
padding-top: 5px;
}
.common_checkbox + .common_checkbox_label:before
{
.common_checkbox + .common_checkbox_label:before {
content: '';
background: #fff;
border: 1px solid #ddd;
@ -720,12 +728,12 @@
border-radius:4px;
cursor:pointer;
}
label
{
label {
font-weight: normal;
}
.common_checkbox:checked + .common_checkbox_label:before
{
.common_checkbox:checked + .common_checkbox_label:before {
content: url('./tick.png');
background: #FFCA27;
color: #fff;
@ -741,12 +749,14 @@ label
.apiResponseTab {
padding-top: 20px;
.apiResponseTabUl {
display: inline-block;
-webkit-padding-start: 0px;
-webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);
.apiResponseTabList {
display: inline-block;
padding: 15px 25px;
@ -756,13 +766,16 @@ label
color: #6B6B6B;
cursor: pointer;
}
.apiResponseTabList:focus {
outline: none;
}
.activeApiResponseTab {
background-color: #FFF3D5
}
}
.apiResponseTabPanel {
.AceEditorWrapper {
margin-top: 15px;

View File

@ -5,9 +5,9 @@ import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import CopyToClipboard from 'react-copy-to-clipboard';
import generateSuggestionBox from '../Common/generateSuggestionBox';
import generateSuggestionBox from './generateSuggestionBox';
import suggestionFunction from './suggestionFunctions';
import suggestionFunctions from './suggestionFunctions';
class ApiResponse extends React.Component {
constructor() {
@ -17,6 +17,7 @@ class ApiResponse extends React.Component {
tabIndex: 0,
};
}
render() {
const {
categoryType,
@ -25,16 +26,20 @@ class ApiResponse extends React.Component {
response,
url,
} = this.props;
const getSuggestionFunction = suggestionFunction[categoryType];
const styles = require('./ApiExplorer.scss');
const suggestionFunction = suggestionFunctions[categoryType];
const isResponseError =
'statusCode' in response ? response.statusCode !== 200 : false;
const responseHtml =
isResponseError && getSuggestionFunction
? generateSuggestionBox(response, getSuggestionFunction)
isResponseError && suggestionFunction
? generateSuggestionBox(response, suggestionFunction)
: '';
const styles = require('./ApiExplorer.scss');
const imgHTMLTag = `<img src='${url}' />`;
let formattedResponse = JSON.stringify(response.response, null, 4);
let responseMode = 'json';
let showGutter = true;
@ -49,6 +54,7 @@ class ApiResponse extends React.Component {
const getHeaders = responseHeader => {
const currHeaders = [];
if (responseHeader.responseHeaders) {
responseHeader.responseHeaders.forEach((value, name) => {
currHeaders.push(
@ -69,6 +75,7 @@ class ApiResponse extends React.Component {
);
});
}
return currHeaders.length > 0 ? currHeaders : '';
};
@ -103,7 +110,9 @@ class ApiResponse extends React.Component {
''
)}
</div>
{responseHtml}
{showHelpBulb ? (
<div className={styles.helpTextWrapper}>
<i className="fa fa-lightbulb-o" aria-hidden="true" />

View File

@ -1,6 +1,6 @@
import React from 'react';
const styles = require('../ApiExplorer/ApiExplorer.scss');
const styles = require('./ApiExplorer.scss');
const generateSuggestionBox = (response, parseFunc) => {
const suggestionText = parseFunc(response);

View File

@ -1,5 +1,4 @@
.alertDanger
{
.alertDanger {
position: sticky;
position: -webkit-sticky;
position: -moz-sticky;
@ -8,17 +7,20 @@
top: 0;
z-index: 1000;
}
.notifModalDialog {
width: 800px;
margin: 30px auto;
right: 100px;
top: -15px;
}
:global {
@keyframes react-progress-spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
@ -33,9 +35,11 @@
opacity: 1;
transition: all 400ms;
z-index: 9999;
&.react-progress-bar-on-top {
height: 100%;
}
&.react-progress-bar-hide {
opacity: 0;
visibility: hidden;

View File

@ -1,14 +0,0 @@
import React, { Component } from 'react';
class BreadCrumb extends Component {
render() {
const styles = require('./BreadCrumb.scss');
return <div className={styles.breadcrumbWrapper}>{this.props.data}</div>;
}
}
BreadCrumb.propTypes = {
data: React.PropTypes.string.isRequired,
};
export default BreadCrumb;

View File

@ -1,9 +0,0 @@
@import "../Common.scss";
.breadcrumbWrapper {
padding: 20px 0px;
padding-bottom: 0px;
font-size: 16px;
font-weight: 400;
color: #767E93;
}

View File

@ -1,4 +1,5 @@
@import "./Common.scss";
button.control {
width: 100%;
}
@ -28,10 +29,10 @@ table td.longOne {
}
.endpoint {
padding-right: 5px;
padding-right: 5px;
}
.floatRight {
float: right;
margin-right: 20px;
float: right;
margin-right: 20px;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
@import "../../../Common/Common.scss";
@import "../Common.scss";
$bgColor: #f9f9f9;
.container {
margin: 10px 0;
}
@ -16,29 +18,37 @@ $bgColor: #f9f9f9;
box-sizing: border-box;
position: relative;
min-height: 30px;
.inputRow {
margin: 20px 0;
div[class^=col-xs-] {
padding-left: 0;
padding-right: 2.5px;
}
:global(.form-control) {
height: 35px;
padding: 0 12px;
}
:global(.form-control):focus {
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0px rgba(102, 175, 233, 0.6);
}
:global(.fa) {
padding-top: 8px;
font-size: 0.8em;
}
i:hover {
cursor: pointer;
color: #888;
}
.descending {
padding-left: 10px;
input {
margin-right: 5px;
}
@ -54,19 +64,24 @@ $bgColor: #f9f9f9;
.runQuery {
margin-left: 0px;
margin-bottom: 20px;
:global(.form-control):focus {
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0px rgba(102, 175, 233, 0.6);
}
:global(.input-group) {
margin-top: -24px;
margin-right: 10px;
input {
max-width: 60px;
}
}
nav {
display: inline-block;
}
button {
margin-top: -24px;
margin-right: 15px;

View File

@ -5,7 +5,7 @@ import { Link } from 'react-router';
class BreadCrumb extends React.Component {
render() {
const { breadCrumbs } = this.props;
const styles = require('../../../Services/EventTrigger/TableCommon/Table.scss');
const styles = require('../../TableCommon/Table.scss');
const bC =
breadCrumbs && breadCrumbs.length > 0
? breadCrumbs.map((b, i) => {

View File

@ -1,67 +0,0 @@
import React from 'react';
import LeftNavBar from '../LeftNavBar/LeftNavBar';
import Helmet from 'react-helmet';
import { Link } from 'react-router';
import PropTypes from 'prop-types';
class LayoutWrapper extends React.Component {
render() {
const styles = require('../../../Services/Data/TableCommon/Table.scss');
const { appPrefix, children } = this.props;
const currentLocation = location.pathname;
return (
<div>
<Helmet title={'Custom Resolvers | Hasura'} />
<div className={styles.wd20 + ' ' + styles.align_left}>
<div
className={styles.pageSidebar + ' col-xs-12 ' + styles.padd_remove}
>
<div>
<ul>
<li
role="presentation"
className={
currentLocation.includes('remote-schemas/manage')
? styles.active
: ''
}
>
<Link
className={styles.linkBorder}
to={appPrefix + '/manage'}
>
<div className={styles.schemaWrapper}>
<div
className={styles.schemaSidebarSection}
data-test="schema"
>
Manage
</div>
</div>
</Link>
<LeftNavBar {...this.props} />
</li>
</ul>
</div>
</div>
</div>
<div className={styles.wd80}>{children}</div>
</div>
);
}
}
LayoutWrapper.propTypes = {
appPrefix: PropTypes.string.isRequired,
};
export default (connect, mapStateToProps, mapDispatchToProps) =>
connect(
mapStateToProps,
mapDispatchToProps
)(LayoutWrapper);

View File

@ -0,0 +1,17 @@
import React from 'react';
class LeftContainer extends React.Component {
render() {
const styles = require('../../TableCommon/Table.scss');
const { children } = this.props;
return (
<div className={styles.pageSidebar + ' col-xs-12 ' + styles.padd_remove}>
<div>{children}</div>
</div>
);
}
}
export default LeftContainer;

View File

@ -1,32 +0,0 @@
/* State
{
ongoingRequest : false, //true if request is going on
lastError : null OR <string>
lastSuccess: null OR <string>
}
*/
import defaultState from './State';
const SET_USERNAME = 'PageContainer/SET_USERNAME';
// HTML Component defines what state it needs
// HTML Component should be able to emit actions
// When an action happens, the state is modified (using the reducer function)
// When the state is modified, anybody dependent on the state is asked to update
// HTML Component is listening to state, hence re-renders
const homeReducer = (state = defaultState, action) => {
switch (action.type) {
case SET_USERNAME:
return { username: action.data };
default:
return state;
}
};
const setUsername = username => ({ type: SET_USERNAME, data: username });
export default homeReducer;
export { setUsername };

View File

@ -1,99 +0,0 @@
/* eslint-disable no-unused-vars */
import React from 'react';
import { Link } from 'react-router';
import Button from '../../Button/Button';
const LeftNavBar = ({
appPrefix,
listItemTemplate,
dataList,
filtered,
searchQuery,
location,
filterItem,
viewResolver,
migrationMode,
}) => {
const styles = require('./LeftNavBar.scss');
// Now schema might be null or an empty array
function tableSearch(e) {
const searchTerm = e.target.value;
filterItem(dataList, searchTerm);
}
// TODO: Make it generic so that other components can use it.
return (
<div className={styles.schemaTableList}>
<div className={styles.display_flex + ' ' + styles.padd_top_medium}>
<div
className={
styles.sidebarSearch + ' form-group col-xs-12 ' + styles.padd_remove
}
>
<i className="fa fa-search" aria-hidden="true" />
<input
type="text"
onChange={tableSearch.bind(this)}
className="form-control"
placeholder="search remote schemas"
data-test="search-remote-schemas"
/>
</div>
</div>
<div>
<div className={styles.sidebarHeadingWrapper}>
<div
className={
'col-xs-8 ' +
styles.sidebarHeading +
' ' +
styles.padd_left_remove
}
>
Remote Schemas ({dataList.length})
</div>
{migrationMode ? (
<div
className={
'col-xs-4 text-center ' +
styles.padd_remove +
' ' +
styles.sidebarCreateTable
}
>
<Link
className={styles.padd_remove_full}
to={`${appPrefix}/manage/add`}
>
<Button
className={styles.add_mar_right}
color="white"
size="xs"
data-test="remote-schema-sidebar-add-table"
>
Add
</Button>
</Link>
</div>
) : null}
</div>
<ul
className={styles.schemaListUl}
data-test="remote-schema-table-links"
>
{listItemTemplate(
searchQuery ? filtered : dataList,
styles,
location,
viewResolver
)}
</ul>
</div>
</div>
);
};
export default LeftNavBar;

View File

@ -1,170 +0,0 @@
@import "~bootstrap-sass/assets/stylesheets/bootstrap/variables";
@import "../../Common.scss";
.container {
}
.displayFlexContainer
{
display: flex;
}
.flexRow {
display: flex;
margin-bottom: 20px;
}
.add_btn {
margin: 10px 0;
}
.account {
padding: 20px 0;
line-height: 26px;
}
.changeSchema {
margin-left: 10px;
width: auto;
}
.sidebar {
height: calc(100vh - 26px);
overflow: auto;
// background: #444;
// color: $navbar-inverse-color;
color: #333;
border: 1px solid #E5E5E5;
background-color: #F8F8F8;
/*
a,a:visited {
color: $navbar-inverse-link-color;
}
a:hover {
color: $navbar-inverse-link-hover-color;
}
*/
hr {
margin: 0;
border-color: $navbar-inverse-color;
}
ul {
list-style-type: none;
padding-top: 10px;
padding-left: 7px;
li {
padding: 7px 0;
transition: color 0.5s;
/*
a,a:visited {
color: $navbar-inverse-link-color;
}
a:hover {
color: $navbar-inverse-link-hover-color;
}
*/
a
{
color: #767E93;
word-wrap: break-word;
}
}
li:hover {
padding: 7px 0;
// color: $navbar-inverse-link-hover-color;
transition: color 0.5s;
pointer: cursor;
}
}
}
.main {
padding: 0;
height: $mainContainerHeight;
overflow: auto;
}
.sidebarSearch {
margin-right: 20px;
padding: 10px 0px;
padding-bottom: 0px;
position: relative;
i
{
position: absolute;
padding: 10px;
font-size: 14px;
padding-left: 8px;
color: #979797;
}
input
{
padding-left: 25px;
}
}
.sidebarHeadingWrapper
{
width: 100%;
float: left;
padding-bottom: 10px;
.sidebarHeading {
font-weight: bold;
display: inline-block;
color: #767E93;
font-size: 15px;
}
}
.schemaTableList {
// max-height: 300px;
// overflow-y: auto;
overflow: auto;
padding-left: 20px;
max-height: calc(100vh - 275px);
border-bottom: 1px solid #e6e6e6;
}
.schemaListUl {
padding-left: 5px;
padding-bottom: 10px;
li {
border-bottom: 0px !important;
padding: 0 0 !important;
a {
background: transparent !important;
padding: 5px 0px !important;
font-weight: 400 !important;
padding-left: 5px !important;
.tableIcon {
margin-right: 5px;
font-size: 12px;
}
}
}
.noTables {
font-weight: 400 !important;
padding-bottom: 10px !important;
color: #767E93 !important;
}
li:first-child {
padding-top: 15px !important;
}
}
.heading_tooltip {
display: inline-block;
padding-right: 10px;
}
.addAllBtn {
margin-left: 15px;
}
.activeTable {
a
{
// border-left: 4px solid #FFC627;
color: #FD9540!important;
}
}
.floatRight {
float: right;
margin-right: 20px;
}

View File

@ -1,5 +0,0 @@
const defaultState = {
username: 'Guest User',
};
export default defaultState;

View File

@ -0,0 +1,86 @@
import React from 'react';
import { Link } from 'react-router';
import Button from '../../Button/Button';
class LeftSubSidebar extends React.Component {
render() {
const styles = require('./LeftSubSidebar.scss');
const {
migrationMode,
searchInput,
heading,
addLink,
addLabel,
addTestString,
children,
childListTestString,
} = this.props;
const getAddButton = () => {
let addButton = null;
if (migrationMode) {
addButton = (
<div
className={
'col-xs-4 text-center ' +
styles.padd_left_remove +
' ' +
styles.sidebarCreateTable
}
>
<Link className={styles.padd_remove_full} to={addLink}>
<Button size="xs" color="white" data-test={addTestString}>
{addLabel}
</Button>
</Link>
</div>
);
}
return addButton;
};
return (
<div className={styles.subSidebarList}>
<div className={styles.display_flex + ' ' + styles.padd_top_medium}>
<div
className={
styles.sidebarSearch +
' form-group col-xs-12 ' +
styles.padd_remove
}
>
<i className="fa fa-search" aria-hidden="true" />
{searchInput}
</div>
</div>
<div>
<div className={styles.sidebarHeadingWrapper}>
<div
className={
'col-xs-8 ' +
styles.sidebarHeading +
' ' +
styles.padd_left_remove
}
>
{heading}
</div>
{getAddButton()}
</div>
<ul
className={styles.subSidebarListUL}
data-test={childListTestString}
>
{children}
</ul>
</div>
</div>
);
}
}
export default LeftSubSidebar;

View File

@ -1,11 +1,13 @@
@import "~bootstrap-sass/assets/stylesheets/bootstrap/variables";
@import "../../../Common/Common.scss";
@import "../../Common.scss";
.container {
}
.displayFlexContainer
{
.displayFlexContainer {
display: flex;
}
.flexRow {
display: flex;
margin-bottom: 20px;
@ -33,40 +35,47 @@
color: #333;
border: 1px solid #E5E5E5;
background-color: #F8F8F8;
/*
a,a:visited {
color: $navbar-inverse-link-color;
}
a:hover {
color: $navbar-inverse-link-hover-color;
}
*/
hr {
margin: 0;
border-color: $navbar-inverse-color;
}
ul {
list-style-type: none;
padding-top: 10px;
padding-left: 7px;
li {
padding: 7px 0;
transition: color 0.5s;
/*
a,a:visited {
color: $navbar-inverse-link-color;
}
a:hover {
color: $navbar-inverse-link-hover-color;
}
*/
a
{
a {
color: #767E93;
word-wrap: break-word;
}
}
li:hover {
padding: 7px 0;
// color: $navbar-inverse-link-hover-color;
@ -87,24 +96,25 @@
padding: 10px 0px;
padding-bottom: 0px;
position: relative;
i
{
i {
position: absolute;
padding: 10px;
font-size: 14px;
padding-left: 8px;
color: #979797;
}
input
{
input {
padding-left: 25px;
}
}
.sidebarHeadingWrapper
{
.sidebarHeadingWrapper {
width: 100%;
float: left;
padding-bottom: 10px;
.sidebarHeading {
font-weight: bold;
display: inline-block;
@ -112,46 +122,57 @@
font-size: 15px;
}
}
.schemaTableList {
.subSidebarList {
// max-height: 300px;
// overflow-y: auto;
overflow: auto;
padding-left: 20px;
max-height: calc(100vh - 275px);
border-bottom: 1px solid #e6e6e6;
}
.schemaListUl {
.subSidebarListUL {
padding-left: 5px;
padding-bottom: 10px;
li {
border-bottom: 0px !important;
padding: 0 0 !important;
.tableFunctionDivider {
margin-top: 5px;
margin-bottom: 5px;
width: 95%;
}
a {
background: transparent !important;
padding: 5px 0px !important;
font-weight: 400 !important;
padding-left: 5px !important;
.tableIcon, .functionIcon {
margin-right: 5px;
font-size: 12px;
}
.functionIcon {
width: 12px;
img {
width: 100%;
}
}
}
}
.noTables {
.noChildren {
font-weight: 400 !important;
padding-bottom: 10px !important;
color: #767E93 !important;
}
li:first-child {
padding-top: 15px !important;
}
@ -167,8 +188,7 @@
}
.activeTable {
a
{
a {
// border-left: 4px solid #FFC627;
color: #FD9540!important;
}

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,22 @@
import React from 'react';
import Helmet from 'react-helmet';
class PageContainer extends React.Component {
render() {
const styles = require('../../Common.scss');
const { helmet, leftContainer, children } = this.props;
return (
<div>
<Helmet title={helmet} />
<div className={styles.wd20 + ' ' + styles.align_left}>
{leftContainer}
</div>
<div className={styles.wd80}>{children}</div>
</div>
);
}
}
export default PageContainer;

View File

@ -1,18 +1,20 @@
@import "../../Common.scss";
.common_header_wrapper {
.defaultWidth
{
.defaultWidth {
width: 300px;
}
.add_mar_right {
margin-right: 10px !important;
}
.header_colon {
margin-right: 10px;
font-weight: bold;
font-size: 24px;
}
.value_wd {
width: 300px;
}

View File

@ -1,7 +1,8 @@
import React from 'react';
const SchemaContainer = ({ children }) => {
const styles = require('./SchemaContainer.scss');
const RightContainer = ({ children }) => {
const styles = require('./RightContainer.scss');
return (
<div className={styles.container + ' container-fluid'}>
<div className="row">
@ -25,7 +26,7 @@ const mapStateToProps = state => {
};
};
const schemaContainerConnector = connect =>
connect(mapStateToProps)(SchemaContainer);
const rightContainerConnector = connect =>
connect(mapStateToProps)(RightContainer);
export default schemaContainerConnector;
export default rightContainerConnector;

View File

@ -1,13 +1,17 @@
@import "~bootstrap-sass/assets/stylesheets/bootstrap/variables";
@import "../../Common.scss";
.container {
}
.flexRow {
display: flex;
}
.padd_left_remove
{
.padd_left_remove {
padding-left: 0;
}
.add_btn {
margin: 10px 0;
}
@ -22,25 +26,31 @@
overflow: auto;
background: #444;
color: $navbar-inverse-color;
hr {
margin: 0;
border-color: $navbar-inverse-color;
}
ul {
list-style-type: none;
padding-top: 10px;
padding-left: 7px;
li {
padding: 7px 0;
transition: color 0.5s;
a,a:visited {
color: $navbar-inverse-link-color;
}
a:hover {
color: $navbar-inverse-link-hover-color;
text-decoration: none;
}
}
li:hover {
padding: 7px 0;
color: $navbar-inverse-link-hover-color;

View File

@ -1,3 +1 @@
export layoutConnector from './LayoutWrapper/LayoutWrapper';
export LeftNavBar from './LeftNavBar/LeftNavBar';
export rightBar from './RightLayoutWrapper/SchemaContainer';
export rightContainerConnector from './RightContainer/RightContainer';

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
const styles = require('./Styles.scss');
const styles = require('./QueryBuilderJson.scss');
class QueryBuilderJson extends React.Component {
static propTypes = {

View File

@ -1,4 +1,4 @@
@import "../Common/Common.scss";
@import "../Common.scss";
.qb_nested {
margin-top: 5px;

View File

@ -4,6 +4,7 @@
height: 40px;
position: relative;
}
.sk_circle .sk_child {
width: 100%;
height: 100%;
@ -11,6 +12,7 @@
left: 0;
top: 0;
}
.sk_circle .sk_child:before {
content: '';
display: block;
@ -22,83 +24,125 @@
-webkit-animation: sk_circleBounceDelay 1.2s infinite ease-in-out both;
animation: sk_circleBounceDelay 1.2s infinite ease-in-out both;
}
.sk_circle .sk_circle2 {
-webkit-transform: rotate(30deg);
-ms-transform: rotate(30deg);
transform: rotate(30deg); }
transform: rotate(30deg);
}
.sk_circle .sk_circle3 {
-webkit-transform: rotate(60deg);
-ms-transform: rotate(60deg);
transform: rotate(60deg); }
transform: rotate(60deg);
}
.sk_circle .sk_circle4 {
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg); }
transform: rotate(90deg);
}
.sk_circle .sk_circle5 {
-webkit-transform: rotate(120deg);
-ms-transform: rotate(120deg);
transform: rotate(120deg); }
transform: rotate(120deg);
}
.sk_circle .sk_circle6 {
-webkit-transform: rotate(150deg);
-ms-transform: rotate(150deg);
transform: rotate(150deg); }
transform: rotate(150deg);
}
.sk_circle .sk_circle7 {
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg); }
transform: rotate(180deg);
}
.sk_circle .sk_circle8 {
-webkit-transform: rotate(210deg);
-ms-transform: rotate(210deg);
transform: rotate(210deg); }
transform: rotate(210deg);
}
.sk_circle .sk_circle9 {
-webkit-transform: rotate(240deg);
-ms-transform: rotate(240deg);
transform: rotate(240deg); }
transform: rotate(240deg);
}
.sk_circle .sk_circle10 {
-webkit-transform: rotate(270deg);
-ms-transform: rotate(270deg);
transform: rotate(270deg); }
.sk_circle .sk_circle11 {
-webkit-transform: rotate(300deg);
-ms-transform: rotate(300deg);
transform: rotate(300deg); }
transform: rotate(300deg);
}
.sk_circle .sk_circle12 {
-webkit-transform: rotate(330deg);
-ms-transform: rotate(330deg);
transform: rotate(330deg); }
.sk_circle .sk_circle2:before {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s; }
animation-delay: -1.1s;
}
.sk_circle .sk_circle3:before {
-webkit-animation-delay: -1s;
animation-delay: -1s; }
animation-delay: -1s;
}
.sk_circle .sk_circle4:before {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s; }
animation-delay: -0.9s;
}
.sk_circle .sk_circle5:before {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s; }
animation-delay: -0.8s;
}
.sk_circle .sk_circle6:before {
-webkit-animation-delay: -0.7s;
animation-delay: -0.7s; }
animation-delay: -0.7s;
}
.sk_circle .sk_circle7:before {
-webkit-animation-delay: -0.6s;
animation-delay: -0.6s; }
animation-delay: -0.6s;
}
.sk_circle .sk_circle8:before {
-webkit-animation-delay: -0.5s;
animation-delay: -0.5s; }
animation-delay: -0.5s;
}
.sk_circle .sk_circle9:before {
-webkit-animation-delay: -0.4s;
animation-delay: -0.4s; }
animation-delay: -0.4s;
}
.sk_circle .sk_circle10:before {
-webkit-animation-delay: -0.3s;
animation-delay: -0.3s; }
animation-delay: -0.3s;
}
.sk_circle .sk_circle11:before {
-webkit-animation-delay: -0.2s;
animation-delay: -0.2s; }
animation-delay: -0.2s;
}
.sk_circle .sk_circle12:before {
-webkit-animation-delay: -0.1s;
animation-delay: -0.1s; }
animation-delay: -0.1s;
}
@-webkit-keyframes sk_circleBounceDelay {
0%, 80%, 100% {

View File

@ -1,3 +1,5 @@
/* eslint-disable */
import React, { Component } from 'react';
import ReactTable, { ReactTableDefaults } from 'react-table';
import 'react-table/react-table.css';
@ -5,7 +7,7 @@ import FoldableHoc from './foldableTable';
Object.assign(ReactTableDefaults, {
defaultPageSize: 10,
minRows: 3
minRows: 3,
});
class DragFoldTable extends Component {
@ -15,7 +17,7 @@ class DragFoldTable extends Component {
this.reorder = [];
this.state = {
trigger: 0,
folded: {}
folded: {},
};
}
mountEvents() {
@ -65,7 +67,7 @@ class DragFoldTable extends Component {
const cols = columns.map(col => ({
...col,
Header: <div className="draggable-header">{col.Header}</div>
Header: <div className="draggable-header">{col.Header}</div>,
}));
//run all reorder events
@ -80,7 +82,11 @@ class DragFoldTable extends Component {
{...this.props}
data={data}
columns={cols}
onFoldChange={newFolded => this.setState(p => { return { folded: newFolded }; })}
onFoldChange={newFolded =>
this.setState(p => {
return { folded: newFolded };
})
}
folded={this.state.folded}
/>
</div>

View File

@ -18,6 +18,7 @@
display: inline-block;
font-weight: bold;
}
.ReactTable .rt-thead {
font-size: 16px;
color: #333;
@ -25,26 +26,36 @@
cursor: pointer;
text-align: left;
}
.ReactTable .rt-thead .rt-resizable-header-content {
font-weight: bold;
}
.ReactTable .rt-thead .rt-resizable-header .rt-resizer {
width: 10px;
right: -5px;
}
.ReactTable .rt-expander {
width: 10px;
}
.ReactTable .rt-thead.-header {
box-shadow: none;
}
.ReactTable .-pagination {
box-shadow: none;
border: none;
}
.ReactTable .rt-table .rt-thead .rt-th,
.ReactTable .rt-table .rt-thead .rt-td {
padding-left: 20px !important;
padding-right: 20px !important;
border-right: 1px solid rgba(0,0,0,0.1);
}
.ReactTable .rt-table .rt-thead .rt-th.collapsed,
.ReactTable .rt-table .rt-thead .rt-td.collapsed {
padding-left: 10px !important;

View File

@ -1,14 +1,9 @@
@import "../../../Common/Common.scss";
@import "../Common.scss";
.container {
padding: 0;
}
.migration_disclaimer {
font-size: 12px;
margin-left: 10px;
margin-top: 10px;
color: rgb(236, 61, 61);
}
.tableContainer {
overflow: auto;
//margin-top: 25px;
@ -16,24 +11,25 @@
.schemaWrapper {
width: 100%;
.schemaSidebarSection {
display: inline-block;
width: 100%;
padding-left: 15px;
a
{
a {
display: inline-block !important;
font-weight: bold;
}
.changeSchema {
width: 50%;
margin-left: 10px;
display: inline-block;
font-weight: bold;
}
}
}
.changeSchema
{
width: 50%;
margin-left: 10px;
display: inline-block;
font-weight: bold;
}
.aceBlock {
max-height: 300px;
position: relative;
@ -63,12 +59,15 @@
button {
margin: 0 10px;
}
label.radioLabel {
padding-top: 0;
input[type="radio"] {
margin-top: 10px;
}
}
span.radioSpan {
line-height: 34px;
}
@ -76,14 +75,17 @@
.table {
width: auto;
thead {
background: #333;
color: #ddd;
}
th {
min-width: 100px;
font-weight: 300;
}
td {
max-width: 300px;
white-space: pre;
@ -110,11 +112,13 @@ a.expanded {
.tableNameInput {
width: 300px;
}
.addCol {
.input {
width: 300px;
display: inline-block;
}
.inputCheckbox {
width: auto;
display: inline-block;
@ -122,28 +126,32 @@ a.expanded {
margin: 0px 20px;
box-shadow: none;
}
.inputDefault
{
.inputDefault {
width: 150px;
margin: 0px 20px;
display: inline-block;
}
.remove_ul_left
{
.remove_ul_left {
}
.select {
display: inline-block;
width: 300px;
height: 34px;
}
.selectWidth {
.select200 {
width: 200px;
}
.defaultWidth {
width: 200px;
margin-right: 0px;
}
i:hover {
cursor: pointer;
color: #B85C27;

View File

@ -1,14 +1,17 @@
.container {
padding: 0;
}
.header {
background: #eee;
h2 {
margin: 0;
padding: 26px;
float: left;
line-height: 26px;
}
.nav {
padding: 20px;
float: left;
@ -28,12 +31,15 @@
button {
margin: 0 10px;
}
label.radioLabel {
padding-top: 0;
input[type="radio"] {
margin-top: 10px;
}
}
span.radioSpan {
line-height: 34px;
}
@ -42,14 +48,21 @@
.table {
width: -webkit-fill-available;
// width: auto;
thead {
background: #333;
color: #ddd;
}
th {
min-width: 100px;
font-weight: 300;
}
tr {
cursor: pointer;
}
td {
width: 300px;
max-width: 300px;
@ -77,16 +90,19 @@ a.expanded {
.tableNameInput {
width: 300px;
}
.addCol {
.input {
width: 250px;
display: inline-block;
}
.select {
margin: 0 20px;
display: inline-block;
width: 120px;
}
i:hover {
cursor: pointer;
color: #B85C27;
@ -108,10 +124,12 @@ a.expanded {
.relationshipTable {
width: auto;
thead {
background: #333;
color: #ddd;
}
th {
min-width: 100px;
font-weight: 300;
@ -125,4 +143,4 @@ a.expanded {
.relEditButtons {
display: flex;
flex-direction:row;
}
}

View File

@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
class ReusableTextAreaWithCopy extends React.Component {
class TextAreaWithCopy extends React.Component {
copyToClip(type, id) {
let text = '';
if (this.props.copyText.length > 0) {
@ -12,6 +12,7 @@ class ReusableTextAreaWithCopy extends React.Component {
})
: this.props.copyText;
}
const textArea = document.createElement('textarea');
textArea.value = text;
document.body.appendChild(textArea);
@ -31,13 +32,17 @@ class ReusableTextAreaWithCopy extends React.Component {
}
document.body.removeChild(textArea);
}
resetCopy(id) {
const tooltip = document.getElementById(id);
tooltip.innerHTML = 'Copy';
}
render() {
const style = require('./style.scss');
const style = require('./TextAreaWithCopy.scss');
const { copyText } = this.props;
return (
<div className={`${style.codeBlockCustom}`}>
<div className={`${style.copyGenerated}`}>
@ -85,9 +90,9 @@ class ReusableTextAreaWithCopy extends React.Component {
}
}
ReusableTextAreaWithCopy.propTypes = {
TextAreaWithCopy.propTypes = {
copyText: PropTypes.string.isRequired,
textLanguage: PropTypes.string,
};
export default ReusableTextAreaWithCopy;
export default TextAreaWithCopy;

View File

@ -2,8 +2,8 @@
position: relative;
width: 80%;
}
.codeBlockCustom
{
.codeBlockCustom {
/* position: relative;
padding: 10px 20px; */
background-color: white;
@ -42,24 +42,23 @@
padding: 0px 0px !important;
}
.copyGenerated
{
.copyGenerated {
position: absolute;
bottom: 15px;
right: 30px;
cursor: pointer;
}
.copyGenerated img, .copyExecution img
{
.copyGenerated img, .copyExecution img {
width: 20px;
opacity: .6;
}
.copyGenerated img:hover, .copyExecution img:hover
{
.copyGenerated img:hover, .copyExecution img:hover {
opacity: 1;
}
.copyGenerated:focus, .copyExecution:focus
{
.copyGenerated:focus, .copyExecution:focus {
outline: none;
}

View File

@ -12,13 +12,18 @@ class Login extends Component {
data: e.target.value,
});
};
loginClicked = () => {
this.props.dispatch(loginClicked());
};
render() {
const { loginInProgress, loginError } = this.props;
const { loginInProgress, loginError, dispatch } = this.props;
const styles = require('./Login.scss');
const hasuraLogo = require('./blue-logo.svg');
let loginText = 'Enter';
const styles = require('./Styles.scss');
if (loginInProgress) {
loginText = (
<span>
@ -30,8 +35,6 @@ class Login extends Component {
loginText = 'Error. Try again?';
}
const hasuraLogo = require('./blue-logo.svg');
const { dispatch } = this.props;
return (
<div className={styles.mainWrapper + ' container-fluid'}>
<div className={styles.container + ' container'} id="login">
@ -55,7 +58,6 @@ class Login extends Component {
<input
onChange={this.handleAdminSecret}
className={styles.form_input + ' form-control'}
placeholder="Password"
type="password"
placeholder={`Enter ${globals.adminSecretLabel}`}
name="password"

View File

@ -1,4 +1,5 @@
@import "../Common/Common.scss";
.container {
display: flex;
align-items: center;
@ -27,26 +28,25 @@
.mainWrapper {
background-color: #F8FAFB;
}
.input_addon_group
{
.input_addon_group {
margin-bottom: 10px;
padding: 0 15px;
.input_group
{
.input_group {
width: 100%;
.input_group_addon
{
.input_group_addon {
background-color: #e2e2e2;
height: 50px;
width: 50px;
border: 0;
}
input:focus
{
input:focus {
border: 1px solid #999;
}
.form_input
{
.form_input {
border: 1px solid #e2e2e2;
border-radius: 5px;
border-top-left-radius: 0;
@ -56,13 +56,13 @@
}
}
}
.signin_btn
{
.signin_btn {
padding: 0 15px;
padding-bottom: 15px;
padding-top: 10px;
button
{
button {
background-color: #27AE60;
height: 60px;
border: 0;
@ -71,6 +71,7 @@
text-transform: uppercase;
}
}
.loginHeading {
text-transform: uppercase;
text-align: center;
@ -78,12 +79,14 @@
font-family: 'Gudea';
color: #4d4d4d;
font-weight: bold;
.text {
border-bottom: 1px solid #dcdcdc;
width: 100px;
margin: 10px auto;
}
}
.hasuraLogo {
width: 100px;
padding-bottom: 20px;

View File

@ -16,7 +16,7 @@ const semver = require('semver');
import {
getLoveConsentState,
setLoveConsentState,
} from '../Common/localStorageManager';
} from './loveConsentLocalStorage';
class Main extends React.Component {
constructor(props) {
@ -123,55 +123,321 @@ class Main extends React.Component {
serverVersion,
latestServerVersion,
} = this.props;
const styles = require('./Main.scss');
const appPrefix = '';
const logo = require('./white-logo.svg');
const github = require('./Github.svg');
const discord = require('./Discord.svg');
const mail = require('./mail.svg');
const docs = require('./logo.svg');
const pixHeart = require('./pix-heart.svg');
const currentLocation = location.pathname;
const currentActiveBlock = currentLocation.split('/')[1];
const sidebarClass = styles.sidebar;
const getMainContent = () => {
let mainContent = null;
let mainContent = null;
if (migrationModeProgress) {
mainContent = (
<div>
{' '}
<Spinner />{' '}
</div>
);
} else {
mainContent = children && React.cloneElement(children);
}
let adminSecretHtml = null;
if (
!globals.isAdminSecretSet &&
(globals.adminSecret === '' || globals.adminSecret === null)
) {
adminSecretHtml = (
<div className={styles.secureSection}>
<OverlayTrigger placement="left" overlay={tooltip.secureEndpoint}>
<a href="https://docs.hasura.io/1.0/graphql/manual/deployment/securing-graphql-endpoint.html">
<i
if (!migrationModeProgress) {
mainContent = children && React.cloneElement(children);
} else {
mainContent = (
<div>
{' '}
<Spinner />{' '}
</div>
);
}
return mainContent;
};
const getMetadataSelectedMarker = () => {
let metadataSelectedMarker = null;
if (currentActiveBlock === 'metadata') {
metadataSelectedMarker = <span className={styles.selected} />;
}
return metadataSelectedMarker;
};
const getAdminSecretSection = () => {
let adminSecretHtml = null;
if (
!globals.isAdminSecretSet &&
(globals.adminSecret === '' || globals.adminSecret === null)
) {
adminSecretHtml = (
<div className={styles.secureSection}>
<OverlayTrigger placement="left" overlay={tooltip.secureEndpoint}>
<a href="https://docs.hasura.io/1.0/graphql/manual/deployment/securing-graphql-endpoint.html">
<i
className={
styles.padd_small_right + ' fa fa-exclamation-triangle'
}
/>
Secure your endpoint
</a>
</OverlayTrigger>
</div>
);
}
return adminSecretHtml;
};
const getBannerNotification = () => {
let bannerNotificationHtml = null;
if (this.state.showBannerNotification) {
bannerNotificationHtml = (
<div>
<div className={styles.phantom} />{' '}
{/* phantom div to prevent overlapping of banner with content. */}
<div className={styles.updateBannerWrapper}>
<div className={styles.updateBanner}>
<span> Hey there! A new server version </span>
<span className={styles.versionUpdateText}>
{' '}
{latestServerVersion}
</span>
<span> is available </span>
<span className={styles.middot}> &middot; </span>
<a
href={
'https://github.com/hasura/graphql-engine/releases/tag/' +
latestServerVersion
}
target="_blank"
rel="noopener noreferrer"
>
<span>View Changelog</span>
</a>
<span className={styles.middot}> &middot; </span>
<a
className={styles.updateLink}
href="https://docs.hasura.io/1.0/graphql/manual/deployment/updating.html"
target="_blank"
rel="noopener noreferrer"
>
<span>Update Now</span>
</a>
<span
className={styles.updateBannerClose}
onClick={this.closeUpdateBanner.bind(this)}
>
<i className={'fa fa-times'} />
</span>
</div>
</div>
</div>
);
}
return bannerNotificationHtml;
};
const getLoveSection = () => {
let loveSectionHtml = null;
if (!this.state.loveConsentState.isDismissed) {
loveSectionHtml = [
<div
key="main_love_1"
className={styles.shareSection + ' dropdown-toggle'}
aria-expanded="false"
onClick={this.handleDropdownToggle.bind(this)}
>
<img
className={'img-responsive'}
src={pixHeart}
alt={'pix Heart'}
/>
{/* <i className={styles.heart + ' fa fa-heart'} /> */}
</div>,
<ul
key="main_love_2"
className={'dropdown-menu ' + styles.dropdown_menu}
>
<div className={styles.dropdown_menu_container}>
<div className={styles.closeDropDown}>
<i
className="fa fa-close"
onClick={this.closeLoveIcon.bind(this)}
/>
{/*
<img
className={'img-responsive'}
src={closeIcon}
alt={'closeIcon'}
onClick={this.closeLoveIcon.bind(this)}
/>
*/}
</div>
{/*
<div className={styles.arrow_up_dropdown} />
<div className={styles.graphqlHeartText}>
Love GraphQL Engine? Shout it from the rooftops!
<br />
Or just spread the word{' '}
<span role="img" aria-label="smile">
😊
</span>
</div>
*/}
<div className={styles.displayFlex}>
<li className={styles.pixelText1}>
Roses are red, <br />
Violets are blue;
<br />
Star us on Github,
<br />
To make our <i className={'fa fa-heart'} /> go wooooo!
</li>
<li className={'dropdown-item'}>
<a
href="https://github.com/hasura/graphql-engine"
target="_blank"
rel="noopener noreferrer"
>
<div className={styles.socialIcon}>
<img
className="img img-responsive"
src={
'https://storage.googleapis.com/hasura-graphql-engine/console/assets/githubicon.png'
}
alt={'Github'}
/>
</div>
<div className={styles.pixelText}>
<i className="fa fa-star" />
&nbsp; Star
</div>
</a>
{/*
<div className={styles.gitHubBtn}>
<iframe
title="github"
src="https://ghbtns.com/github-btn.html?user=hasura&repo=graphql-engine&type=star&count=true"
frameBorder="0"
scrolling="0"
width="100px"
height="30px"
/>
</div>
*/}
</li>
<li className={'dropdown-item '}>
<a
href="https://twitter.com/intent/tweet?hashtags=graphql,postgres&text=Just%20deployed%20a%20GraphQL%20backend%20with%20@HasuraHQ!%20%E2%9D%A4%EF%B8%8F%20%F0%9F%9A%80%0Ahttps://github.com/hasura/graphql-engine%0A"
target="_blank"
rel="noopener noreferrer"
>
<div className={styles.socialIcon}>
<img
className="img img-responsive"
src={
'https://storage.googleapis.com/hasura-graphql-engine/console/assets/twittericon.png'
}
alt={'Twitter'}
/>
</div>
<div className={styles.pixelText}>
<i className="fa fa-twitter" />
&nbsp; Tweet
</div>
</a>
</li>
</div>
</div>
</ul>,
];
}
return loveSectionHtml;
};
const getHelpDropdownPosStyle = () => {
let helpDropdownPosStyle = '';
if (this.state.loveConsentState.isDismissed) {
helpDropdownPosStyle = styles.help_dropdown_menu_heart_dismissed;
}
return helpDropdownPosStyle;
};
const getRemoteSchemaLink = () => {
let remoteSchemaLink = null;
if (this.state.showSchemaStitch) {
remoteSchemaLink = (
<OverlayTrigger placement="right" overlay={tooltip.customresolver}>
<li>
<Link
className={
styles.padd_small_right + ' fa fa-exclamation-triangle'
currentActiveBlock === 'remote-schemas'
? styles.navSideBarActive
: ''
}
/>
Secure your endpoint
</a>
to={appPrefix + '/remote-schemas/manage/schemas'}
>
<div className={styles.iconCenter}>
<i
title="Remote Schemas"
className="fa fa-plug"
aria-hidden="true"
/>
</div>
<p>Remote Schemas</p>
</Link>
</li>
</OverlayTrigger>
</div>
);
}
);
}
return remoteSchemaLink;
};
const getEventsLink = () => {
let eventsLink = null;
if (this.state.showEvents) {
eventsLink = (
<OverlayTrigger placement="right" overlay={tooltip.events}>
<li>
<Link
className={
currentActiveBlock === 'events' ? styles.navSideBarActive : ''
}
to={appPrefix + '/events/manage/triggers'}
>
<div className={styles.iconCenter}>
<i
title="Events"
className="fa fa-cloud"
aria-hidden="true"
/>
</div>
<p>Events</p>
</Link>
</li>
</OverlayTrigger>
);
}
return eventsLink;
};
return (
<div className={styles.container}>
<div className={styles.flexRow}>
<div className={sidebarClass}>
<div className={styles.sidebar}>
<div className={styles.header_logo_wrapper}>
<div className={styles.logoParent}>
<div className={styles.logo}>
@ -232,65 +498,19 @@ class Main extends React.Component {
</Link>
</li>
</OverlayTrigger>
{this.state.showSchemaStitch ? (
<OverlayTrigger
placement="right"
overlay={tooltip.customresolver}
>
<li>
<Link
className={
currentActiveBlock === 'remote-schemas'
? styles.navSideBarActive
: ''
}
to={appPrefix + '/remote-schemas/manage/schemas'}
>
<div className={styles.iconCenter}>
<i
title="Remote Schemas"
className="fa fa-plug"
aria-hidden="true"
/>
</div>
<p>Remote Schemas</p>
</Link>
</li>
</OverlayTrigger>
) : null}
{this.state.showEvents ? (
<OverlayTrigger placement="right" overlay={tooltip.events}>
<li>
<Link
className={
currentActiveBlock === 'events'
? styles.navSideBarActive
: ''
}
to={appPrefix + '/events/manage/triggers'}
>
<div className={styles.iconCenter}>
<i
title="Events"
className="fa fa-cloud"
aria-hidden="true"
/>
</div>
<p>Events</p>
</Link>
</li>
</OverlayTrigger>
) : null}
{getRemoteSchemaLink()}
{getEventsLink()}
</ul>
</div>
<div id="dropdown_wrapper" className={styles.clusterInfoWrapper}>
{adminSecretHtml}
{getAdminSecretSection()}
<Link to="/metadata">
<div className={styles.helpSection + ' ' + styles.settingsIcon}>
<i className={styles.question + ' fa fa-cog'} />
{currentActiveBlock === 'metadata' ? (
<span className={styles.selected} />
) : null}
{getMetadataSelectedMarker()}
</div>
</Link>
<div className={styles.supportSection}>
@ -308,9 +528,7 @@ class Main extends React.Component {
'dropdown-menu ' +
styles.help_dropdown_menu +
' ' +
(this.state.loveConsentState.isDismissed
? styles.help_dropdown_menu_heart_consented
: '')
getHelpDropdownPosStyle()
}
aria-labelledby="help"
>
@ -370,165 +588,16 @@ class Main extends React.Component {
</div>
</ul>
</div>
{!this.state.loveConsentState.isDismissed
? [
<div
key="main_love_1"
className={styles.shareSection + ' dropdown-toggle'}
aria-expanded="false"
onClick={this.handleDropdownToggle.bind(this)}
>
<img
className={'img-responsive'}
src={pixHeart}
alt={'pix Heart'}
/>
{/* <i className={styles.heart + ' fa fa-heart'} /> */}
</div>,
<ul
key="main_love_2"
className={'dropdown-menu ' + styles.dropdown_menu}
>
<div className={styles.dropdown_menu_container}>
<div className={styles.closeDropDown}>
<i
className="fa fa-close"
onClick={this.closeLoveIcon.bind(this)}
/>
{/*
<img
className={'img-responsive'}
src={closeIcon}
alt={'closeIcon'}
onClick={this.closeLoveIcon.bind(this)}
/>
*/}
</div>
{/*
<div className={styles.arrow_up_dropdown} />
<div className={styles.graphqlHeartText}>
Love GraphQL Engine? Shout it from the rooftops!
<br />
Or just spread the word{' '}
<span role="img" aria-label="smile">
😊
</span>
</div>
*/}
<div className={styles.displayFlex}>
<li className={styles.pixelText1}>
Roses are red, <br />
Violets are blue;
<br />
Star us on Github,
<br />
To make our <i className={'fa fa-heart'} /> go
wooooo!
</li>
<li className={'dropdown-item'}>
<a
href="https://github.com/hasura/graphql-engine"
target="_blank"
rel="noopener noreferrer"
>
<div className={styles.socialIcon}>
<img
className="img img-responsive"
src={
'https://storage.googleapis.com/hasura-graphql-engine/console/assets/githubicon.png'
}
alt={'Github'}
/>
</div>
<div className={styles.pixelText}>
<i className="fa fa-star" />
&nbsp; Star
</div>
</a>
{/*
<div className={styles.gitHubBtn}>
<iframe
title="github"
src="https://ghbtns.com/github-btn.html?user=hasura&repo=graphql-engine&type=star&count=true"
frameBorder="0"
scrolling="0"
width="100px"
height="30px"
/>
</div>
*/}
</li>
<li className={'dropdown-item '}>
<a
href="https://twitter.com/intent/tweet?hashtags=graphql,postgres&text=Just%20deployed%20a%20GraphQL%20backend%20with%20@HasuraHQ!%20%E2%9D%A4%EF%B8%8F%20%F0%9F%9A%80%0Ahttps://github.com/hasura/graphql-engine%0A"
target="_blank"
rel="noopener noreferrer"
>
<div className={styles.socialIcon}>
<img
className="img img-responsive"
src={
'https://storage.googleapis.com/hasura-graphql-engine/console/assets/twittericon.png'
}
alt={'Twitter'}
/>
</div>
<div className={styles.pixelText}>
<i className="fa fa-twitter" />
&nbsp; Tweet
</div>
</a>
</li>
</div>
</div>
</ul>,
]
: null}
{getLoveSection()}
</div>
</div>
<div className={styles.main + ' container-fluid'}>{mainContent}</div>
{this.state.showBannerNotification ? (
<div>
<div className={styles.phantom} />{' '}
{/* phantom div to prevent overlapping of banner with content. */}
<div className={styles.updateBannerWrapper}>
<div className={styles.updateBanner}>
<span> Hey there! A new server version </span>
<span className={styles.versionUpdateText}>
{' '}
{latestServerVersion}
</span>
<span> is available </span>
<span className={styles.middot}> &middot; </span>
<a
href={
'https://github.com/hasura/graphql-engine/releases/tag/' +
latestServerVersion
}
target="_blank"
rel="noopener noreferrer"
>
<span>View Changelog</span>
</a>
<span className={styles.middot}> &middot; </span>
<a
className={styles.updateLink}
href="https://docs.hasura.io/1.0/graphql/manual/deployment/updating.html"
target="_blank"
rel="noopener noreferrer"
>
<span>Update Now</span>
</a>
<span
className={styles.updateBannerClose}
onClick={this.closeUpdateBanner.bind(this)}
>
<i className={'fa fa-times'} />
</span>
</div>
</div>
</div>
) : null}
<div className={styles.main + ' container-fluid'}>
{getMainContent()}
</div>
{getBannerNotification()}
</div>
</div>
);

View File

@ -1,10 +1,12 @@
@import "~bootstrap-sass/assets/stylesheets/bootstrap/variables";
@import url('https://fonts.googleapis.com/css?family=Press+Start+2P');
@import "../Common/Common.scss";
@font-face {
font-family: arcadeClassic;
src: url(https://storage.googleapis.com/hasura-graphql-engine/console/assets/ARCADECLASSIC.ttf);
}
.container {
position: relative;
}
@ -30,28 +32,34 @@
background-color: #FFC627;
color: #43495a;
padding: 14.5px 10px;
.updateBanner {
display: flex;
align-items: center;
justify-content: center;
a {
color: #43495a;
text-decoration: underline;
font-weight: bold;
}
}
.updateBannerClose {
cursor: pointer;
position: absolute;
right: 10px;
}
.versionUpdateText {
font-weight: bold;
padding: 0px 5px;
}
.updateLink {
font-weight: bold;
}
.middot {
line-height: 0;
font-size: 20px;
@ -74,11 +82,12 @@
font-weight: bold;
font-size: 20px;
}
.header_items {
width: 50%;
}
.header_logo_wrapper
{
.header_logo_wrapper {
padding: 10px 20px;
position: relative;
display: flex;
@ -86,31 +95,33 @@
border-right: 1px solid #788095;
display: inline-block;
width: 20%;
.logoParent
{
.logoParent {
display: flex;
align-items: center;
a {
display: flex;
align-items: center;
}
.logo
{
.logo {
display: inline-block;
// margin-right: 6px;
a
{
img
{
a {
img {
width: 100px;
}
}
}
&.collapsed {
padding: 10px 10px !important;
}
}
}
.project_version {
font-family: Gudea;
color: #fff;
@ -122,6 +133,7 @@
font-weight: 300;
padding-top: 6px;
}
.toggleSidebar {
position: absolute;
color: #fff;
@ -132,16 +144,19 @@
border: 1px solid #43495a;
z-index: 1;
}
.clusterInfoWrapper {
width: 30%;
display: flex;
justify-content: flex-end;
position: relative;
.clusterBtn {
background-color: transparent;
color: #DEDEDE;
font-weight: 700;
pointer-events: none;
.caret {
margin-left: 15px;
border-top: 6px dashed;
@ -150,11 +165,13 @@
border-left: 6px solid transparent;
}
}
.clusterInfoMenu {
min-width: 250px;
right: 0;
left: unset;
top: 38px;
li {
text-transform: none;
padding: 6px 15px;
@ -163,35 +180,34 @@
}
}
}
.setting_wrapper {
position: fixed;
right: 20px;
cursor: pointer;
z-index: 101;
}
.setting_wrapper, .clusterInfoWrapper
{
.setting_dropdown
{
.dropdown_menu
{
.setting_wrapper, .clusterInfoWrapper {
.setting_dropdown {
.dropdown_menu {
left: inherit;
right: 0;
li
{
a
{
li {
a {
padding: 6px 15px;
}
}
hr
{
hr {
margin-top: 6px;
margin-bottom: 6px;
}
}
}
}
.bubble {
display: inline-block;
font-size: 16px;
@ -208,18 +224,19 @@
-o-animation: pulse 1s ease infinite;
animation: pulse 1s ease infinite;
}
.onBoardingHighlight
{
.onBoardingHighlight {
position: absolute;
z-index: 1001;
.focusDiv {
display: flex;
justify-content: flex-end;
padding-top: 10px;
font-weight: bold;
}
.onBoardingHighlightCallOut
{
.onBoardingHighlightCallOut {
position: absolute;
width: 21px;
height: 21px;
@ -229,59 +246,59 @@
transform: rotate(45deg);
background-color: #4D4D4D;
}
.onBoardingDataFocus
{
.onBoardingDataFocus {
top: -5%;
left: 15%;
}
.onBoardingAuthFocus
{
.onBoardingAuthFocus {
top: -5%;
left: 15%;
}
.onBoardingAuthUserFocus
{
.onBoardingAuthUserFocus {
bottom: -5%;
left: 15%;
}
.onBoardingTableFocus
{
.onBoardingTableFocus {
top: 10%;
left: -5px;
}
.onBoardingPanelFocus
{
.onBoardingPanelFocus {
top: 15%;
left: -3%;
}
.onBoardingBuilderFocus
{
.onBoardingBuilderFocus {
top: 93%;
left: 15%;
}
.onBoardingSendFocus
{
.onBoardingSendFocus {
top: -5%;
left: 19%;
}
.onBoardingCodeFocus
{
.onBoardingCodeFocus {
bottom: -7%;
left: 15%;
}
.onBoardingNoFocus
{
.onBoardingNoFocus {
top: 10px;
left: 10px;
}
.onBoardingDocsLink
{
.onBoardingDocsLink {
a {
color: #fff;
}
}
.onBoardingHighlightInterior
{
.onBoardingHighlightInterior {
background-color: #4D4D4D;
position: relative;
width: 300px;
@ -290,30 +307,32 @@
color: #fff;
}
}
.onBoardingPanelPosition
{
.onBoardingPanelPosition {
left: 20%;
top: 126px;
}
.onBoardingBuilderPosition{
left: 45%;
top: 320px;
}
.onBoardingSendPosition
{
.onBoardingSendPosition {
left: 26%;
top: 450px;
}
.onBoardingCodePosition
{
.onBoardingCodePosition {
left: 63%;
top: 230px;
}
.onBoardingNoFocusPosition
{
.onBoardingNoFocusPosition {
left: 80%;
top: 80%;
}
.mainBox {
position: absolute;
text-align: center;
@ -329,25 +348,26 @@
-webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.1);
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.1);
.yellow_button
{
.yellow_button {
padding: 15px 60px;
font-size: 15px;
font-weight: 600;
}
.subheading_text
{
.subheading_text {
font-size: 45px;
font-family: 'Gudea';
font-weight: 400;
}
.description
{
.description {
font-size: 16px;
font-family: 'Gudea';
font-weight: 400;
padding-bottom: 10px;
}
.welcomeText {
font-size: 25px;
font-family: 'Gudea';
@ -356,38 +376,43 @@
padding-top: 20px;
padding-bottom: 20px;
}
.welcomeSubText {
padding-bottom: 10px;
text-align: left;
}
.smallDescription
{
.smallDescription {
font-size: 12px;
font-family: 'Gudea';
font-weight: 400;
padding-bottom: 20px;
a {
cursor: pointer;
}
}
.mainBoxListWrapper
{
.mainBoxListWrapper {
-webkit-padding-start: 0;
padding-left: 150px;
li
{
li {
list-style-type: none;
text-align: left;
i {
padding-right: 10px;
}
}
}
}
.headerOnBoarding {
opacity: 0.1;
pointer-events: none;
}
.sidebar {
color: #DEDEDE;
background-color: #43495a;
@ -400,29 +425,35 @@
width: 100%;
min-width: $minContainerWidth;
z-index: 100;
hr {
margin: 0 auto;
width: 80%;
border-top-color: #aaa;
opacity: 0.8;
}
.sidebarItems {
list-style-type: none;
padding: 0;
display: inline-block;
margin-bottom: 0;
margin-top: 16px;
a,a:visited {
color: #DEDEDE;
}
a:hover {
color: #DEDEDE;
}
li {
transition: color 0.5s;
font-size: 14px;
letter-spacing: 1px;
display: inline-block;
p {
padding-left: 5px;
display: inline-block;
@ -430,6 +461,7 @@
letter-spacing: 1px;
margin: 0 0 0px;
}
a {
margin: 0px 0px;
display: block;
@ -437,36 +469,42 @@
border-bottom: 4px solid transparent;
padding: 0 10px;
padding-bottom: 10px;
.iconCenter {
display: inline-block;
width: 20px;
text-align: center;
i {
width: 20px;
display: inline-block;
}
}
}
.serviceLink {
display: inline-block;
width: 80%;
margin: 10px 0px;
}
.expandArrow {
text-align: center;
width: 20%;
display: inline-block;
float: right;
i {
font-size: 14px;
}
a {
margin: 0 0;
padding: 10px;
cursor: pointer;
}
.sidebar_dropdown
{
.sidebar_dropdown {
left: -1px;
right: inherit;
top: inherit;
@ -474,15 +512,14 @@
box-shadow: none;
border-radius: 0;
background-color: #515766;
li
{
a
{
li {
a {
padding: 6px 15px;
}
}
hr
{
hr {
margin-top: 6px;
margin-bottom: 6px;
}
@ -493,22 +530,24 @@
background-color: grey;
}
}
.serviceList {
display: flex;
align-items: center;
}
.navSideBarActive
{
.navSideBarActive {
border-bottom: 4px solid #FFC627;
i
{
i {
color: #FFC627;
}
p
{
p {
color: #FFC627;
}
}
li:hover {
// color: $navbar-inverse-link-hover-color;
// background: #444;
@ -521,11 +560,13 @@
.sidebarCollapsed {
max-width: 50px !important;
min-width: 50px !important;
ul {
li {
p {
display: none !important;
}
a {
.iconCenter {
i {
@ -545,10 +586,12 @@
text-align: right;
padding: 0;
padding-right: 15px;
img {
height: 50px;
float: left;
}
.headerItem {
display: inline-block;
color: $navbar-inverse-color;
@ -557,15 +600,18 @@
padding: 17.5px 15px;
cursor: pointer;
}
.headerItem:hover {
display: inline-block;
color: $navbar-inverse-link-hover-color;
transition: color 0.5s;
}
.headerItem:hover * {
color: $navbar-inverse-link-hover-color;
transition: color 0.5s;
}
.headerItem * {
color: $navbar-inverse-color;
}
@ -616,16 +662,17 @@
display: inline-block;
cursor: pointer;
}
.statusHeading {
padding-right: 5px;
display: inline-block;
}
.detailButton
{
.detailButton {
display: inline-block;
padding-left: 5px;
button
{
button {
background-color: transparent;
border-radius: 5px;
color: #DEDEDE;
@ -633,6 +680,7 @@
padding: 4px 10px;
}
}
.statusOk {
color: green;
}
@ -711,6 +759,7 @@
right: 0px;
z-index: 12;
font-family: 'Gudea';
p {
font-size: 16px;
padding-top: 5px;
@ -736,20 +785,20 @@
color: #272B36;
height: calc(100vh - 260px);
overflow-y: auto;
ol li {
padding-bottom: 20px;
}
a
{
button
{
a {
button {
width: 105px;
text-align: center;
padding: 7px 0;
}
}
button
{
button {
width: 105px;
text-align: center;
padding: 7px 0;
@ -763,8 +812,8 @@
.progressBtn {
float: right;
padding-top: 10px;
button
{
button {
width: 105px;
text-align: center;
padding: 7px 0;
@ -780,8 +829,8 @@
float: right;
padding: 5px;
cursor: pointer;
i
{
i {
color: #AAAAAA;
}
}
@ -817,9 +866,11 @@
.spreadWord {
display: flex;
align-items: center;
.yellow_button {
border-radius: 20px;
margin-right: 20px;
i {
padding-top: 0px;
}
@ -836,18 +887,21 @@
.heart {
display: inline-block;
i {
font-size: 20px;
// color: #fb5f5f;
color: #fff;
}
}
.borderBottom
{
.borderBottom {
border-bottom: 1px solid #788095;
}
.supportSection {
cursor: pointer;
.helpSection {
&:hover {
opacity: 0.7;
@ -855,12 +909,14 @@
}
}
}
.helpSection {
display: flex;
align-items: center;
// background-color: #22283b;
padding: 15px;
position: relative;
.selected {
bottom: 0;
background: #FFC627;
@ -874,6 +930,7 @@
.settingsIcon {
// background: #5668a4;
a {
text-decoration: none;
}
@ -886,11 +943,12 @@
padding: 15px;
color: white;
cursor: pointer;
&:hover {
opacity: 0.7;
}
img
{
img {
width: 23px;
}
}
@ -899,48 +957,47 @@
// background-color: #545a6c;
padding: 15px;
a {
color: white;
text-decoration: none;
}
}
@keyframes heartbeat
{
0%
{
@keyframes heartbeat {
0% {
transform: scale( .75 );
}
20%
{
20% {
transform: scale( 1 );
}
40%
{
40% {
transform: scale( .75 );
}
60%
{
60% {
transform: scale( 1 );
}
80%
{
80% {
transform: scale( .75 );
}
100%
{
100% {
transform: scale( .75 );
}
}
.graphqlHeartText
{
.graphqlHeartText {
font-size: 14px;
font-weight: 300;
text-transform: none;
text-align: center;
}
.pixelText
{
.pixelText {
font-family: arcadeClassic;
font-size: 20px;
text-transform: uppercase;
@ -953,8 +1010,7 @@
font-size: 15px;
}
.pixelText1
{
.pixelText1 {
font-family: arcadeClassic;
font-size: 14px;
padding-left: 0px !important;
@ -964,64 +1020,65 @@
line-height: 1.8;
letter-spacing: 1px;
}
.help_dropdown_menu
{
.help_dropdown_menu {
top: 43px;
right: 53px;
background-color: transparent;
box-shadow: none;
border: 0;
.help_dropdown_menu_container
{
.help_dropdown_menu_container {
width: 300px;
float: right;
background-color: #43495a;
padding: 15px;
position: relative;
}
li
{
li {
display: block;
font-weight: 300;
text-transform: none;
font-size: 14px;
color: #fff;
padding: 5px 0;
.displayBlock
{
.displayBlock {
display: inline-block !important;
}
a
{
a {
color: #fff;
display: flex;
align-items: center;
img
{
img {
width: 20px;
display: inline-block;
margin-right: 10px;
}
}
a:hover
{
a:hover {
text-decoration: none;
opacity: 0.7;
}
}
}
.help_dropdown_menu_heart_consented {
right: 0px;
.help_dropdown_menu_heart_dismissed {
right: 0;
}
.dropdown_menu
{
.dropdown_menu {
top: 43px;
right: 0px;
background-color: transparent;
box-shadow: none;
border: 0;
.dropdown_menu_container
{
.dropdown_menu_container {
width: 490px;
float: right;
@ -1034,21 +1091,21 @@
padding: 25px;
position: relative;
.closeDropDown
{
.closeDropDown {
color: #43495a;
cursor: pointer;
position: absolute;
top: 10px;
left: 20px;
img
{
img {
width: 10px;
}
}
}
.arrow_up_dropdown
{
.arrow_up_dropdown {
width: 0;
height: 0;
border-left: 10px solid transparent;
@ -1058,15 +1115,15 @@
top: -5px;
right: 10px;
}
.displayFlex
{
.displayFlex {
display: flex;
// align-items: center;
justify-content: center;
margin-top: 10px;
}
li
{
li {
display: block;
color: #f24444;
text-transform: none;
@ -1074,16 +1131,16 @@
display: inline-block;
padding-bottom: 0;
font-weight: 300;
a
{
a {
color: #fff;
}
a:hover
{
a:hover {
color: #fff;
}
.socialIcon
{
.socialIcon {
width: 90px;
height: 90px;
border: 2px solid #fff;
@ -1092,12 +1149,13 @@
align-items: center;
justify-content: center;
}
.gitHubBtn
{
.gitHubBtn {
height: 20px;
}
}
}
.twitterShare {
position: relative;
height: 20px;
@ -1108,14 +1166,15 @@
border-radius: 3px;
font-weight: 500;
cursor: pointer;
button
{
button {
background-color: #1b95e0;
padding: 5px;
letter-spacing: 0.4px;
border: 0;
}
}
.telemetryNotification {
background-color: red;
padding: 10px;

View File

@ -11,9 +11,12 @@ class Add extends React.Component {
componentWillUnmount() {
this.props.dispatch({ type: RESET });
}
render() {
const styles = require('../Styles.scss');
const styles = require('../CustomResolver.scss');
const { isRequesting, dispatch } = this.props;
return (
<div className={styles.addWrapper}>
<Helmet title={`Add ${pageTitle} - ${pageTitle}s | Hasura`} />

View File

@ -11,28 +11,6 @@ import {
import CommonHeader from '../../../Common/Layout/ReusableHeader/Header';
const graphqlurl = (
<Tooltip id="tooltip-cascade">
Remote GraphQL servers URL. E.g. https://my-domain/v1alpha1/graphql
</Tooltip>
);
const clientHeaderForward = (
<Tooltip id="tooltip-cascade">
Toggle forwarding headers sent by the client app in the request to your
remote GraphQL server
</Tooltip>
);
const additionalHeaders = (
<Tooltip id="tooltip-cascade">
Custom headers to be sent to the remote GraphQL server
</Tooltip>
);
const schema = (
<Tooltip id="tooltip-cascade">
Give this GraphQL schema a friendly name.
</Tooltip>
);
class Common extends React.Component {
getPlaceHolderText(valType) {
if (valType === 'static') {
@ -40,23 +18,55 @@ class Common extends React.Component {
}
return 'env var name';
}
handleInputChange(e) {
const fieldName = e.target.getAttribute('data-key');
this.props.dispatch(inputChange(fieldName, e.target.value));
}
toggleUrlParam(e) {
const field = e.target.getAttribute('value');
this.props.dispatch(inputChange(field, ''));
}
toggleForwardHeaders() {
this.props.dispatch({ type: UPDATE_FORWARD_CLIENT_HEADERS });
}
render() {
const styles = require('../Styles.scss');
const styles = require('../CustomResolver.scss');
const { name, manualUrl, envName, forwardClientHeaders } = this.props;
const { isModify, id } = this.props.editState;
const isDisabled = id >= 0 && !isModify;
const urlRequired = !manualUrl && !envName;
const graphqlurl = (
<Tooltip id="tooltip-cascade">
Remote GraphQL servers URL. E.g. https://my-domain/v1alpha1/graphql
</Tooltip>
);
const clientHeaderForward = (
<Tooltip id="tooltip-cascade">
Toggle forwarding headers sent by the client app in the request to your
remote GraphQL server
</Tooltip>
);
const additionalHeaders = (
<Tooltip id="tooltip-cascade">
Custom headers to be sent to the remote GraphQL server
</Tooltip>
);
const schema = (
<Tooltip id="tooltip-cascade">
Give this GraphQL schema a friendly name.
</Tooltip>
);
return (
<div className={styles.CommonWrapper}>
<div className={styles.subheading_text + ' ' + styles.addPaddTop}>

View File

@ -1,143 +1,152 @@
@import "../../Common/Common.scss";
.addPaddCommom
{
.addPaddCommom {
padding: 10px 0;
}
.wd_300 {
width: 300px;
}
.addPaddTop
{
.addPaddTop {
padding-top: 20px;
}
.dropdown_button {
width: 300px;
}
.detailsSection {
width: 80%;
margin-top: 20px;
}
.detailsRefreshButton {
padding-top: 10px !important;
}
.resolverWrapper
{
.resolverWrapper {
// padding: 10px 0;
.resolverContent
{
.resolverContent {
text-align: center;
padding-bottom: 10px;
font-weight: 600;
}
.resolverImg
{
.resolverImg {
width: 100%;
padding: 20px;
text-align: center;
// height: 200px;
// border: 1px solid #000;
img {
}
}
.commonBtn
{
.commonBtn {
text-align: center;
padding: 20px 0;
padding-bottom: 10px
}
.readMore
{
.readMore {
padding-bottom: 10px;
text-align: center;
}
}
.CommonWrapper
{
.CommonWrapper {
.check_box {
margin-bottom: 20px;
label {
cursor: pointer;
margin-right: 10px;
}
input {
margin: 0;
cursor: pointer;
}
i {
cursor: pointer;
}
}
.font_normal {
font-weight: normal;
}
.subheading_text
{
i
{
.subheading_text {
i {
cursor: pointer;
}
}
.defaultWidth
{
.defaultWidth {
width: 300px;
}
.radioLabel
{
.radioLabel {
padding-right: 20px;
text-align: left;
padding-top: 5px;
.radioInput
{
.radioInput {
cursor: pointer;
}
}
.inputLabel
{
.inputLabel {
margin-left: 0;
input
{
input {
width: 300px;
}
}
}
.addWrapper
{
.commonBtn
{
.addWrapper {
.commonBtn {
padding: 20px 0;
padding-top: 40px;
.delete_confirmation_error {
margin-left: 15px;
color: #d9534f;
}
.yellow_button
{
.yellow_button {
margin-right: 20px;
}
.red_button {
color: #FFF;
}
a
{
a {
margin-left: 20px;
}
.refresh_schema_btn {
margin-left: 20px;
}
span
{
i
{
span {
i {
cursor: pointer;
margin-left: 10px;
}
}
}
.remove_padding_bottom {
padding-bottom: 0px;
}
.set_line_height {
line-height: 26px;
}

View File

@ -0,0 +1,54 @@
import React from 'react';
import { Link } from 'react-router';
import PropTypes from 'prop-types';
import LeftContainer from '../../Common/Layout/LeftContainer/LeftContainer';
import PageContainer from '../../Common/Layout/PageContainer/PageContainer';
import CustomResolverSubSidebar from './CustomResolverSubSidebar';
class CustomResolverPageContainer extends React.Component {
render() {
const styles = require('../../Common/TableCommon/Table.scss');
const { appPrefix, children } = this.props;
const currentLocation = location.pathname;
const sidebarContent = (
<ul>
<li
role="presentation"
className={
currentLocation.includes('remote-schemas/manage')
? styles.active
: ''
}
>
<Link className={styles.linkBorder} to={appPrefix + '/manage'}>
Manage
</Link>
<CustomResolverSubSidebar {...this.props} />
</li>
</ul>
);
const helmet = 'Remote Schemas | Hasura';
const leftContainer = <LeftContainer>{sidebarContent}</LeftContainer>;
return (
<PageContainer helmet={helmet} leftContainer={leftContainer}>
{children}
</PageContainer>
);
}
}
CustomResolverPageContainer.propTypes = {
appPrefix: PropTypes.string.isRequired,
};
export default (connect, mapStateToProps, mapDispatchToProps) =>
connect(
mapStateToProps,
mapDispatchToProps
)(CustomResolverPageContainer);

View File

@ -1,10 +1,11 @@
import React from 'react';
import { Route, IndexRedirect, Link } from 'react-router';
import { layoutConnector, rightBar } from '../../Common/Layout';
import { Route, IndexRedirect } from 'react-router';
import { rightContainerConnector } from '../../Common/Layout';
import globals from '../../../Globals';
import {
landingCustomResolverGen,
customResolverPageConnector,
landingConnector,
addConnector,
editConnector,
viewConnector,
@ -18,43 +19,6 @@ import { fetchResolvers, FILTER_RESOLVER } from './customActions';
import { appPrefix } from './constants';
const listItem = (dataList, styles, currentLocation, currentResolver) => {
if (dataList.length === 0) {
return (
<li
className={styles.noTables}
data-test="remote-schema-sidebar-no-schemas"
>
<i>No remote schemas available</i>
</li>
);
}
return dataList.map((d, i) => {
let activeTableClass = '';
if (
d.name === currentResolver &&
currentLocation.pathname.indexOf(currentResolver) !== -1
) {
activeTableClass = styles.activeTable;
}
return (
<li
className={activeTableClass}
key={i}
data-test={`remote-schema-sidebar-links-${i + 1}`}
>
<Link
to={appPrefix + '/manage/' + d.name + '/details'}
data-test={d.name}
>
<i className={styles.tableIcon + ' fa fa-table'} aria-hidden="true" />
{d.name}
</Link>
</li>
);
});
};
const filterItem = dispatch => {
return (dataList, searchVal) => {
// form new schema
@ -85,7 +49,6 @@ const leftNavMapStateToProps = state => {
searchQuery: state.customResolverData.listData.searchQuery,
viewResolver: state.customResolverData.listData.viewResolver,
migrationMode: state.main.migrationMode ? state.main.migrationMode : false,
listItemTemplate: listItem,
appPrefix,
};
};
@ -129,10 +92,11 @@ const getCustomResolverRouter = (connect, store, composeOnEnterHooks) => {
}
cb();
};
return (
<Route
path="remote-schemas"
component={layoutConnector(
component={customResolverPageConnector(
connect,
leftNavMapStateToProps,
leftNavMapDispatchToProps
@ -141,9 +105,9 @@ const getCustomResolverRouter = (connect, store, composeOnEnterHooks) => {
onChange={fetchInitialData(store)}
>
<IndexRedirect to="manage" />
<Route path="manage" component={rightBar(connect)}>
<Route path="manage" component={rightContainerConnector(connect)}>
<IndexRedirect to="schemas" />
<Route path="schemas" component={landingCustomResolverGen(connect)} />
<Route path="schemas" component={landingConnector(connect)} />
<Route
path="add"
component={addConnector(connect)}

View File

@ -0,0 +1,97 @@
import React from 'react';
import { Link } from 'react-router';
import LeftSubSidebar from '../../Common/Layout/LeftSubSidebar/LeftSubSidebar';
const CustomResolverSubSidebar = ({
appPrefix,
dataList,
filtered,
searchQuery,
location,
filterItem,
viewResolver,
migrationMode,
}) => {
const styles = require('../../Common/Layout/LeftSubSidebar/LeftSubSidebar.scss');
function tableSearch(e) {
const searchTerm = e.target.value;
filterItem(dataList, searchTerm);
}
const getSearchInput = () => {
return (
<input
type="text"
onChange={tableSearch.bind(this)}
className="form-control"
placeholder="search remote schemas"
data-test="search-remote-schemas"
/>
);
};
const getChildList = () => {
const _dataList = searchQuery ? filtered : dataList;
let childList;
if (_dataList.length === 0) {
childList = (
<li
className={styles.noChildren}
data-test="remote-schema-sidebar-no-schemas"
>
<i>No remote schemas available</i>
</li>
);
} else {
childList = _dataList.map((d, i) => {
let activeTableClass = '';
if (
d.name === viewResolver &&
location.pathname.includes(viewResolver)
) {
activeTableClass = styles.activeTable;
}
return (
<li
className={activeTableClass}
key={i}
data-test={`remote-schema-sidebar-links-${i + 1}`}
>
<Link
to={appPrefix + '/manage/' + d.name + '/details'}
data-test={d.name}
>
<i
className={styles.tableIcon + ' fa fa-table'}
aria-hidden="true"
/>
{d.name}
</Link>
</li>
);
});
}
return childList;
};
return (
<LeftSubSidebar
migrationMode={migrationMode}
searchInput={getSearchInput()}
heading={`Remote Schemas (${dataList.length})`}
addLink={`${appPrefix}/manage/add`}
addLabel={'Add'}
addTestString={'remote-schema-sidebar-add-table'}
childListTestString={'remote-schema-table-links'}
>
{getChildList()}
</LeftSubSidebar>
);
};
export default CustomResolverSubSidebar;

View File

@ -32,16 +32,19 @@ class Edit extends React.Component {
this.state = {};
this.state.deleteConfirmationError = null;
}
componentDidMount() {
const { resolverName } = this.props.params;
if (!resolverName) {
this.props.dispatch(push(prefixUrl));
}
Promise.all([
this.props.dispatch(fetchResolver(resolverName)),
this.props.dispatch({ type: VIEW_RESOLVER, data: resolverName }),
]);
}
componentWillReceiveProps(nextProps) {
if (nextProps.params.resolverName !== this.props.params.resolverName) {
Promise.all([
@ -53,6 +56,7 @@ class Edit extends React.Component {
]);
}
}
componentWillUnmount() {
Promise.all([
this.props.dispatch({ type: RESET }),
@ -62,9 +66,11 @@ class Edit extends React.Component {
handleDeleteResolver(e) {
e.preventDefault();
const a = prompt(
'Are you absolutely sure?\nThis action cannot be undone. This will permanently delete stitched GraphQL schema. Please type "DELETE" (in caps, without quotes) to confirm.\n'
);
try {
if (a && typeof a === 'string' && a.trim() === 'DELETE') {
this.updateDeleteConfirmationError(null);
@ -78,20 +84,26 @@ class Edit extends React.Component {
console.error(err);
}
}
updateDeleteConfirmationError(data) {
this.setState({ deleteConfirmationError: data });
}
modifyClick() {
this.props.dispatch({ type: TOGGLE_MODIFY });
}
handleCancelModify() {
this.props.dispatch({ type: TOGGLE_MODIFY });
}
editClicked() {
this.props.dispatch(modifyResolver());
}
render() {
const styles = require('../Styles.scss');
const styles = require('../CustomResolver.scss');
const { isFetching, isRequesting, editState, migrationMode } = this.props;
const { resolverName } = this.props.params;

View File

@ -17,13 +17,6 @@ import globals from '../../../../Globals';
const prefixUrl = globals.urlPrefix + appPrefix;
const refresh = (
<Tooltip id="tooltip-cascade">
If your remote schema has changed, you need to refresh the GraphQL Engine
metadata to query the modified schema
</Tooltip>
);
class ViewStitchedSchema extends React.Component {
componentDidMount() {
const { resolverName } = this.props.params;
@ -35,6 +28,7 @@ class ViewStitchedSchema extends React.Component {
this.props.dispatch({ type: VIEW_RESOLVER, data: resolverName }),
]);
}
componentWillReceiveProps(nextProps) {
if (nextProps.params.resolverName !== this.props.params.resolverName) {
Promise.all([
@ -46,17 +40,22 @@ class ViewStitchedSchema extends React.Component {
]);
}
}
componentWillUnmount() {
Promise.all([
this.props.dispatch({ type: RESET }),
this.props.dispatch({ type: VIEW_RESOLVER, data: '' }),
]);
}
render() {
const styles = require('../Styles.scss');
const styles = require('../CustomResolver.scss');
const { resolverName } = this.props.params;
const { manualUrl, envName, headers } = this.props;
const filterHeaders = headers.filter(h => !!h.name);
const breadCrumbs = [
{
title: 'Remote schemas',
@ -85,6 +84,14 @@ class ViewStitchedSchema extends React.Component {
url: '',
});
}
const refresh = (
<Tooltip id="tooltip-cascade">
If your remote schema has changed, you need to refresh the GraphQL
Engine metadata to query the modified schema
</Tooltip>
);
return (
<div
className={styles.view_stitch_schema_wrapper + ' ' + styles.addWrapper}
@ -112,17 +119,19 @@ class ViewStitchedSchema extends React.Component {
<td>Headers</td>
<td>
{filterHeaders &&
filterHeaders.filter(k => !!k.name).map((h, i) => [
<tr key={i}>
<td>
{h.name} :{' '}
{h.type === 'static'
? h.value
: '<' + h.value + '>'}
</td>
</tr>,
i !== filterHeaders.length - 1 ? <hr /> : null,
])}
filterHeaders
.filter(k => !!k.name)
.map((h, i) => [
<tr key={i}>
<td>
{h.name} :{' '}
{h.type === 'static'
? h.value
: '<' + h.value + '>'}
</td>
</tr>,
i !== filterHeaders.length - 1 ? <hr /> : null,
])}
</td>
</tr>
) : null}

View File

@ -8,11 +8,12 @@ import Button from '../../../Common/Button/Button';
class CustomResolver extends React.Component {
render() {
const styles = require('../Styles.scss');
const styles = require('../CustomResolver.scss');
// const landingImage = require('./schema-stitching-color.png');
// const landingImage = 'https://storage.googleapis.com/hasura-graphql-engine/console/assets/schema-stitching-diagram.png';
const { dispatch, migrationMode } = this.props;
return (
<div
className={`${styles.padd_left_remove} ${
@ -80,7 +81,7 @@ const mapStateToProps = state => {
};
};
const landingCustomResolverGen = connect =>
const customResolverConnector = connect =>
connect(mapStateToProps)(CustomResolver);
export default landingCustomResolverGen;
export default customResolverConnector;

View File

@ -1,8 +1,9 @@
export landingCustomResolverGen from './Landing/CustomResolver';
export getCustomResolverRouter from './CustomResolverRouter';
export customResolverPageConnector from './CustomResolverPageContainer';
export landingConnector from './Landing/CustomResolver';
export addConnector from './Add/Add';
export customResolverReducer from './customResolverReducer';
export editConnector from './Edit/Edit';
export viewConnector from './Edit/View';
export getCustomResolverRouter from './CustomResolverRouter';
export customResolverReducer from './customResolverReducer';

View File

@ -15,7 +15,7 @@ class AddExistingTableView extends Component {
render() {
const { dispatch, ongoingRequest, lastError, lastSuccess } = this.props;
const styles = require('../TableCommon/Table.scss');
const styles = require('../../../Common/TableCommon/Table.scss');
let alert = null;
if (ongoingRequest) {
@ -47,7 +47,7 @@ class AddExistingTableView extends Component {
return (
<div
className={
'container-fluid ' + styles.main_wrapper + ' ' + styles.padd_top
'container-fluid ' + styles.clear_fix + ' ' + styles.padd_top
}
>
<Helmet title="Add Existing Table/View - Data | Hasura" />

View File

@ -239,7 +239,7 @@ class AddTable extends Component {
lastSuccess,
internalError,
} = this.props;
const styles = require('../TableCommon/Table.scss');
const styles = require('../../../Common/TableCommon/Table.scss');
const cols = columns.map((column, i) => {
let removeIcon;
if (i + 1 === columns.length) {
@ -282,7 +282,7 @@ class AddTable extends Component {
/>
<select
value={column.type}
className={`${styles.select} ${styles.selectWidth} form-control ${
className={`${styles.select} ${styles.select200} form-control ${
styles.add_pad_left
}`}
onChange={e => {
@ -422,7 +422,7 @@ class AddTable extends Component {
return (
<div
className={`${styles.addTablesBody} ${styles.main_wrapper} ${
className={`${styles.addTablesBody} ${styles.clear_fix} ${
styles.padd_left
}`}
>

View File

@ -1,139 +0,0 @@
import React from 'react';
import { Link } from 'react-router';
import _push from './push';
import Helmet from 'react-helmet';
import PageContainer from './PageContainer/PageContainer';
import globals from '../../../Globals';
import {
loadSchema,
loadUntrackedSchema,
loadUntrackedRelations,
UPDATE_CURRENT_SCHEMA,
fetchFunctionInit,
} from './DataActions';
const sectionPrefix = '/data';
const DataHeader = ({
schema,
currentSchema,
schemaList,
children,
location,
dispatch,
}) => {
const styles = require('./TableCommon/Table.scss');
const currentLocation = location.pathname;
let migrationSection = null;
if (globals.consoleMode === 'cli') {
migrationSection = (
<li
role="presentation"
className={
currentLocation.includes('data/migrations') ? styles.active : ''
}
>
<Link className={styles.linkBorder} to={sectionPrefix + '/migrations'}>
Migrations
</Link>
</li>
);
}
const handleSchemaChange = e => {
const updatedSchema = e.target.value;
dispatch(_push(`/schema/${updatedSchema}`));
Promise.all([
dispatch({ type: UPDATE_CURRENT_SCHEMA, currentSchema: updatedSchema }),
dispatch(loadSchema()),
dispatch(loadUntrackedSchema()),
dispatch(loadUntrackedRelations()),
dispatch(fetchFunctionInit()),
]);
};
return (
<div>
<Helmet title={'Data | Hasura'} />
<div className={styles.wd20 + ' ' + styles.align_left}>
<div
className={styles.pageSidebar + ' col-xs-12 ' + styles.padd_remove}
>
<div>
<ul>
<li
role="presentation"
className={
currentLocation.includes('data/schema') ? styles.active : ''
}
>
<Link
className={styles.linkBorder}
to={sectionPrefix + '/schema/' + currentSchema}
>
<div className={styles.schemaWrapper}>
<div
className={styles.schemaSidebarSection}
data-test="schema"
>
Schema:
<select
onChange={handleSchemaChange}
className={styles.changeSchema + ' form-control'}
>
{schemaList.map(s => (
<option
key={s.schema_name}
selected={s.schema_name === currentSchema}
>
{s.schema_name}
</option>
))}
</select>
</div>
</div>
</Link>
<PageContainer
location={location}
schema={schema}
currentSchema={currentSchema}
dispatch={dispatch}
/>
</li>
<li
role="presentation"
className={
currentLocation.includes('data/sql') ? styles.active : ''
}
>
<Link
className={styles.linkBorder}
to={sectionPrefix + '/sql'}
data-test="sql-link"
>
SQL
</Link>
</li>
{migrationSection}
</ul>
</div>
</div>
</div>
<div className={styles.wd80}>{children}</div>
</div>
);
};
const mapStateToProps = state => {
return {
schema: state.tables.allSchemas,
schemaList: state.tables.schemaList,
currentSchema: state.tables.currentSchema,
};
};
const dataHeaderConnector = connect => connect(mapStateToProps)(DataHeader);
export default dataHeaderConnector;

View File

@ -0,0 +1,134 @@
import React from 'react';
import { Link } from 'react-router';
import _push from './push';
import globals from '../../../Globals';
import LeftContainer from '../../Common/Layout/LeftContainer/LeftContainer';
import PageContainer from '../../Common/Layout/PageContainer/PageContainer';
import DataSubSidebar from './DataSubSidebar';
import {
loadSchema,
loadUntrackedSchema,
loadUntrackedRelations,
UPDATE_CURRENT_SCHEMA,
fetchFunctionInit,
} from './DataActions';
const sectionPrefix = '/data';
const DataPageContainer = ({
schema,
currentSchema,
schemaList,
children,
location,
dispatch,
}) => {
const styles = require('../../Common/TableCommon/Table.scss');
const currentLocation = location.pathname;
let migrationTab = null;
if (globals.consoleMode === 'cli') {
migrationTab = (
<li
role="presentation"
className={
currentLocation.includes('data/migrations') ? styles.active : ''
}
>
<Link className={styles.linkBorder} to={sectionPrefix + '/migrations'}>
Migrations
</Link>
</li>
);
}
const handleSchemaChange = e => {
const updatedSchema = e.target.value;
dispatch(_push(`/schema/${updatedSchema}`));
Promise.all([
dispatch({ type: UPDATE_CURRENT_SCHEMA, currentSchema: updatedSchema }),
dispatch(loadSchema()),
dispatch(loadUntrackedSchema()),
dispatch(loadUntrackedRelations()),
dispatch(fetchFunctionInit()),
]);
};
const sidebarContent = (
<ul>
<li
role="presentation"
className={currentLocation.includes('data/schema') ? styles.active : ''}
>
<Link
className={styles.linkBorder}
to={sectionPrefix + '/schema/' + currentSchema}
>
<div className={styles.schemaWrapper}>
<div className={styles.schemaSidebarSection} data-test="schema">
Schema:
<select
onChange={handleSchemaChange}
className={styles.changeSchema + ' form-control'}
>
{schemaList.map(s => (
<option
key={s.schema_name}
selected={s.schema_name === currentSchema}
>
{s.schema_name}
</option>
))}
</select>
</div>
</div>
</Link>
<DataSubSidebar
location={location}
schema={schema}
currentSchema={currentSchema}
dispatch={dispatch}
/>
</li>
<li
role="presentation"
className={currentLocation.includes('data/sql') ? styles.active : ''}
>
<Link
className={styles.linkBorder}
to={sectionPrefix + '/sql'}
data-test="sql-link"
>
SQL
</Link>
</li>
{migrationTab}
</ul>
);
const helmet = 'Data | Hasura';
const leftContainer = <LeftContainer>{sidebarContent}</LeftContainer>;
return (
<PageContainer helmet={helmet} leftContainer={leftContainer}>
{children}
</PageContainer>
);
};
const mapStateToProps = state => {
return {
schema: state.tables.allSchemas,
schemaList: state.tables.schemaList,
currentSchema: state.tables.currentSchema,
};
};
const dataPageConnector = connect =>
connect(mapStateToProps)(DataPageContainer);
export default dataPageConnector;

View File

@ -7,7 +7,6 @@ import { SERVER_CONSOLE_MODE } from '../../../constants';
import {
schemaConnector,
schemaContainerConnector,
viewTableConnector,
insertItemConnector,
rawSQLConnector,
@ -19,7 +18,7 @@ import {
relationshipsConnector,
relationshipsViewConnector,
permissionsConnector,
dataHeaderConnector,
dataPageConnector,
migrationsConnector,
functionWrapperConnector,
ModifyCustomFunction,
@ -27,6 +26,8 @@ import {
// metadataConnector,
} from '.';
import { rightContainerConnector } from '../../Common/Layout';
import {
fetchDataInit,
fetchFunctionInit,
@ -47,9 +48,9 @@ const makeDataRouter = (
consoleModeRedirects
) => {
return (
<Route path="data" component={dataHeaderConnector(connect)}>
<Route path="data" component={dataPageConnector(connect)}>
<IndexRedirect to="schema/public" />
<Route path="schema" component={schemaContainerConnector(connect)}>
<Route path="schema" component={rightContainerConnector(connect)}>
<IndexRedirect to="public" />
<Route path=":schema" component={schemaConnector(connect)} />
<Route path=":schema/tables" component={schemaConnector(connect)} />
@ -129,7 +130,7 @@ const makeDataRouter = (
);
};
const dataRouter = (connect, store, composeOnEnterHooks) => {
const dataRouterUtils = (connect, store, composeOnEnterHooks) => {
const requireSchema = (nextState, replaceState, cb) => {
// check if admin secret is available in localstorage. if so use that.
// if localstorage admin secret didn't work, redirect to login (meaning value has changed)
@ -198,4 +199,4 @@ const dataRouter = (connect, store, composeOnEnterHooks) => {
};
};
export default dataRouter;
export default dataRouterUtils;

View File

@ -0,0 +1,222 @@
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
// import globals from '../../../Globals';
import LeftSubSidebar from '../../Common/Layout/LeftSubSidebar/LeftSubSidebar';
import { LISTING_SCHEMA, UPDATE_TRACKED_FUNCTIONS } from './DataActions';
import semverCheck from '../../../helpers/semver';
const appPrefix = '/data';
const DataSubSidebar = ({
schema,
listingSchema,
functionsList,
listedFunctions,
currentTable,
schemaName,
migrationMode,
// children,
dispatch,
location,
currentFunction,
serverVersion,
}) => {
const styles = require('../../Common/Layout/LeftSubSidebar/LeftSubSidebar.scss');
const functionSymbol = require('../../Common/Layout/LeftSubSidebar/function.svg');
const functionSymbolActive = require('../../Common/Layout/LeftSubSidebar/function_high.svg');
const handleFunc = semverCheck('customFunctionSection', serverVersion);
function tableSearch(e) {
const searchTerm = e.target.value;
// form new schema
const matchedTables = [];
schema.map(table => {
if (table.table_name.indexOf(searchTerm) !== -1) {
matchedTables.push(table);
}
});
const matchedFuncs = functionsList.filter(
f => f.function_name.indexOf(searchTerm) !== -1
);
// update schema with matchedTables
dispatch({ type: LISTING_SCHEMA, updatedSchemas: matchedTables });
dispatch({ type: UPDATE_TRACKED_FUNCTIONS, data: matchedFuncs });
}
const getSearchInput = () => {
return (
<input
type="text"
onChange={tableSearch.bind(this)}
className="form-control"
placeholder={`search table/view${handleFunc ? '/function' : ''}`}
data-test="search-tables"
/>
);
};
const getChildList = () => {
let tableLinks = [
<li className={styles.noChildren} key="no-tables-1">
<i>No tables/views available</i>
</li>,
];
const tables = {};
listingSchema.map(t => {
tables[t.table_name] = t;
});
const currentLocation = location.pathname;
if (listingSchema && listingSchema.length) {
tableLinks = Object.keys(tables)
.sort()
.map((tableName, i) => {
let activeTableClass = '';
if (
tableName === currentTable &&
currentLocation.indexOf(currentTable) !== -1
) {
activeTableClass = styles.activeTable;
}
if (tables[tableName].detail.table_type === 'BASE TABLE') {
return (
<li className={activeTableClass} key={i}>
<Link
to={
appPrefix +
'/schema/' +
schemaName +
'/tables/' +
tableName +
'/browse'
}
data-test={tableName}
>
<i
className={styles.tableIcon + ' fa fa-table'}
aria-hidden="true"
/>
{tableName}
</Link>
</li>
);
}
return (
<li className={activeTableClass} key={i}>
<Link
to={
appPrefix +
'/schema/' +
schemaName +
'/views/' +
tableName +
'/browse'
}
data-test={tableName}
>
<i
className={styles.tableIcon + ' fa fa-table'}
aria-hidden="true"
/>
<i>{tableName}</i>
</Link>
</li>
);
});
}
const dividerHr = [
<li key={'fn-divider-1'}>
<hr className={styles.tableFunctionDivider} />
</li>,
];
// If the listedFunctions is non empty
if (listedFunctions.length > 0) {
const functionHtml = listedFunctions.map((f, i) => (
<li
className={
f.function_name === currentFunction ? styles.activeTable : ''
}
key={'fn ' + i}
>
<Link
to={
appPrefix +
'/schema/' +
schemaName +
'/functions/' +
f.function_name
}
data-test={f.function_name}
>
<div className={styles.display_inline + ' ' + styles.functionIcon}>
<img
src={
f.function_name === currentFunction
? functionSymbolActive
: functionSymbol
}
/>
</div>
{f.function_name}
</Link>
</li>
));
tableLinks = [...tableLinks, ...dividerHr, ...functionHtml];
} else if (
functionsList.length !== listedFunctions.length &&
listedFunctions.length === 0
) {
const noFunctionResult = [
<li className={styles.noChildren}>
<i>No matching functions available</i>
</li>,
];
tableLinks = [...tableLinks, ...dividerHr, ...noFunctionResult];
}
return tableLinks;
};
return (
<LeftSubSidebar
migrationMode={migrationMode}
searchInput={getSearchInput()}
heading={`Tables (${schema.length})`}
addLink={'/data/schema/' + schemaName + '/table/add'}
addLabel={'Add Table'}
addTestString={'sidebar-add-table'}
childListTestString={'table-links'}
>
{getChildList()}
</LeftSubSidebar>
);
};
const mapStateToProps = state => {
return {
schemaName: state.tables.currentSchema,
schema: state.tables.allSchemas,
listingSchema: state.tables.listingSchemas,
currentTable: state.tables.currentTable,
migrationMode: state.main.migrationMode,
functionsList: state.tables.trackedFunctions,
listedFunctions: state.tables.listedFunctions,
currentFunction: state.functions.functionName,
serverVersion: state.main.serverVersion ? state.main.serverVersion : '',
};
};
export default connect(mapStateToProps)(DataSubSidebar);

View File

@ -14,7 +14,7 @@ import Button from '../../../../Common/Button/Button';
const prefixUrl = globals.urlPrefix + appPrefix;
import ReusableTextAreaWithCopy from '../../../../Common/Layout/ReusableTextAreaWithCopy/ReusableTextAreaWithCopy';
import TextAreaWithCopy from '../../../../Common/TextAreaWithCopy/TextAreaWithCopy';
import {
fetchCustomFunction,
@ -30,6 +30,7 @@ class ModifyCustomFunction extends React.Component {
this.state = {};
this.state.deleteConfirmationError = null;
}
componentDidMount() {
const { functionName, schema } = this.props.params;
if (!functionName || !schema) {
@ -39,6 +40,7 @@ class ModifyCustomFunction extends React.Component {
this.props.dispatch(fetchCustomFunction(functionName, schema)),
]);
}
componentWillReceiveProps(nextProps) {
const { functionName, schema } = this.props.params;
if (
@ -55,6 +57,7 @@ class ModifyCustomFunction extends React.Component {
]);
}
}
loadRunSQLAndLoadPage() {
const { functionDefinition } = this.props.functions;
Promise.all([
@ -62,18 +65,23 @@ class ModifyCustomFunction extends React.Component {
this.props.dispatch(_push('/sql')),
]);
}
updateDeleteConfirmationError(data) {
this.setState({ deleteConfirmationError: data });
}
handleUntrackCustomFunction(e) {
e.preventDefault();
this.props.dispatch(unTrackCustomFunction());
}
handleDeleteCustomFunction(e) {
e.preventDefault();
const a = prompt(
'Are you absolutely sure?\nThis action cannot be undone. This will permanently delete function. Please type "DELETE" (in caps, without quotes) to confirm.\n'
);
try {
if (a && typeof a === 'string' && a.trim() === 'DELETE') {
this.updateDeleteConfirmationError(null);
@ -87,6 +95,7 @@ class ModifyCustomFunction extends React.Component {
console.error(err);
}
}
render() {
const styles = require('./ModifyCustomFunction.scss');
const {
@ -193,7 +202,7 @@ class ModifyCustomFunction extends React.Component {
<h4>Function Definition:</h4>
*/}
<div className={styles.sqlBlock}>
<ReusableTextAreaWithCopy
<TextAreaWithCopy
copyText={functionDefinition}
textLanguage={'sql'}
/>

View File

@ -1,49 +1,54 @@
@import '../../../../Common/Common.scss';
.modifyWrapper {
.commonBtn
{
.commonBtn {
// padding: 20px 0;
// padding-top: 40px;
.delete_confirmation_error {
margin-left: 15px;
color: #d9534f;
}
.yellow_button
{
.yellow_button {
margin-right: 20px;
}
.red_button {
margin-right: 20px;
color: #FFF;
}
.no_mr_right {
margin-right: 0px;
}
.white_button {
margin-right: 20px;
color: #333;
&:hover {
background-color: #d4d4d4;
}
border-color: #8c8c8c;
}
a
{
a {
// margin-left: 20px;
}
.refresh_schema_btn {
margin-left: 20px;
}
span
{
i
{
span {
i {
cursor: pointer;
margin-left: 10px;
}
}
}
.sqlBlock {
position: relative;
width: 100%;

View File

@ -48,11 +48,11 @@ class Metadata extends Component {
});
}
render() {
const styles = require('../TableCommon/Table.scss');
const styles = require('../../../Common/TableCommon/Table.scss');
const metaDataStyles = require('./Metadata.scss');
return (
<div
className={`${styles.main_wrapper} ${styles.padd_left} ${
className={`${styles.clear_fix} ${styles.padd_left} ${
styles.padd_top
} ${metaDataStyles.metadata_wrapper} container-fluid`}
>

View File

@ -5,9 +5,11 @@
font-size: 16px;
font-weight: 600;
}
.margin_bottom_header {
margin-bottom: 10px;
}
.intro_note {
.intro_note_heading {
margin-bottom: 10px;
@ -15,6 +17,7 @@
margin-bottom: 20px;
margin-top: 20px;
}
.content_width {
margin-top: 10px;
width: 50%;

View File

@ -1,11 +1,14 @@
@import "../../../Common/Common.scss";
.migration_mode {
display: inline-block;
margin-left: 10px;
label {
display: flex;
align-items: center;
}
span {
margin-right: 10px;
font-weight: 700;

View File

@ -6,24 +6,27 @@ import 'brace/mode/sql';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import Tooltip from 'react-bootstrap/lib/Tooltip';
import Toggle from 'react-toggle';
import { updateMigrationModeStatus } from '../../../Main/Actions';
import './ReactToggle.css';
import '../../../Common/ReactToggle/ReactToggleOverrides.css';
const migrationTip = (
<Tooltip id="tooltip-migration">
Modifications to the underlying postgres schema should be tracked as
migrations.
</Tooltip>
);
import { updateMigrationModeStatus } from '../../../Main/Actions';
const MigrationsHome = ({ dispatch, migrationMode }) => {
const styles = require('./Styles.scss');
const styles = require('./Migrations.scss');
const handleMigrationModeToggle = () => {
const isConfirm = window.confirm('Are you sure?');
if (isConfirm) {
dispatch(updateMigrationModeStatus());
}
};
const migrationTip = (
<Tooltip id="tooltip-migration">
Modifications to the underlying postgres schema should be tracked as
migrations.
</Tooltip>
);
return (
<div className={'container-fluid'}>
<Helmet title="Migrations - Data | Hasura" />

View File

@ -1,13 +0,0 @@
@import "../../../Common/Common.scss";
.migration_mode {
display: inline-block;
margin-left: 10px;
label {
display: flex;
align-items: center;
}
span {
margin-right: 10px;
font-weight: 700;
}
}

View File

@ -4,7 +4,7 @@ import { showNotification, showTempNotification } from '../../App/Actions';
import { notifExpand, notifMsg } from '../../App/Actions';
import Button from '../../Common/Button/Button';
const styles = require('./TableCommon/Table.scss');
const styles = require('../../Common/TableCommon/Table.scss');
const showErrorNotification = (title, message, reqBody, error) => {
let modMessage;

View File

@ -1,32 +0,0 @@
/* State
{
ongoingRequest : false, //true if request is going on
lastError : null OR <string>
lastSuccess: null OR <string>
}
*/
import defaultState from './State';
const SET_USERNAME = 'PageContainer/SET_USERNAME';
// HTML Component defines what state it needs
// HTML Component should be able to emit actions
// When an action happens, the state is modified (using the reducer function)
// When the state is modified, anybody dependent on the state is asked to update
// HTML Component is listening to state, hence re-renders
const homeReducer = (state = defaultState, action) => {
switch (action.type) {
case SET_USERNAME:
return { username: action.data };
default:
return state;
}
};
const setUsername = username => ({ type: SET_USERNAME, data: username });
export default homeReducer;
export { setUsername };

View File

@ -1,247 +0,0 @@
/* eslint-disable no-unused-vars */
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import globals from '../../../../Globals';
import Button from '../../../Common/Button/Button';
import { LISTING_SCHEMA, UPDATE_TRACKED_FUNCTIONS } from '../DataActions';
import semverCheck from '../../../../helpers/semver';
const appPrefix = '/data';
const PageContainer = ({
schema,
listingSchema,
functionsList,
listedFunctions,
currentTable,
schemaName,
migrationMode,
children,
dispatch,
location,
currentFunction,
serverVersion,
}) => {
const styles = require('./PageContainer.scss');
const functionSymbol = require('./function.svg');
const functionSymbolActive = require('./function_high.svg');
const handleFunc = semverCheck('customFunctionSection', serverVersion)
? true
: false;
// Now schema might be null or an empty array
let tableLinks = [
<li className={styles.noTables} key="no-tables-1">
<i>No tables/views available</i>
</li>,
];
const tables = {};
listingSchema.map(t => {
tables[t.table_name] = t;
});
const currentLocation = location.pathname;
if (listingSchema && listingSchema.length) {
tableLinks = Object.keys(tables)
.sort()
.map((tableName, i) => {
let activeTableClass = '';
if (
tableName === currentTable &&
currentLocation.indexOf(currentTable) !== -1
) {
activeTableClass = styles.activeTable;
}
if (tables[tableName].detail.table_type === 'BASE TABLE') {
return (
<li className={activeTableClass} key={i}>
<Link
to={
appPrefix +
'/schema/' +
schemaName +
'/tables/' +
tableName +
'/browse'
}
data-test={tableName}
>
<i
className={styles.tableIcon + ' fa fa-table'}
aria-hidden="true"
/>
{tableName}
</Link>
</li>
);
}
return (
<li className={activeTableClass} key={i}>
<Link
to={
appPrefix +
'/schema/' +
schemaName +
'/views/' +
tableName +
'/browse'
}
data-test={tableName}
>
<i
className={styles.tableIcon + ' fa fa-table'}
aria-hidden="true"
/>
<i>{tableName}</i>
</Link>
</li>
);
});
}
const dividerHr = [
<li key={'fn-divider-1'}>
<hr className={styles.tableFunctionDivider} />
</li>,
];
// If the listedFunctions is non empty
if (listedFunctions.length > 0) {
const functionHtml = listedFunctions.map((f, i) => (
<li
className={
f.function_name === currentFunction ? styles.activeTable : ''
}
key={'fn ' + i}
>
<Link
to={
appPrefix +
'/schema/' +
schemaName +
'/functions/' +
f.function_name
}
data-test={f.function_name}
>
<div className={styles.display_inline + ' ' + styles.functionIcon}>
<img
src={
f.function_name === currentFunction
? functionSymbolActive
: functionSymbol
}
/>
</div>
{f.function_name}
</Link>
</li>
));
tableLinks = [...tableLinks, ...dividerHr, ...functionHtml];
} else if (
functionsList.length !== listedFunctions.length &&
listedFunctions.length === 0
) {
const noFunctionResult = [
<li className={styles.noTables}>
<i>No matching functions available</i>
</li>,
];
tableLinks = [...tableLinks, ...dividerHr, ...noFunctionResult];
}
function tableSearch(e) {
const searchTerm = e.target.value;
// form new schema
const matchedTables = [];
schema.map(table => {
if (table.table_name.indexOf(searchTerm) !== -1) {
matchedTables.push(table);
}
});
const matchedFuncs = functionsList.filter(
f => f.function_name.indexOf(searchTerm) !== -1
);
// update schema with matchedTables
dispatch({ type: LISTING_SCHEMA, updatedSchemas: matchedTables });
dispatch({ type: UPDATE_TRACKED_FUNCTIONS, data: matchedFuncs });
}
return (
<div className={styles.schemaTableList}>
<div className={styles.display_flex + ' ' + styles.padd_top_medium}>
<div
className={
styles.sidebarSearch + ' form-group col-xs-12 ' + styles.padd_remove
}
>
<i className="fa fa-search" aria-hidden="true" />
<input
type="text"
onChange={tableSearch.bind(this)}
className="form-control"
placeholder={`search table/view${handleFunc ? '/function' : ''}`}
data-test="search-tables"
/>
</div>
</div>
<div>
<div className={styles.sidebarHeadingWrapper}>
<div
className={
'col-xs-8 ' +
styles.sidebarHeading +
' ' +
styles.padd_left_remove
}
>
Tables ({schema.length})
</div>
{migrationMode ? (
<div
className={
'col-xs-4 text-center ' +
styles.padd_left_remove +
' ' +
styles.sidebarCreateTable
}
>
<Link
className={styles.padd_remove_full}
to={'/data/schema/' + schemaName + '/table/add'}
>
<Button size="xs" color="white" data-test="sidebar-add-table">
Add Table
</Button>
</Link>
</div>
) : null}
</div>
<ul className={styles.schemaListUl} data-test="table-links">
{tableLinks}
</ul>
</div>
</div>
);
};
const mapStateToProps = state => {
return {
schemaName: state.tables.currentSchema,
schema: state.tables.allSchemas,
listingSchema: state.tables.listingSchemas,
currentTable: state.tables.currentTable,
migrationMode: state.main.migrationMode,
functionsList: state.tables.trackedFunctions,
listedFunctions: state.tables.listedFunctions,
currentFunction: state.functions.functionName,
serverVersion: state.main.serverVersion ? state.main.serverVersion : '',
};
};
export default connect(mapStateToProps)(PageContainer);

View File

@ -1,5 +0,0 @@
const defaultState = {
username: 'Guest User',
};
export default defaultState;

View File

@ -64,7 +64,7 @@ const RawSQL = ({
migrationMode,
serverVersion,
}) => {
const styles = require('../TableCommon/Table.scss');
const styles = require('../../../Common/TableCommon/Table.scss');
let alert = null;
@ -181,9 +181,7 @@ const RawSQL = ({
const placeholderText = functionText ? 'this' : 'table';
return (
<div
className={`${styles.main_wrapper} ${styles.padd_left} ${
styles.padd_top
}`}
className={`${styles.clear_fix} ${styles.padd_left} ${styles.padd_top}`}
>
<Helmet title="Run SQL - Data | Hasura" />
<div className={styles.subHeader}>

View File

@ -15,9 +15,12 @@ class AutoAddRelations extends Component {
trackAllRelations = untrackedData => {
this.props.dispatch(autoTrackRelations(untrackedData));
};
render() {
const styles = require('../../../Common/Layout/LeftSubSidebar/LeftSubSidebar.scss');
const { untrackedRelations, dispatch } = this.props;
const styles = require('../PageContainer/PageContainer.scss');
const handleAutoAddIndivRel = obj => {
dispatch(autoAddRelName(obj));
};
@ -32,6 +35,7 @@ class AutoAddRelations extends Component {
</div>
);
}
const untrackData = untrackedRelations.map((obj, i) => {
return (
<div
@ -61,6 +65,7 @@ class AutoAddRelations extends Component {
</div>
);
});
return (
<div>
{untrackedRelations.length === 0 ? (

View File

@ -79,6 +79,8 @@ class Schema extends Component {
trackedFunctions,
} = this.props;
const styles = require('../../../Common/Layout/LeftSubSidebar/LeftSubSidebar.scss');
/* Filter */
const trackedFuncs = trackedFunctions.map(t => t.function_name);
// Assuming schema for both function and tables are same
@ -101,7 +103,6 @@ class Schema extends Component {
]);
};
const styles = require('../PageContainer/PageContainer.scss');
let relationships = 0;
schema.map(t => (relationships += t.relationships.length));

View File

@ -1,35 +0,0 @@
import React from 'react';
import Helmet from 'react-helmet';
// import PageContainer from '../PageContainer/PageContainer';
const SchemaContainer = ({ children }) => {
const styles = require('./SchemaContainer.scss');
return (
<div className={styles.container + ' container-fluid'}>
<Helmet title={'Schema | Data | Hasura'} />
<div className="row">
<div
className={
styles.main + ' ' + styles.padd_left_remove + ' ' + styles.padd_top
}
>
<div className={styles.rightBar + ' '}>
{children && React.cloneElement(children)}
</div>
</div>
</div>
</div>
);
};
const mapStateToProps = state => {
return {
schema: state.tables.allSchemas,
};
};
const schemaContainerConnector = connect =>
connect(mapStateToProps)(SchemaContainer);
export default schemaContainerConnector;

View File

@ -1,63 +0,0 @@
@import "~bootstrap-sass/assets/stylesheets/bootstrap/variables";
@import "../../../Common/Common.scss";
.flexRow {
display: flex;
}
.padd_left_remove
{
padding-left: 0;
}
.add_btn {
margin: 10px 0;
}
.account {
padding: 20px 0;
line-height: 26px;
}
.sidebar {
height: $mainContainerHeight;
overflow: auto;
background: #444;
color: $navbar-inverse-color;
hr {
margin: 0;
border-color: $navbar-inverse-color;
}
ul {
list-style-type: none;
padding-top: 10px;
padding-left: 7px;
li {
padding: 7px 0;
transition: color 0.5s;
a,a:visited {
color: $navbar-inverse-link-color;
}
a:hover {
color: $navbar-inverse-link-hover-color;
text-decoration: none;
}
}
li:hover {
padding: 7px 0;
color: $navbar-inverse-link-hover-color;
transition: color 0.5s;
pointer: cursor;
}
}
}
.main {
padding: 0;
padding-left: 15px;
height: $mainContainerHeight;
overflow: auto;
padding-right: 15px;
}
.rightBar {
padding-left: 15px;
}

View File

@ -65,7 +65,7 @@ class EditItem extends Component {
return null;
}
const styles = require('../TableCommon/Table.scss');
const styles = require('../../../Common/TableCommon/Table.scss');
const columns = schemas.find(x => x.table_name === tableName).columns;
const refs = {};

View File

@ -70,7 +70,7 @@ const renderOps = (opName, onChange, key) => (
);
const renderWheres = (whereAnd, tableSchema, dispatch) => {
const styles = require('./FilterQuery.scss');
const styles = require('../../../Common/FilterQuery/FilterQuery.scss');
return whereAnd.map((clause, i) => {
const colName = Object.keys(clause)[0];
const opName = Object.keys(clause[colName])[0];
@ -119,7 +119,7 @@ const renderWheres = (whereAnd, tableSchema, dispatch) => {
};
const renderSorts = (orderBy, tableSchema, dispatch) => {
const styles = require('./FilterQuery.scss');
const styles = require('../../../Common/FilterQuery/FilterQuery.scss');
return orderBy.map((c, i) => {
const dSetOrderCol = e => {
dispatch(setOrderCol(e.target.value, i));
@ -154,7 +154,9 @@ const renderSorts = (orderBy, tableSchema, dispatch) => {
}}
data-test={`sort-order-${i}`}
>
<option disabled value="">--</option>
<option disabled value="">
--
</option>
<option value="asc">Asc</option>
<option value="desc">Desc</option>
</select>
@ -173,7 +175,7 @@ class FilterQuery extends Component {
render() {
const { dispatch, whereAnd, tableSchema, orderBy } = this.props; // eslint-disable-line no-unused-vars
const styles = require('./FilterQuery.scss');
const styles = require('../../../Common/FilterQuery/FilterQuery.scss');
return (
<div className={styles.filterOptions}>
<form

View File

@ -1,95 +0,0 @@
@import "../../../Common/Common.scss";
$bgColor: #f9f9f9;
.container {
margin: 10px 0;
}
.count {
display: inline-block;
max-height: 34px;
padding: 5px 20px;
margin-left: 10px;
border-radius: 4px;
}
.queryBox {
box-sizing: border-box;
position: relative;
min-height: 30px;
.inputRow {
margin: 20px 0;
div[class^=col-xs-] {
padding-left: 0;
padding-right: 2.5px;
}
:global(.form-control) {
height: 35px;
padding: 0 12px;
}
:global(.form-control):focus {
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0px rgba(102, 175, 233, 0.6);
}
:global(.fa) {
padding-top: 8px;
font-size: 0.8em;
}
i:hover {
cursor: pointer;
color: #888;
}
.descending {
padding-left: 10px;
input {
margin-right: 5px;
}
margin-right: 10px;
}
}
}
.inline {
display: inline-block;
}
.runQuery {
margin-left: 0px;
margin-bottom: 20px;
:global(.form-control):focus {
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0px rgba(102, 175, 233, 0.6);
}
:global(.input-group) {
margin-top: -24px;
margin-right: 10px;
input {
max-width: 60px;
}
}
nav {
display: inline-block;
}
button {
margin-top: -24px;
margin-right: 15px;
}
}
.filterOptions {
margin-top: 10px;
background: $bgColor;
// padding: 20px;
}
.pagination {
margin: 0;
}
.boxHeading {
top: -0.55em;
line-height: 1.1em;
background: $bgColor;
display: inline-block;
position: absolute;
padding: 0 10px;
color: #929292;
font-weight: normal;
}

View File

@ -14,7 +14,7 @@ const ViewHeader = ({
dispatch,
allowRename,
}) => {
const styles = require('../TableCommon/Table.scss');
const styles = require('../../../Common/TableCommon/Table.scss');
let capitalised = tabName;
capitalised = capitalised[0].toUpperCase() + capitalised.slice(1);
const activeTab = tabNameMap[tabName];

View File

@ -1,8 +1,8 @@
import React from 'react';
import { Link } from 'react-router';
import 'react-table/react-table.css';
import './ReactTableFix.css';
import DragFoldTable from './DragFoldTable';
import '../../../Common/TableCommon/ReactTableOverrides.css';
import DragFoldTable from '../../../Common/TableCommon/DragFoldTable';
import {
vExpandRel,
@ -52,9 +52,9 @@ const ViewRows = ({
count,
expandedRow,
}) => {
const styles = require('../TableCommon/Table.scss');
const styles = require('../../../Common/TableCommon/Table.scss');
const checkIfSingleRow = (_curRelName) => {
const checkIfSingleRow = _curRelName => {
let _isSingleRow = false;
const parentTableSchema = parentTableName
@ -67,7 +67,9 @@ const ViewRows = ({
} else if (
_curRelName &&
parentTableSchema &&
parentTableSchema.relationships.find(r => r.name === _curRelName && r.rel_type === 'object')
parentTableSchema.relationships.find(
r => r.name === _curRelName && r.rel_type === 'object'
)
) {
// Am I an obj_rel for my parent?
_isSingleRow = true;
@ -76,8 +78,10 @@ const ViewRows = ({
return _isSingleRow;
};
const checkIfHasPrimaryKey = (_tableSchema) => {
return _tableSchema.primary_key && _tableSchema.primary_key.columns.length > 0;
const checkIfHasPrimaryKey = _tableSchema => {
return (
_tableSchema.primary_key && _tableSchema.primary_key.columns.length > 0
);
};
const getGridHeadings = (_columns, _relationships) => {
@ -107,13 +111,13 @@ const ViewRows = ({
Header: (
<div className="ellipsis" title="Click to sort">
<span className={styles.tableHeaderCell}>
{ columnName } <i className={'fa ' + sortIcon} />
{columnName} <i className={'fa ' + sortIcon} />
</span>
</div>
),
accessor: columnName,
id: columnName,
foldable: true
foldable: true,
});
});
@ -123,14 +127,12 @@ const ViewRows = ({
_gridHeadings.push({
Header: (
<div className="ellipsis">
<span className={styles.tableHeaderCell}>
{ relName }
</span>
<span className={styles.tableHeaderCell}>{relName}</span>
</div>
),
accessor: relName,
id: relName,
foldable: true
foldable: true,
});
});
@ -178,7 +180,7 @@ const ViewRows = ({
title={title}
data-test={`row-${type}-button-${rowIndex}`}
>
{ icon }
{icon}
</Button>
);
};
@ -201,17 +203,13 @@ const ViewRows = ({
handleClick = handleExpand;
}
const expanderIcon = (
<i className={`fa ${icon}`} />
);
const expanderIcon = <i className={`fa ${icon}`} />;
return getButton('expand', expanderIcon, title, handleClick);
};
const getEditButton = (pkClause) => {
const editIcon = (
<i className="fa fa-edit" />
);
const getEditButton = pkClause => {
const editIcon = <i className="fa fa-edit" />;
const handleEditClick = () => {
dispatch({ type: E_SET_EDITITEM, oldItem: row, pkClause });
@ -225,10 +223,8 @@ const ViewRows = ({
return getButton('edit', editIcon, editTitle, handleEditClick);
};
const getDeleteButton = (pkClause) => {
const deleteIcon = (
<i className="fa fa-trash" />
);
const getDeleteButton = pkClause => {
const deleteIcon = <i className="fa fa-trash" />;
const handleDeleteClick = () => {
dispatch(deleteItem(pkClause));
@ -236,13 +232,16 @@ const ViewRows = ({
const deleteTitle = 'Delete row';
return getButton('delete', deleteIcon, deleteTitle, handleDeleteClick);
return getButton(
'delete',
deleteIcon,
deleteTitle,
handleDeleteClick
);
};
const getCloneButton = () => {
const cloneIcon = (
<i className="fa fa-clone" />
);
const cloneIcon = <i className="fa fa-clone" />;
const handleCloneClick = () => {
dispatch({ type: I_SET_CLONE, clone: row });
@ -293,7 +292,7 @@ const ViewRows = ({
let cellTitle = '';
if (rowColumnValue === null) {
cellValue = (<i>NULL</i>);
cellValue = <i>NULL</i>;
cellTitle = 'NULL';
} else if (rowColumnValue === undefined) {
cellValue = 'NULL';
@ -306,9 +305,11 @@ const ViewRows = ({
cellTitle = cellValue;
}
return (
<div className={isExpanded ? styles.tableCellExpanded : ''} title={cellTitle}>
<div
className={isExpanded ? styles.tableCellExpanded : ''}
title={cellTitle}
>
{cellValue}
</div>
);
@ -326,17 +327,14 @@ const ViewRows = ({
const getRelExpander = (value, className, clickHandler) => {
return (
<a
href="#"
className={className}
onClick={clickHandler}
>
<a href="#" className={className} onClick={clickHandler}>
{value}
</a>
);
};
const isRelExpanded = curQuery.columns.find(c => c.name === rel.rel_name) !== undefined;
const isRelExpanded =
curQuery.columns.find(c => c.name === rel.rel_name) !== undefined;
if (isRelExpanded) {
const handleCloseClick = e => {
@ -344,16 +342,18 @@ const ViewRows = ({
dispatch(vCloseRel(curPath, rel.rel_name));
};
cellValue = getRelExpander('Close', styles.expanded, handleCloseClick);
cellValue = getRelExpander(
'Close',
styles.expanded,
handleCloseClick
);
} else {
const currentFkey = rel.rel_def.foreign_key_constraint_on;
const currentFkeyValue = row[currentFkey];
if (currentFkeyValue === null) {
// cannot be expanded as value is null
cellValue = (
<i>NULL</i>
);
cellValue = <i>NULL</i>;
} else {
// can be expanded
const pkClause = getPKClause();
@ -367,11 +367,7 @@ const ViewRows = ({
}
}
return (
<div>
{ cellValue }
</div>
);
return <div>{cellValue}</div>;
};
newRow[relName] = getRelCellContent();
@ -447,8 +443,8 @@ const ViewRows = ({
<div className="alert alert-warning" role="alert">
There is no unique identifier (primary Key) for a row. You need
at-least one primary key to allow editing, Please use{' '}
<Link to="/data/sql">Raw SQL</Link> to make one or more column as
primary key.
<Link to="/data/sql">Raw SQL</Link> to make one or more column
as primary key.
</div>
</div>
</div>
@ -499,7 +495,9 @@ const ViewRows = ({
return (
<ViewRows
key={i}
curTableName={findTableFromRel(schemas, tableSchema, rel).table_name}
curTableName={
findTableFromRel(schemas, tableSchema, rel).table_name
}
currentSchema={currentSchema}
curQuery={cq}
curFilter={curFilter}
@ -538,7 +536,8 @@ const ViewRows = ({
if (isProgressing) {
return (
<div>
{' '}<Spinner />{' '}
{' '}
<Spinner />{' '}
</div>
);
}
@ -612,11 +611,8 @@ const ViewRows = ({
};
const getTheadThProps = (finalState, some, column) => ({
onClick: (e) => {
if (
!disableSortColumn &&
column.id
) {
onClick: e => {
if (!disableSortColumn && column.id) {
sortByColumn(column.id, !e.shiftKey);
}
@ -675,19 +671,15 @@ const ViewRows = ({
return (
<div className={isVisible ? '' : 'hide '}>
{ getFilterQuery() }
{getFilterQuery()}
<hr />
{ getPrimaryKeyMsg() }
{getPrimaryKeyMsg()}
<div className="row">
<div className="col-xs-12">
<div className={styles.tableContainer}>
{ renderTableBody() }
</div>
<div className={styles.tableContainer}>{renderTableBody()}</div>
<br />
<br />
<div>
{ getChildComponent() }
</div>
<div>{getChildComponent()}</div>
</div>
</div>
</div>

View File

@ -15,7 +15,7 @@ const TableHeader = ({
dispatch,
allowRename,
}) => {
const styles = require('./Table.scss');
const styles = require('../../../Common/TableCommon/Table.scss');
let capitalised = tabName;
capitalised = capitalised[0].toUpperCase() + capitalised.slice(1);
let showCount = '';

View File

@ -49,7 +49,7 @@ class InsertItem extends Component {
dispatch,
} = this.props;
const styles = require('../TableCommon/Table.scss');
const styles = require('../../../Common/TableCommon/Table.scss');
const _columns = schemas.find(x => x.table_name === tableName).columns;
const refs = {};
const columns = _columns.sort(ordinalColSort);

View File

@ -38,7 +38,7 @@ const ColumnEditor = ({
}) => {
// eslint-disable-line no-unused-vars
const c = column;
const styles = require('./Modify.scss');
const styles = require('./ModifyTable.scss');
let [iname, inullable, iunique, idefault, icomment, itype] = [
null,
null,

View File

@ -86,7 +86,7 @@ class ModifyTable extends React.Component {
columnComment,
tableCommentEdit,
} = this.props;
const styles = require('./Modify.scss');
const styles = require('./ModifyTable.scss');
const tableSchema = allSchemas.find(t => t.table_name === tableName);
const hasPrimaryKeys =
tableSchema &&

View File

@ -1,4 +1,5 @@
@import "../../../Common/Common.scss";
.container {
padding: 0;
}
@ -25,8 +26,8 @@
:global(.form-control):focus {
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 rgba(102, 175, 233, 0.6);
}
.yellow_button, .yellow_button1
{
.yellow_button, .yellow_button1 {
text-align: center !important;
margin-right: 15px;
}
@ -52,20 +53,19 @@
.select {
margin-right: 10px;
}
.modifyMinWidth
{
.modifyMinWidth {
min-width: 735px;
}
.leftIndent {
padding-left: 0;
margin-left: 0 !important;
margin-right: 0 !important;
.insertRatio
{
.paddRight
{
select
{
.insertRatio {
.paddRight {
select {
width: 150px;
display: inline-block;
margin: 0 10px;
@ -74,10 +74,11 @@
}
}
}
hr
{
hr {
clear: both;
}
.removeBtnPadding {
padding-left: 66px;
}
@ -101,6 +102,7 @@ hr
box-shadow: none;
outline: none;
}
.nullable:focus {
box-shadow: none;
outline: none;
@ -127,8 +129,8 @@ hr
.relBlockRight {
width: 30%;
}
.radioWrapperAccess
{
.radioWrapperAccess {
background-color: #F2F4F6;
padding: 20px;
clear: both;
@ -175,14 +177,17 @@ hr
font-weight: bold;
width: 10%;
}
td:nth-child(2) {
overflow: auto;
max-width: 250px;
width: 250px;
}
.newRoleTd {
padding-top: 13px;
}
//.permissionDelete {
// cursor: pointer;
// margin-left: 10px;
@ -196,6 +201,10 @@ hr
cursor: pointer;
}
.bulkSelect {
margin-right: 10px !important;
}
.clickableCell {
cursor: pointer;
}
@ -255,6 +264,7 @@ hr
.center_radio_label_input {
display: flex;
align-content: center;
input {
margin-top: 0px;
}
@ -267,13 +277,16 @@ hr
margin-bottom: 5px;
word-wrap: break-word;
}
.editPermissionsSection.removePadding {
padding-top: 0px;
}
.editPermissionsSection {
margin: 5px;
padding: 10px;
word-wrap: break-word;
.columnListElement {
float: left;
margin-right: 50px;
@ -290,6 +303,7 @@ hr
.editActionButton {
margin-right: 20px;
}
.form_permission_insert_set_wrapper {
.permission_insert_set_wrapper {
.configure_insert_set_checkbox {
@ -297,37 +311,47 @@ hr
display: block;
margin-top: 10px;
margin-bottom: 10px;
label {
cursor: pointer;
min-height: 20px;
font-weight: normal;
input:not([disabled]) {
cursor: pointer;
}
}
}
.insertSetConfigRow {
margin: 10px 0px;
display: flex;
align-items: center;
.e_g_text {
font-style: italic;
}
.input_element_wrapper {
width: 20%;
i {
cursor: pointer;
}
select {
width: 100%;
}
input {
width: 100%;
}
}
}
.set_warning {
margin-left: 25px;
.danger_text {
color: red;
}
@ -338,4 +362,4 @@ hr
}
.chevron_mar_right {
margin-right: 5px;
}
}

View File

@ -75,7 +75,7 @@ class ModifyView extends Component {
migrationMode,
} = this.props;
const styles = require('./Modify.scss');
const styles = require('./ModifyTable.scss');
const tableSchema = allSchemas.find(t => t.table_name === tableName); // eslint-disable-line no-unused-vars

View File

@ -28,9 +28,7 @@ import {
PGTypes,
} from './utils';
import QueryBuilderJson from '../../../../QueryBuilderJson/QueryBuilderJson';
const styles = require('./Styles.scss');
import QueryBuilderJson from '../../../../Common/QueryBuilderJson/QueryBuilderJson';
class PermissionBuilder extends React.Component {
static propTypes = {
@ -126,6 +124,8 @@ class PermissionBuilder extends React.Component {
}
render() {
const styles = require('./PermissionBuilder.scss');
const wrapDoubleQuotes = value => {
return (
<span>

View File

@ -25,7 +25,7 @@ import {
permToggleAllowAggregation,
permToggleModifyLimit,
permCustomChecked,
permRemoveRole,
// permRemoveRole,
permSetBulkSelect,
permRemoveMultipleRoles,
permSetSameSelect,
@ -240,7 +240,7 @@ class Permissions extends Component {
currentSchema,
} = this.props;
const { showAggregation, showInsertPrefix, showUpdatePresets } = this.state;
const styles = require('../TableModify/Modify.scss');
const styles = require('../TableModify/ModifyTable.scss');
const getAllRoles = allTableSchemas => {
const _allRoles = [];
@ -609,9 +609,24 @@ class Permissions extends Component {
roleList
) => {
const permissionsSymbols = {
fullAccess: <i className={'fa fa-check ' + styles.permissionSymbolFA} aria-hidden="true" />,
noAccess: <i className={'fa fa-times ' + styles.permissionSymbolNA} aria-hidden="true" />,
partialAccess: <i className={'fa fa-filter ' + styles.permissionSymbolPA} aria-hidden="true" />,
fullAccess: (
<i
className={'fa fa-check ' + styles.permissionSymbolFA}
aria-hidden="true"
/>
),
noAccess: (
<i
className={'fa fa-times ' + styles.permissionSymbolNA}
aria-hidden="true"
/>
),
partialAccess: (
<i
className={'fa fa-filter ' + styles.permissionSymbolPA}
aria-hidden="true"
/>
),
};
return (
@ -703,160 +718,160 @@ class Permissions extends Component {
const setOptions =
insertState && insertState.localSet && insertState.localSet.length > 0
? insertState.localSet.map((s, i) => {
return (
<div className={styles.insertSetConfigRow} key={i}>
<div
className={
styles.display_inline +
return (
<div className={styles.insertSetConfigRow} key={i}>
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
}
>
<select
className="input-sm form-control"
value={s.key}
onChange={e => this.onSetKeyChange(e, 'insert')}
data-index-id={i}
data-test={'column-presets-column-' + i}
>
<select
className="input-sm form-control"
value={s.key}
onChange={e => this.onSetKeyChange(e, 'insert')}
data-index-id={i}
data-test={'column-presets-column-' + i}
>
<option value="" disabled>
<option value="" disabled>
Column Name
</option>
{columns && columns.length > 0
? columns.map((c, key) => (
<option
value={c.column_name}
data-column-type={c.data_type}
key={key}
>
{c.column_name}
</option>
))
: null}
</select>
</div>
<div
className={
styles.display_inline +
</option>
{columns && columns.length > 0
? columns.map((c, key) => (
<option
value={c.column_name}
data-column-type={c.data_type}
key={key}
>
{c.column_name}
</option>
))
: null}
</select>
</div>
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
}
>
<select
className="input-sm form-control"
onChange={e => this.onSetTypeChange(e, 'insert')}
data-index-id={i}
data-test={'column-presets-type-' + i}
value={setConfigValueType(s.value) || ''}
>
<select
className="input-sm form-control"
onChange={e => this.onSetTypeChange(e, 'insert')}
data-index-id={i}
data-test={'column-presets-type-' + i}
value={setConfigValueType(s.value) || ''}
>
<option value="" disabled>
<option value="" disabled>
Select Preset Type
</option>
<option value="static">static</option>
<option value="session">from session variable</option>
</select>
</div>
<div
className={
styles.display_inline +
</option>
<option value="static">static</option>
<option value="session">from session variable</option>
</select>
</div>
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
>
{setConfigValueType(s.value) === 'session' ? (
<InputGroup>
<InputGroup.Addon>X-Hasura-</InputGroup.Addon>
<input
className={'input-sm form-control '}
placeholder="column_value"
value={s.value.slice(X_HASURA_CONST.length)}
onChange={e => this.onSetValueChange(e, 'insert')}
data-test={'column-presets-value-' + i}
data-index-id={i}
data-prefix-val={X_HASURA_CONST}
/>
</InputGroup>
) : (
<EnhancedInput
}
>
{setConfigValueType(s.value) === 'session' ? (
<InputGroup>
<InputGroup.Addon>X-Hasura-</InputGroup.Addon>
<input
className={'input-sm form-control '}
placeholder="column_value"
type={
i in this.state.setOperations.insert.columnTypeMap
? this.state.setOperations.insert.columnTypeMap[i]
: ''
}
value={s.value}
value={s.value.slice(X_HASURA_CONST.length)}
onChange={e => this.onSetValueChange(e, 'insert')}
data-test={'column-presets-value-' + i}
indexId={i}
data-index-id={i}
data-prefix-val={X_HASURA_CONST}
/>
)}
</div>
{setConfigValueType(s.value) === 'session' ? (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper +
' ' +
styles.e_g_text
}
>
e.g. X-Hasura-User-Id
</div>
</InputGroup>
) : (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper +
' ' +
styles.e_g_text
}
>
e.g. false, 1, some-text
</div>
)}
{i !== insertState.localSet.length - 1 ? (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
>
<i
className="fa-lg fa fa-times"
onClick={e => this.deleteSetKeyVal(e, 'insert')}
data-index-id={i}
/>
</div>
) : (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
<EnhancedInput
placeholder="column_value"
type={
i in this.state.setOperations.insert.columnTypeMap
? this.state.setOperations.insert.columnTypeMap[i]
: ''
}
value={s.value}
onChange={e => this.onSetValueChange(e, 'insert')}
data-test={'column-presets-value-' + i}
indexId={i}
data-prefix-val={X_HASURA_CONST}
/>
)}
</div>
);
})
{setConfigValueType(s.value) === 'session' ? (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper +
' ' +
styles.e_g_text
}
>
e.g. X-Hasura-User-Id
</div>
) : (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper +
' ' +
styles.e_g_text
}
>
e.g. false, 1, some-text
</div>
)}
{i !== insertState.localSet.length - 1 ? (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
>
<i
className="fa-lg fa fa-times"
onClick={e => this.deleteSetKeyVal(e, 'insert')}
data-index-id={i}
/>
</div>
) : (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
/>
)}
</div>
);
})
: null;
return (
@ -928,160 +943,160 @@ class Permissions extends Component {
const setOptions =
updateState && updateState.localSet && updateState.localSet.length > 0
? updateState.localSet.map((s, i) => {
return (
<div className={styles.insertSetConfigRow} key={i}>
<div
className={
styles.display_inline +
return (
<div className={styles.insertSetConfigRow} key={i}>
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
}
>
<select
className="input-sm form-control"
value={s.key}
data-test={'column-presets-column-' + i}
onChange={e => this.onSetKeyChange(e, 'update')}
data-index-id={i}
>
<select
className="input-sm form-control"
value={s.key}
data-test={'column-presets-column-' + i}
onChange={e => this.onSetKeyChange(e, 'update')}
data-index-id={i}
>
<option value="" disabled>
<option value="" disabled>
Column Name
</option>
{columns && columns.length > 0
? columns.map((c, key) => (
<option
value={c.column_name}
data-column-type={c.data_type}
key={key}
>
{c.column_name}
</option>
))
: null}
</select>
</div>
<div
className={
styles.display_inline +
</option>
{columns && columns.length > 0
? columns.map((c, key) => (
<option
value={c.column_name}
data-column-type={c.data_type}
key={key}
>
{c.column_name}
</option>
))
: null}
</select>
</div>
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
}
>
<select
className="input-sm form-control"
onChange={e => this.onSetTypeChange(e, 'update')}
data-index-id={i}
data-test={'column-presets-type-' + i}
value={setConfigValueType(s.value) || ''}
>
<select
className="input-sm form-control"
onChange={e => this.onSetTypeChange(e, 'update')}
data-index-id={i}
data-test={'column-presets-type-' + i}
value={setConfigValueType(s.value) || ''}
>
<option value="" disabled>
<option value="" disabled>
Select Preset Type
</option>
<option value="static">static</option>
<option value="session">from session variable</option>
</select>
</div>
<div
className={
styles.display_inline +
</option>
<option value="static">static</option>
<option value="session">from session variable</option>
</select>
</div>
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
>
{setConfigValueType(s.value) === 'session' ? (
<InputGroup>
<InputGroup.Addon>X-Hasura-</InputGroup.Addon>
<input
className={'input-sm form-control '}
placeholder="column_value"
value={s.value.slice(X_HASURA_CONST.length)}
onChange={e => this.onSetValueChange(e, 'update')}
data-index-id={i}
data-prefix-val={X_HASURA_CONST}
data-test={'column-presets-value-' + i}
/>
</InputGroup>
) : (
<EnhancedInput
}
>
{setConfigValueType(s.value) === 'session' ? (
<InputGroup>
<InputGroup.Addon>X-Hasura-</InputGroup.Addon>
<input
className={'input-sm form-control '}
placeholder="column_value"
type={
i in this.state.setOperations.update.columnTypeMap
? this.state.setOperations.update.columnTypeMap[i]
: ''
}
value={s.value}
value={s.value.slice(X_HASURA_CONST.length)}
onChange={e => this.onSetValueChange(e, 'update')}
indexId={i}
data-index-id={i}
data-prefix-val={X_HASURA_CONST}
data-test={'column-presets-value-' + i}
/>
)}
</div>
{setConfigValueType(s.value) === 'session' ? (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper +
' ' +
styles.e_g_text
}
>
e.g. X-Hasura-User-Id
</div>
</InputGroup>
) : (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper +
' ' +
styles.e_g_text
}
>
e.g. false, 1, some-text
</div>
)}
{i !== updateState.localSet.length - 1 ? (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
>
<i
className="fa-lg fa fa-times"
onClick={e => this.deleteSetKeyVal(e, 'update')}
data-index-id={i}
/>
</div>
) : (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
<EnhancedInput
placeholder="column_value"
type={
i in this.state.setOperations.update.columnTypeMap
? this.state.setOperations.update.columnTypeMap[i]
: ''
}
value={s.value}
onChange={e => this.onSetValueChange(e, 'update')}
indexId={i}
data-prefix-val={X_HASURA_CONST}
data-test={'column-presets-value-' + i}
/>
)}
</div>
);
})
{setConfigValueType(s.value) === 'session' ? (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper +
' ' +
styles.e_g_text
}
>
e.g. X-Hasura-User-Id
</div>
) : (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper +
' ' +
styles.e_g_text
}
>
e.g. false, 1, some-text
</div>
)}
{i !== updateState.localSet.length - 1 ? (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
>
<i
className="fa-lg fa fa-times"
onClick={e => this.deleteSetKeyVal(e, 'update')}
data-index-id={i}
/>
</div>
) : (
<div
className={
styles.display_inline +
' ' +
styles.add_mar_right +
' ' +
styles.input_element_wrapper
}
/>
)}
</div>
);
})
: null;
return (
<div

View File

@ -79,7 +79,7 @@ class AddManualRelationship extends Component {
}
render() {
const styles = require('../TableModify/Modify.scss');
const styles = require('../TableModify/ModifyTable.scss');
const {
tableName,
allSchemas,

View File

@ -5,7 +5,7 @@ import Button from '../../../Common/Button/Button';
import { deleteRelMigrate, saveRenameRelationship } from './Actions';
import { showErrorNotification } from '../Notification';
import gqlPattern, { gqlRelErrorNotif } from '../Common/GraphQLValidation';
import styles from '../TableModify/Modify.scss';
import styles from '../TableModify/ModifyTable.scss';
class RelationshipEditor extends React.Component {
state = {

View File

@ -151,7 +151,7 @@ const AddRelationship = ({
tableName,
allSchemas
);
const styles = require('../TableModify/Modify.scss');
const styles = require('../TableModify/ModifyTable.scss');
if (
suggestedRelationshipsData.objectRel.length < 1 &&
suggestedRelationshipsData.arrayRel.length < 1
@ -356,8 +356,8 @@ class Relationships extends Component {
currentSchema,
schemaList,
} = this.props;
const styles = require('../TableModify/Modify.scss');
const tableStyles = require('../TableCommon/TableStyles.scss');
const styles = require('../TableModify/ModifyTable.scss');
const tableStyles = require('../../../Common/TableCommon/TableStyles.scss');
const tableSchema = allSchemas.find(t => t.table_name === tableName);
let alert = null;

View File

@ -85,8 +85,8 @@ class RelationshipsView extends Component {
migrationMode,
schemaList,
} = this.props;
const styles = require('../TableModify/Modify.scss');
const tableStyles = require('../TableCommon/TableStyles.scss');
const styles = require('../TableModify/ModifyTable.scss');
const tableStyles = require('../../../Common/TableCommon/TableStyles.scss');
const tableSchema = allSchemas.find(t => t.table_name === tableName);
let alert = null;

View File

@ -5,8 +5,8 @@
*
*/
export dataHeaderConnector from './DataHeader';
export PageContainer from './PageContainer/PageContainer';
export dataPageConnector from './DataPageContainer';
export PageContainer from './DataSubSidebar';
export viewTableConnector from './TableBrowseRows/ViewTable';
export addExistingTableViewConnector from './Add/AddExistingTableView';
export addTableConnector from './Add/AddTable';
@ -19,10 +19,9 @@ export relationshipsConnector from './TableRelationships/Relationships';
export relationshipsViewConnector from './TableRelationships/RelationshipsView';
export permissionsConnector from './TablePermissions/Permissions';
export schemaConnector from './Schema/Schema';
export schemaContainerConnector from './Schema/SchemaContainer';
export migrationsConnector from './Migrations/MigrationsHome';
export dataRouter from './DataRouter';
export dataRouterUtils from './DataRouter';
export dataReducer from './DataReducer';

View File

@ -232,7 +232,7 @@ class AddTrigger extends Component {
const { supportColumnChangeFeature, supportRetryTimeout } = this.state;
const styles = require('../TableCommon/Table.scss');
const styles = require('../TableCommon/EventTable.scss');
let createBtnText = 'Add Event Trigger';
if (ongoingRequest) {
createBtnText = 'Creating...';
@ -297,7 +297,7 @@ class AddTrigger extends Component {
/>
);
return (
<div key={i} className={styles.noPadd + ' col-md-4'}>
<div key={i} className={styles.padd_remove + ' col-md-4'}>
<div className={'checkbox '}>
<label>
{inputHtml}
@ -323,7 +323,7 @@ class AddTrigger extends Component {
</OverlayTrigger>{' '}
</h4>
{selectedOperations.update ? (
<div className={styles.clearBoth + ' ' + styles.listenColumnWrapper}>
<div className={styles.clear_fix + ' ' + styles.listenColumnWrapper}>
{' '}
{getColumnList('update')}{' '}
</div>
@ -470,7 +470,7 @@ class AddTrigger extends Component {
return (
<div
className={`${styles.addTablesBody} ${styles.main_wrapper} ${
className={`${styles.addTablesBody} ${styles.clear_fix} ${
styles.padd_left
}`}
>

View File

@ -1,70 +0,0 @@
import React from 'react';
import { Link } from 'react-router';
import Helmet from 'react-helmet';
import PageContainer from './PageContainer/PageContainer';
const appPrefix = '/events';
const EventHeader = ({
schema,
currentSchema,
children,
location,
dispatch,
}) => {
const styles = require('../Data/TableCommon/Table.scss');
const currentLocation = location.pathname;
return (
<div>
<Helmet title={'Events | Hasura'} />
<div className={styles.wd20 + ' ' + styles.align_left}>
<div
className={styles.pageSidebar + ' col-xs-12 ' + styles.padd_remove}
>
<div>
<ul>
<li
role="presentation"
className={
currentLocation.includes('events/manage') ? styles.active : ''
}
>
<Link className={styles.linkBorder} to={appPrefix + '/manage'}>
<div className={styles.schemaWrapper}>
<div
className={styles.schemaSidebarSection}
data-test="schema"
>
Manage
</div>
</div>
</Link>
<PageContainer
location={location}
schema={schema}
currentSchema={currentSchema}
dispatch={dispatch}
/>
</li>
</ul>
</div>
</div>
</div>
<div className={styles.wd80}>{children}</div>
</div>
);
};
const mapStateToProps = state => {
return {
schema: state.tables.allSchemas,
schemaList: state.tables.schemaList,
currentSchema: state.tables.currentSchema,
};
};
const eventHeaderConnector = connect => connect(mapStateToProps)(EventHeader);
export default eventHeaderConnector;

View File

@ -0,0 +1,64 @@
import React from 'react';
import { Link } from 'react-router';
import PageContainer from '../../Common/Layout/PageContainer/PageContainer';
import LeftContainer from '../../Common/Layout/LeftContainer/LeftContainer';
import EventSubSidebar from './EventSubSidebar';
const appPrefix = '/events';
const EventPageContainer = ({
schema,
currentSchema,
children,
location,
dispatch,
}) => {
const styles = require('../../Common/TableCommon/Table.scss');
const currentLocation = location.pathname;
const sidebarContent = (
<ul>
<li
role="presentation"
className={
currentLocation.includes('events/manage') ? styles.active : ''
}
>
<Link className={styles.linkBorder} to={appPrefix + '/manage'}>
Manage
</Link>
<EventSubSidebar
location={location}
schema={schema}
currentSchema={currentSchema}
dispatch={dispatch}
/>
</li>
</ul>
);
const helmet = 'Events | Hasura';
const leftContainer = <LeftContainer>{sidebarContent}</LeftContainer>;
return (
<PageContainer helmet={helmet} leftContainer={leftContainer}>
{children}
</PageContainer>
);
};
const mapStateToProps = state => {
return {
schema: state.tables.allSchemas,
schemaList: state.tables.schemaList,
currentSchema: state.tables.currentSchema,
};
};
const eventPageConnector = connect =>
connect(mapStateToProps)(EventPageContainer);
export default eventPageConnector;

Some files were not shown because too many files have changed in this diff Show More