Category Archives: Uncategorized

Adding navigation in Single Page App

The concept of Single Page App is that all modules will be dynamically rendered while user navigates the page, without reloading. Express routing which we added is providing this functionality for us, so let’s use it.

Adding navigation.

Let’s get started. Edit index.html and add the highlighted line so we will have some marker on the page that will indicate if the page reloads.

./index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Babel Webpack Boilerplate</title>
    </head>
    <body>
        <h3>SPA</h3>
        <div id="root"></div>
        <script type="text/javascript" src="dist/main-bundle.js"></script>
    </body>
</html>

 

Create header menu for navigation.

Let’s create new navigation component and call it Header component. Create new folder ./src/components/Header and add:

./src/components/Header/index.js

import React from 'react';
import { Link } from 'react-router-dom';

const styles = require('./styles.scss');

const Header = ( {title} ) => (
  <div>
    <h2>{ title }</h2>
    <div className={styles.wrapper}>
      <ul>
        <li><Link to='/'>HOME</Link></li>
        <li><Link to='/about'>ABOUT</Link></li>
        <li><Link to='/greetings'>GREETINGS</Link></li>   
        <li><Link to='/gallery'>GALLERY</Link></li>      
      </ul>
    </div>
  </div>
);

export default Header;

also add the CSS

./src/components/Header/styles.scss

.wrapper {
  
  ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    border: 1px solid #e7e7e7;
    background-color: #f3f3f3;
  }
  li {
    float: left;
  }

  li a {
    display: block;
    color: #666;
    text-align: center;
    padding: 14px 16px;
    text-decoration: none;
  }

  li a:hover:not(.active) {
      background-color: #ddd;
  }

  li a.active {
      color: white;
    
  }
}

Add header menu in our components.

Home component

We added home as a first link but we actually don’t have Home component, so let’s create a simple one and add header navigation there.

create ./src/components/Home folder and add:

./src/components/Home/index.js

import React from 'react';
import Header from '../Header';

const styles = require('./styles.scss');

const Home = () => (
  <div>
    <Header />
    <div className={styles.wrapper}>This is my home section.</div>
  </div>
)

export default Home;

and the css:

./src/components/Home/styles.js

.wrapper {
  background: rgb(141, 141, 172);
  color: white;
  text-align: center;
}

About component.

do the same for About component.

./src/components/About/index.js

import React from 'react';
import Header from '../Header';

const styles = require('./styles.scss');

const About = () => (
  <div>
    <Header />
    <div className={styles.wrapper}>This is the About section.</div>
  </div>
)

export default About;

./src/components/Home/styles.scss

.wrapper {
  background: rgb(141, 141, 172);
  color: white;
  text-align: center;
}

DogsCatalog container component.

and DogsCatalog container component

./src/containers/DogsCatalog/index.js

/* eslint-disable no-debugger */

import React, { Component } from 'react';
import { graphql } from 'react-apollo';
import DogDetails from './DogDetails';
import Header from '../../components/Header';

import query from './query';

const styles = require('./styles.scss');


class DogsCatalog extends Component {

  constructor(props) {
    super(props);
    this.state = {
        breed: "labrador"
    }
  }

  handleClick(breedType) {
    this.setState({
        breed: breedType
    });
  }

  render() {  
    if(typeof this.props.data.getDogsList == 'undefined') {
      return(
        <div>Loading ... </div>
      );
    }
    return(
      <div>
        <Header />
        <div className={styles.Wrapper}>
          <p>Dogs catalog</p>
          <div className={styles.Buttons}>
            {this.props.data.getDogsList.map( (dog) => {
              return (<button key={dog.id} onClick={ () => { this.handleClick(dog.breed) } }>{dog.breed}</button>);
            })}          
          </div>
          <DogDetails breed={this.state.breed} />
        </div>
      </div>
    );
  }
}


export default graphql(query, {})(DogsCatalog);

Greetings component.

./src/components/Greetings/index.js

import React from 'react';
import Header from '../Header';

const styles = require('./styles.scss');

const Greetings = (props) => (
  <div>
    <Header />
    <div className={styles.wrapper}><h2>Hello  {props.user}</h2></div>
  </div>
)



export default Greetings;

Set up the routes.

./src/components/app.index.js

import React, { Component } from 'react';
import Greetings from '../greetings';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import About from '../about';
import Home from '../Home';
import { ApolloProvider, graphql } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import DogsCatalog from '../../containers/DogsCatalog';
import fetch from 'unfetch';

export default class App extends Component {

  render() {

    const GRAPHQL_URL = 'http://localhost:4001/graphql';
    const client = new ApolloClient({
      link: new HttpLink({ uri:  GRAPHQL_URL, fetch: fetch }),
      cache: new InMemoryCache()
    });  

    return (
      <ApolloProvider client={client}>
        <Router>
          <Switch>
            <Route exact path="/" component={Home} />    
            <Route exact path="/About" component={About} />                      
            <Route exact path="/greetings" component={Greetings} />
            <Route exact path="/gallery" component={DogsCatalog} />
          </Switch>
        </Router>
      </ApolloProvider>
    );
  }
}

Basically we told Express which component to render for each route.

Give it a try and fire up the server using your preferred config.

At this point you will have neat SPA (Single Page App) that dynamically renders the components without ever reloading the page.

 

Setting up SSL host using LetsEncrypt free certificate and set up auto renewal shell script.

1. Obtain SSL certificates from the letsencrypt.org ACME server.Navigate to the location that you would like to add the script. I personally prefer to keep apps and scripts here:
cd ~/Applications

2. Download getssl (this is the auto renewal shell script)
git clone https://github.com/srvrco/getssl.git

4. Do initial setup
 ./getssl -c yourdomain.com

this command will create the following folders and files:

~/.getssl
~/.getssl/getssl.cfg
~/.getssl/yourdomain.com
~/.getssl/yourdomain.com/getssl.cfg

5. Edit ~/.getssl/getssl.cfg There are a couple of things that we have to set up:
– make sure that you switch to use the staging server while testing, since the production one has rate limits.

# The staging server is best for testing
CA="https://acme-staging.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"

6.Add the sub domains in ~/.getssl/yourdomain.com/getssl.cfg

# Additional domains - this could be multiple domains / subdomains in a comma separated list
# Note: this is Additional domains - so should not include the primary domain.
SANS="www.mysite.com, other.mysite.com"

– Very important: add the location where the script should put verification file in order to prove that you have ownership over this domain. For more information of what exactly is the prove of ownership procedure you could read https://letsencrypt.org/how-it-works/ but basically the bash script puts a small file into specific server directory and then the letsencrypt server checks id the file is there and ensures that you have control over this domain.
So Make sure that this folder (acme-challenge) is accessible on the web.
What that means is that if you put a test text file (e.e. test.txt) with any random text inside in this location: /webroot/.well-known/acme-challenge and then you open the browser and point to www.mysite.com/.well-known/acme-challenge/test.txt you should be able to see the contents of the file.
Once you did this you could go ahead and edit .getssl file and add the right location.

# Acme Challenge Location. The first line for the domain, the following ones for each additional domain.
# If these start with ssh: then the next variable is assumed to be the hostname and the rest the location.
# An ssh key will be needed to provide you with access to the remote server.
# Optionally, you can specify a different userid for ssh/scp to use on the remote server before the @ sign.
# If left blank, the username on the local server will be used to authenticate against the remote server.
# If these start with ftp: then the next variables are ftpuserid:ftppassword:servername:ACL_location
# These should be of the form "/path/to/your/website/folder/.well-known/acme-challenge"
# where "/path/to/your/website/folder/" is the path, on your web server, to the web root for your domain.
#ACL=('/var/www/toninichev.com/web/.well-known/acme-challenge'
#     'ssh:server5:/var/www/toninichev.com/web/.well-known/acme-challenge'
#     'ssh:sshuserid@server5:/var/www/toninichev.com/web/.well-known/acme-challenge'
#     'ftp:ftpuserid:ftppassword:toninichev.com:/web/.well-known/acme-challenge')

ACL=('/var/www/html/projects/src/webroot/.well-known/acme-challenge')

 Make sure that you replace /var/www/html/projects/src/ with the actual location on your server.
– one last thing that I did is to use single ACL to make my life easier

#Set USE_SINGLE_ACL="true" to use a single ACL for all checks
USE_SINGLE_ACL="true"

7. Execute the script and create certificate

~/Applications/getssl yourdomain.com

Again make sure that you navigate to the place where you did git clone of the script.

Example of adding certificate to an express server:

var options = {
    key: fs.readFileSync('/Users/toninichev/.getssl/mysite.com.key'),
    cert: fs.readFileSync('/Users/toninichev/.getssl/mysite.com.crt')
    };

/**
 * HTTP Server
 * Gets post requests from app_clients and sends data to the web_clients
 */
var app = https.createServer(options, function (request, response) {
...
});

Example of adding certificate to Apache virtual host:

<VirtualHost *:443>

    ServerName mywebsite.com
    ServerAlias www.mywebsite.com
    ServerAdmin info@mywebsite.com

    SSLEngine on
    SSLCertificateFile /Users/toninichev/.getssl/mywebsite.com/mywebsite.com.crt
    SSLCertificateKeyFile /Users/toninichev/.getssl/mywebsite.com/mywebsite.com.key

    ErrorLog "/private/var/log/apache2/mywebsite.com-error_log"
    CustomLog "/private/var/log/apache2/mywebsite.com-access_log" common

    SetEnv APPLICATION_ENV production
    DocumentRoot "/Users/toninichev/mywebsite/app/webroot"
    <Directory "/Users/toninichev/mywebsite/app/webroot">
        Options Indexes FollowSymLinks
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>

 

 

Two way communication between parent document and iFrame

This page is a simple demonstration of two way communication between iFrame and parent document even if they are hosted in different domains.

index.html

<html>
  <head>
    <style>
      iframe {
      width:50%;
      height:50%;
      }
    </style>

    <script>
      // Listen for iframe loaded event
      window.addEventListener("message", receiveMessage, false);
      function receiveMessage(event)
      {
        if(event.origin !== "http://sandbox.toni-develops.com")
        return
        console.log('[parent]' + event.data);
      }

      function postTheMessage() {
        document.querySelector('#my_iframe').contentWindow.postMessage("Parent doc messaged the iframe", "*");
      }
    </script>
  </head>

  <body>
    <div id="wrapper">
    <iframe id="my_iframe" src="./iframe.html"></iframe>
    <br>
    <button onclick="postTheMessage()">send message to the iframe</button>
    </div>
  </body>
</html>

Two very important notes:
– When we add an event listener, we have to explicitly specify that we are going to listen to a “message” (line 12) and not passing the actual message there.
– we have to declare the event listeners before loading the actual <iframe ..> tag.

 

iframe.html

<html>

<head></head>

<body>
  <script>
    window.addEventListener("message", receiveMessage, false);
    function receiveMessage(event) {
      if (event.origin !== "http://mydev.com")
        return
      console.log('[iframe]' + event.data);
    }
    function postTheMessage() {
      window.parent.postMessage("iFrame sent a message", "http://mydev.com/sandbox/*");
    }
    postTheMessage();
  </script>
  <p>I am an iFrame!</p>
  <br>
  <button onclick="postTheMessage()">click to post message to the parent document</button>
</body>

</html>

 

How this works:
– Parent document index.html is subscribing for events named “message” (line 12) and calls receiveMessage function (line 13) when the event occur.
– When document is loaded, and the iframe is ready, it emits message to index.html (line 19 in iframe.html)
– When parent document receives message, it makes sure that it comes from the domain that the parent document is interested in, so no other iframe could trigger this action (line 15 in index.html) If so, do something. In this case console.log the message.

 

Synchronizing Filezilla site config between all devices.

If you use several computers at work and at home, sometimes becomes quite handy to be able to have all site configs synced automatically instead of importing and exporting it after each change. And this is quite simple to achieve.
Filezilla stores site config in sitemanager.xml file, so all that you need to do is to replace this file with a copy stored in Dropbox, Google Drive or any other file synchronizing service.

  1. Locate sitemanager.xml file on your machine.
    Windows 7/8 & Vista – C:\Users\YourUserName\AppData\Roaming\FileZilla\sitemanager.xml
    Mac OSX – /users/YourUserName/.config/filezilla/sitemanager.xml
    Linux – /home/YourUserName/.filezilla/sitemanager.xml
  2. Create copy of this file to your favorite synchronizing folder: i.e.:\Dropbox\Settings\sitemanager.xml
  3. Create “softlink” (symbolic link) to the new location.
    Windows(open command prompt and type):
    mklink “C:\Users\YourUserName\AppData\Roaming\FileZilla\sitemanager.xml” “C:\Users\YourUserName\Dropbox\Settings\sitemanager.xml”OS X (terminal):
    ln -s /users/YourUserName/Dropbox/Settings/sitemanager.xml /users/YourUserName/.config/filezilla/sitemanager.xml

    Linux (terminal):
    ln -s /home/YourUserName/Dropbox/Settings/sitemanager.xml /home/YourUserName/.filezilla/sitemanager.xml

GIT bash cheatsheet

  • Create repository from existing folder in github

    – open terminal and navigate to project’s folder
    – initialize repository with git init

[bash]git init[/bash]

– (optionally) create `.gitignore` file and add all files and folders that should not be a part of the repository commit like: log folders, cache folders, .project, and perhaps .gitignore itself.

add all files and folders

[bash]git add .[/bash]

commit all files

[bash]git commit -m”My first commit”[/bash]

create new repository by logging into your github account and visiting http://github.com/new

– copy remote repository url

link local repository to the remote one

[bash]git remote add origin remote repository URL[/bash]

push new repository to the server

git push -u <origin> <branch-name>

-u specifies upstream

  • Clone existing repository

git clone myGitName@http://my.repository.com

– or clone specific branch

git clone -b branchname myGitName@http://my.repository.com

  • Show

all branches and their origin upstreams

git branch -avv

– a shows all branches (current branch is marked with * in front of the name
– v verbose

remote repository path

git remote show <origin>

remote repositories list

git ls-remote

  • Branches and day to day workflow

– create new branch

git checkout -b <new_branch_name>

– delete branch

locally:

git branch -D <branch_name>

on the remote server

git push --delete <origin-server> <branch-name>

– push new branch to remote repository

git push -u origin new_branch_name

– u upstream

– reset local repository to be the same like remote repository

git reset --hard head