You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by ku...@apache.org on 2017/07/14 16:07:08 UTC

[3/5] zeppelin git commit: [ZEPPELIN-2749] Use scalable file structure for zeppelin web

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/elasticInputCtrl/elasticInput.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/elasticInputCtrl/elasticInput.controller.js b/zeppelin-web/src/components/elasticInputCtrl/elasticInput.controller.js
deleted file mode 100644
index 507b2f6..0000000
--- a/zeppelin-web/src/components/elasticInputCtrl/elasticInput.controller.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-angular.module('zeppelinWebApp').controller('ElasticInputCtrl', ElasticInputCtrl)
-
-function ElasticInputCtrl () {
-  let vm = this
-  vm.showEditor = false
-  vm.value = ''
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/expandCollapse/expandCollapse.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/expandCollapse/expandCollapse.css b/zeppelin-web/src/components/expandCollapse/expandCollapse.css
deleted file mode 100644
index b1a60d8..0000000
--- a/zeppelin-web/src/components/expandCollapse/expandCollapse.css
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- .expandable {
-  display: none;
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/expandCollapse/expandCollapse.directive.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/expandCollapse/expandCollapse.directive.js b/zeppelin-web/src/components/expandCollapse/expandCollapse.directive.js
deleted file mode 100644
index c71fae0..0000000
--- a/zeppelin-web/src/components/expandCollapse/expandCollapse.directive.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-angular.module('zeppelinWebApp').directive('expandCollapse', expandCollapse)
-
-function expandCollapse () {
-  return {
-    restrict: 'EA',
-    link: function (scope, element, attrs) {
-      angular.element(element).click(function (event) {
-        if (angular.element(element).find('.expandable:visible').length > 1) {
-          angular.element(element).find('.expandable:visible').slideUp('slow')
-          angular.element(element).find('i.fa-folder-open').toggleClass('fa-folder fa-folder-open')
-        } else {
-          angular.element(element).find('.expandable').first().slideToggle('200', function () {
-            // do not toggle trash folder
-            if (angular.element(element).find('.fa-trash-o').length === 0) {
-              angular.element(element).find('i').first().toggleClass('fa-folder fa-folder-open')
-            }
-          })
-        }
-
-        let target = event.target
-
-        // add note
-        if (target.classList !== undefined && target.classList.contains('fa-plus') &&
-          target.tagName.toLowerCase() === 'i') {
-          return
-        }
-
-        event.stopPropagation()
-      })
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/filterNoteNames/filter-note-names.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/filterNoteNames/filter-note-names.html b/zeppelin-web/src/components/filterNoteNames/filter-note-names.html
deleted file mode 100644
index 071cba4..0000000
--- a/zeppelin-web/src/components/filterNoteNames/filter-note-names.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<input type="text"
-       class="note-name-query form-control"
-       ng-click="$event.stopPropagation()"
-       placeholder="&#xf002 Filter"
-       ng-model="$parent.query.q"
-       ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 300, 'blur': 0 } }" />

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/helium/helium-conf.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/helium/helium-conf.js b/zeppelin-web/src/components/helium/helium-conf.js
deleted file mode 100644
index 10ca18a..0000000
--- a/zeppelin-web/src/components/helium/helium-conf.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-export const HeliumConfFieldType = {
-  NUMBER: 'number',
-  JSON: 'json',
-  STRING: 'string',
-}
-
-/**
- * @param persisted <Object> including `type`, `description`, `defaultValue` for each conf key
- * @param spec <Object> including `value` for each conf key
- */
-export function mergePersistedConfWithSpec (persisted, spec) {
-  const confs = []
-
-  for (let name in spec) {
-    const specField = spec[name]
-    const persistedValue = persisted[name]
-
-    const value = (persistedValue) ? persistedValue : specField.defaultValue
-    const merged = {
-      name: name,
-      type: specField.type,
-      description: specField.description,
-      value: value,
-      defaultValue: specField.defaultValue,
-    }
-
-    confs.push(merged)
-  }
-
-  return confs
-}
-
-export function createAllPackageConfigs (defaultPackages, persistedConfs) {
-  let packageConfs = {}
-
-  for (let name in defaultPackages) {
-    const pkgSearchResult = defaultPackages[name]
-
-    const spec = pkgSearchResult.pkg.config
-    if (!spec) { continue }
-
-    const artifact = pkgSearchResult.pkg.artifact
-    if (!artifact) { continue }
-
-    let persistedConf = {}
-    if (persistedConfs[artifact]) {
-      persistedConf = persistedConfs[artifact]
-    }
-
-    const confs = mergePersistedConfWithSpec(persistedConf, spec)
-    packageConfs[name] = confs
-  }
-
-  return packageConfs
-}
-
-export function parseConfigValue (type, stringified) {
-  let value = stringified
-
-  try {
-    if (HeliumConfFieldType.NUMBER === type) {
-      value = parseFloat(stringified)
-    } else if (HeliumConfFieldType.JSON === type) {
-      value = JSON.parse(stringified)
-    }
-  } catch (error) {
-    // return just the stringified one
-    console.error(`Failed to parse conf type ${type}, value ${value}`)
-  }
-
-  return value
-}
-
-/**
- * persist key-value only
- * since other info (e.g type, desc) can be provided by default config
- */
-export function createPersistableConfig (currentConfs) {
-  const filtered = currentConfs.reduce((acc, c) => {
-    acc[c.name] = parseConfigValue(c.type, c.value)
-    return acc
-  }, {})
-
-  return filtered
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/helium/helium-package.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/helium/helium-package.js b/zeppelin-web/src/components/helium/helium-package.js
deleted file mode 100644
index 88d191a..0000000
--- a/zeppelin-web/src/components/helium/helium-package.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-export function createDefaultPackage (pkgSearchResult, sce) {
-  for (let pkgIdx in pkgSearchResult) {
-    const pkg = pkgSearchResult[pkgIdx]
-    pkg.pkg.icon = sce.trustAsHtml(pkg.pkg.icon)
-    if (pkg.enabled) {
-      pkgSearchResult.splice(pkgIdx, 1)
-      return pkg
-    }
-  }
-
-  // show first available version if package is not enabled
-  const result = pkgSearchResult[0]
-  pkgSearchResult.splice(0, 1)
-  return result
-}
-
-/**
- * create default packages based on `enabled` field and `latest` version.
- *
- * @param pkgSearchResults
- * @param sce angular `$sce` object
- * @returns {Object} including {name, pkgInfo}
- */
-export function createDefaultPackages (pkgSearchResults, sce) {
-  const defaultPackages = {}
-  // show enabled version if any version of package is enabled
-  for (let name in pkgSearchResults) {
-    const pkgSearchResult = pkgSearchResults[name]
-    defaultPackages[name] = createDefaultPackage(pkgSearchResult, sce)
-  }
-
-  return defaultPackages
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/helium/helium-type.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/helium/helium-type.js b/zeppelin-web/src/components/helium/helium-type.js
deleted file mode 100644
index 27b34fa..0000000
--- a/zeppelin-web/src/components/helium/helium-type.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-export const HeliumType = {
-  VISUALIZATION: 'VISUALIZATION',
-  SPELL: 'SPELL',
-  INTERPRETER: 'INTERPRETER',
-  APPLICATION: 'APPLICATION',
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/helium/helium.service.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/helium/helium.service.js b/zeppelin-web/src/components/helium/helium.service.js
deleted file mode 100644
index 46fcc85..0000000
--- a/zeppelin-web/src/components/helium/helium.service.js
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { HeliumType, } from './helium-type'
-import {
-  createAllPackageConfigs,
-  createPersistableConfig,
-  mergePersistedConfWithSpec,
-} from './helium-conf'
-import {
-  createDefaultPackages,
-} from './helium-package'
-
-angular.module('zeppelinWebApp').service('heliumService', heliumService)
-
-export default function heliumService ($http, $sce, baseUrlSrv) {
-  'ngInject'
-
-  let visualizationBundles = []
-  let visualizationPackageOrder = []
-  // name `heliumBundles` should be same as `HeliumBundleFactory.HELIUM_BUNDLES_VAR`
-  let heliumBundles = []
-  // map for `{ magic: interpreter }`
-  let spellPerMagic = {}
-  // map for `{ magic: package-name }`
-  let pkgNamePerMagic = {}
-
-  /**
-   * @param magic {string} e.g `%flowchart`
-   * @returns {SpellBase} undefined if magic is not registered
-   */
-  this.getSpellByMagic = function (magic) {
-    return spellPerMagic[magic]
-  }
-
-  this.executeSpell = function (magic, textWithoutMagic) {
-    const promisedConf = this.getSinglePackageConfigUsingMagic(magic)
-      .then(confs => createPersistableConfig(confs))
-
-    return promisedConf.then(conf => {
-      const spell = this.getSpellByMagic(magic)
-      const spellResult = spell.interpret(textWithoutMagic, conf)
-      const parsed = spellResult.getAllParsedDataWithTypes(
-        spellPerMagic, magic, textWithoutMagic)
-
-      return parsed
-    })
-  }
-
-  this.executeSpellAsDisplaySystem = function (magic, textWithoutMagic) {
-    const promisedConf = this.getSinglePackageConfigUsingMagic(magic)
-      .then(confs => createPersistableConfig(confs))
-
-    return promisedConf.then(conf => {
-      const spell = this.getSpellByMagic(magic)
-      const spellResult = spell.interpret(textWithoutMagic.trim(), conf)
-      const parsed = spellResult.getAllParsedDataWithTypes(spellPerMagic)
-
-      return parsed
-    })
-  }
-
-  this.getVisualizationCachedPackages = function () {
-    return visualizationBundles
-  }
-
-  this.getVisualizationCachedPackageOrder = function () {
-    return visualizationPackageOrder
-  }
-
-  /**
-   * @returns {Promise} which returns bundleOrder and cache it in `visualizationPackageOrder`
-   */
-  this.getVisualizationPackageOrder = function () {
-    return $http.get(baseUrlSrv.getRestApiBase() + '/helium/order/visualization')
-      .then(function (response, status) {
-        const order = response.data.body
-        visualizationPackageOrder = order
-        return order
-      })
-      .catch(function (error) {
-        console.error('Can not get bundle order', error)
-      })
-  }
-
-  this.setVisualizationPackageOrder = function (list) {
-    return $http.post(baseUrlSrv.getRestApiBase() + '/helium/order/visualization', list)
-  }
-
-  this.enable = function (name, artifact) {
-    return $http.post(baseUrlSrv.getRestApiBase() + '/helium/enable/' + name, artifact)
-  }
-
-  this.disable = function (name) {
-    return $http.post(baseUrlSrv.getRestApiBase() + '/helium/disable/' + name)
-  }
-
-  this.saveConfig = function (pkg, defaultPackageConfig, closeConfigPanelCallback) {
-    // in case of local package, it will include `/`
-    const pkgArtifact = encodeURIComponent(pkg.artifact)
-    const pkgName = pkg.name
-    const filtered = createPersistableConfig(defaultPackageConfig)
-
-    if (!pkgName || !pkgArtifact || !filtered) {
-      console.error(
-        `Can't save config for helium package '${pkgArtifact}'`, filtered)
-      return
-    }
-
-    const url = `${baseUrlSrv.getRestApiBase()}/helium/config/${pkgName}/${pkgArtifact}`
-    return $http.post(url, filtered)
-      .then(() => {
-        if (closeConfigPanelCallback) { closeConfigPanelCallback() }
-      }).catch((error) => {
-        console.error(`Failed to save config for ${pkgArtifact}`, error)
-      })
-  }
-
-  /**
-   * @returns {Promise<Object>} which including {name, Array<package info for artifact>}
-   */
-  this.getAllPackageInfo = function () {
-    return $http.get(`${baseUrlSrv.getRestApiBase()}/helium/package`)
-      .then(function (response, status) {
-        return response.data.body
-      })
-      .catch(function (error) {
-        console.error('Failed to get all package infos', error)
-      })
-  }
-
-  this.getAllEnabledPackages = function () {
-    return $http.get(`${baseUrlSrv.getRestApiBase()}/helium/enabledPackage`)
-      .then(function (response, status) {
-        return response.data.body
-      })
-      .catch(function (error) {
-        console.error('Failed to get all enabled package infos', error)
-      })
-  }
-
-  this.getSingleBundle = function (pkgName) {
-    let url = `${baseUrlSrv.getRestApiBase()}/helium/bundle/load/${pkgName}`
-    if (process.env.HELIUM_BUNDLE_DEV) {
-      url = url + '?refresh=true'
-    }
-
-    return $http.get(url)
-      .then(function (response, status) {
-        const bundle = response.data
-        if (bundle.substring(0, 'ERROR:'.length) === 'ERROR:') {
-          console.error(`Failed to get bundle: ${pkgName}`, bundle)
-          return '' // empty bundle will be filtered later
-        }
-
-        return bundle
-      })
-      .catch(function (error) {
-        console.error(`Failed to get single bundle: ${pkgName}`, error)
-      })
-  }
-
-  this.getDefaultPackages = function () {
-    return this.getAllPackageInfo()
-      .then(pkgSearchResults => {
-        return createDefaultPackages(pkgSearchResults, $sce)
-      })
-  }
-
-  this.getAllPackageInfoAndDefaultPackages = function () {
-    return this.getAllPackageInfo()
-      .then(pkgSearchResults => {
-        return {
-          pkgSearchResults: pkgSearchResults,
-          defaultPackages: createDefaultPackages(pkgSearchResults, $sce),
-        }
-      })
-  }
-
-  /**
-   * get all package configs.
-   * @return { Promise<{name, Array<Object>}> }
-   */
-  this.getAllPackageConfigs = function () {
-    const promisedDefaultPackages = this.getDefaultPackages()
-    const promisedPersistedConfs =
-      $http.get(`${baseUrlSrv.getRestApiBase()}/helium/config`)
-      .then(function (response, status) {
-        return response.data.body
-      })
-
-    return Promise.all([promisedDefaultPackages, promisedPersistedConfs])
-      .then(values => {
-        const defaultPackages = values[0]
-        const persistedConfs = values[1]
-
-        return createAllPackageConfigs(defaultPackages, persistedConfs)
-      })
-      .catch(function (error) {
-        console.error('Failed to get all package configs', error)
-      })
-  }
-
-  /**
-   * get the package config which is persisted in server.
-   * @return { Promise<Array<Object>> }
-   */
-  this.getSinglePackageConfigs = function (pkg) {
-    const pkgName = pkg.name
-    // in case of local package, it will include `/`
-    const pkgArtifact = encodeURIComponent(pkg.artifact)
-
-    if (!pkgName || !pkgArtifact) {
-      console.error('Failed to fetch config for\n', pkg)
-      return Promise.resolve([])
-    }
-
-    const confUrl = `${baseUrlSrv.getRestApiBase()}/helium/config/${pkgName}/${pkgArtifact}`
-    const promisedConf = $http.get(confUrl)
-      .then(function (response, status) {
-        return response.data.body
-      })
-
-    return promisedConf.then(({confSpec, confPersisted}) => {
-      const merged = mergePersistedConfWithSpec(confPersisted, confSpec)
-      return merged
-    })
-  }
-
-  this.getSinglePackageConfigUsingMagic = function (magic) {
-    const pkgName = pkgNamePerMagic[magic]
-
-    const confUrl = `${baseUrlSrv.getRestApiBase()}/helium/spell/config/${pkgName}`
-    const promisedConf = $http.get(confUrl)
-      .then(function (response, status) {
-        return response.data.body
-      })
-
-    return promisedConf.then(({confSpec, confPersisted}) => {
-      const merged = mergePersistedConfWithSpec(confPersisted, confSpec)
-      return merged
-    })
-  }
-
-  const p = this.getAllEnabledPackages()
-    .then(enabledPackageSearchResults => {
-      const promises = enabledPackageSearchResults.map(packageSearchResult => {
-        const pkgName = packageSearchResult.pkg.name
-        return this.getSingleBundle(pkgName)
-      })
-
-      return Promise.all(promises)
-    })
-    .then(bundles => {
-      return bundles.reduce((acc, b) => {
-        // filter out empty bundle
-        if (b === '') { return acc }
-        acc.push(b)
-        return acc
-      }, [])
-    })
-
-  // load should be promise
-  this.load = p.then(availableBundles => {
-    // evaluate bundles
-    availableBundles.map(b => {
-      // eslint-disable-next-line no-eval
-      eval(b)
-    })
-
-    // extract bundles by type
-    heliumBundles.map(b => {
-      if (b.type === HeliumType.SPELL) {
-        const spell = new b.class() // eslint-disable-line new-cap
-        const pkgName = b.id
-        spellPerMagic[spell.getMagic()] = spell
-        pkgNamePerMagic[spell.getMagic()] = pkgName
-      } else if (b.type === HeliumType.VISUALIZATION) {
-        visualizationBundles.push(b)
-      }
-    })
-  })
-
-  this.init = function() {
-    this.getVisualizationPackageOrder()
-  }
-
-  // init
-  this.init()
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/interpreter/interpreter.directive.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/interpreter/interpreter.directive.js b/zeppelin-web/src/components/interpreter/interpreter.directive.js
deleted file mode 100644
index 7080760..0000000
--- a/zeppelin-web/src/components/interpreter/interpreter.directive.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-angular.module('zeppelinWebApp').directive('interpreterDirective', interpreterDirective)
-
-function interpreterDirective ($timeout) {
-  'ngInject'
-
-  return {
-    restrict: 'A',
-    link: function (scope, element, attr) {
-      if (scope.$last === true) {
-        $timeout(function () {
-          let id = 'ngRenderFinished'
-          scope.$emit(id)
-        })
-      }
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/interpreter/widget/widget.number.directive.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/interpreter/widget/widget.number.directive.js b/zeppelin-web/src/components/interpreter/widget/widget.number.directive.js
deleted file mode 100644
index 5d66cd1..0000000
--- a/zeppelin-web/src/components/interpreter/widget/widget.number.directive.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-angular.module('zeppelinWebApp').directive('widgetNumber', numericOnly)
-
-function numericOnly() {
-  return {
-    require: 'ngModel',
-    link: function (scope, element, attrs, modelCtrl) {
-      modelCtrl.$parsers.push(function (inputValue) {
-        let transformedInput = inputValue ? inputValue.replace(/[^\d.-]/g, '') : null
-        if (transformedInput !== inputValue) {
-          modelCtrl.$setViewValue(transformedInput)
-          modelCtrl.$render()
-        }
-        return transformedInput
-      })
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/login/login.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/login/login.html b/zeppelin-web/src/components/login/login.html
index cd3b604..d4a94a6 100644
--- a/zeppelin-web/src/components/login/login.html
+++ b/zeppelin-web/src/components/login/login.html
@@ -17,7 +17,7 @@ limitations under the License.
     <div class="modal-dialog">
 
       <!-- Modal content-->
-      <div class="modal-content" id="NoteImportCtrl" ng-init="NoteImportInit">
+      <div id="loginModalContent" class="modal-content">
         <div class="modal-header">
           <button type="button" class="close" data-dismiss="modal">&times;</button>
           <h4 class="modal-title">Login</h4>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/modal-shortcut/modal-shortcut.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/modal-shortcut/modal-shortcut.html b/zeppelin-web/src/components/modal-shortcut/modal-shortcut.html
deleted file mode 100644
index 775da4f..0000000
--- a/zeppelin-web/src/components/modal-shortcut/modal-shortcut.html
+++ /dev/null
@@ -1,312 +0,0 @@
-<!--
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-<div class="modal fade" id="shortcutModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
-  <div class="modal-dialog">
-    <div class="modal-content">
-      <div class="shortcut-modal-header">
-        <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
-        <h4 class="shortcut-modal-title" id="myModalLabel">Keyboard shortcuts</h4>
-      </div>
-      <div class="table-scroll">
-        <table class="table table-shortcut">
-          <tr>
-            <th style="width:70%">Note Keyboard Shortcuts</th>
-            <th></th>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Run paragraph</div>
-           </td>
-           <td>
-              <div class="keys">
-                <kbd class="kbd-default">Shift</kbd> + <kbd class="kbd-default">Enter</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Cancel</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">C</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Move cursor Up</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">P</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Move cursor Down</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">N</kbd>
-              </div>
-            </td>
-          </tr>
-
-        <tr>
-          <td>
-            <div class="col-md-8">Remove paragraph</div>
-          </td>
-          <td>
-            <div class="keys">
-              <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">D</kbd>
-            </div>
-          </td>
-        </tr>
-
-        <tr>
-          <td>
-            <div class="col-md-8">Insert new paragraph above</div>
-          </td>
-          <td>
-            <div class="keys">
-              <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">A</kbd>
-            </div>
-          </td>
-        </tr>
-
-        <tr>
-          <td>
-            <div class="col-md-8">Insert new paragraph below</div>
-          </td>
-          <td>
-            <div class="keys">
-              <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">B</kbd>
-            </div>
-          </td>
-        </tr>
-
-        <tr>
-          <td>
-            <div class="col-md-8">Insert copy of paragraph below</div>
-          </td>
-          <td>
-            <div class="keys">
-              <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">Shift</kbd> + <kbd class="kbd-default">C</kbd>
-            </div>
-          </td>
-        </tr>
-
-        <tr>
-          <td>
-            <div class="col-md-8">Move paragraph Up</div>
-          </td>
-          <td>
-            <div class="keys">
-              <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">K</kbd>
-            </div>
-          </td>
-        </tr>
-
-        <tr>
-          <td>
-            <div class="col-md-8">Move paragraph Down</div>
-          </td>
-          <td>
-            <div class="keys">
-              <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">J</kbd>
-            </div>
-          </td>
-        </tr>
-
-        <tr>
-          <td>
-            <div class="col-md-8">Enable/Disable run paragraph</div>
-          </td>
-          <td>
-            <div class="keys">
-              <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt' }}</kbd> + <kbd class="kbd-default">R</kbd>
-            </div>
-          </td>
-        </tr>
-
-        <tr>
-          <td>
-            <div class="col-md-8">Toggle output</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">O</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Toggle editor</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">E</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Toggle line number</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">M</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Toggle title</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">T</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Clear output</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">L</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Link this paragraph</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-default">W</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Reduce paragraph width</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">Shift</kbd> + <kbd class="kbd-default">-</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Increase paragraph width</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">Shift</kbd> + <kbd class="kbd-default">+</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr class="sub-title">
-            <th style="width:70%">Editor Keyboard Shortcuts</th>
-            <th></th>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Auto-completion</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">.</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Cut the line</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">K</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Paste the line</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">Y</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Search inside the code</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">S</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Move cursor to the beginning</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">A</kbd>
-              </div>
-            </td>
-          </tr>
-
-          <tr>
-            <td>
-              <div class="col-md-8">Move cursor at the end</div>
-            </td>
-            <td>
-              <div class="keys">
-                <kbd class="kbd-default">Ctrl</kbd> + <kbd class="kbd-default">E</kbd>
-              </div>
-            </td>
-          </tr>
-        </table>
-      </div>
-    </div>
-  </div>
-</div>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/navbar/expand-collapse/expand-collapse.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/expand-collapse/expand-collapse.css b/zeppelin-web/src/components/navbar/expand-collapse/expand-collapse.css
new file mode 100644
index 0000000..b1a60d8
--- /dev/null
+++ b/zeppelin-web/src/components/navbar/expand-collapse/expand-collapse.css
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ .expandable {
+  display: none;
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/navbar/expand-collapse/expand-collapse.directive.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/expand-collapse/expand-collapse.directive.js b/zeppelin-web/src/components/navbar/expand-collapse/expand-collapse.directive.js
new file mode 100644
index 0000000..95e0681
--- /dev/null
+++ b/zeppelin-web/src/components/navbar/expand-collapse/expand-collapse.directive.js
@@ -0,0 +1,48 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import './expand-collapse.css'
+
+angular.module('zeppelinWebApp').directive('expandCollapse', expandCollapseDirective)
+
+function expandCollapseDirective() {
+  return {
+    restrict: 'EA',
+    link: function (scope, element, attrs) {
+      angular.element(element).click(function (event) {
+        if (angular.element(element).find('.expandable:visible').length > 1) {
+          angular.element(element).find('.expandable:visible').slideUp('slow')
+          angular.element(element).find('i.fa-folder-open').toggleClass('fa-folder fa-folder-open')
+        } else {
+          angular.element(element).find('.expandable').first().slideToggle('200', function () {
+            // do not toggle trash folder
+            if (angular.element(element).find('.fa-trash-o').length === 0) {
+              angular.element(element).find('i').first().toggleClass('fa-folder fa-folder-open')
+            }
+          })
+        }
+
+        let target = event.target
+
+        // add note
+        if (target.classList !== undefined && target.classList.contains('fa-plus') &&
+          target.tagName.toLowerCase() === 'i') {
+          return
+        }
+
+        event.stopPropagation()
+      })
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/navbar/navbar-note-list-elem.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/navbar-note-list-elem.html b/zeppelin-web/src/components/navbar/navbar-note-list-elem.html
new file mode 100644
index 0000000..cb36cfa
--- /dev/null
+++ b/zeppelin-web/src/components/navbar/navbar-note-list-elem.html
@@ -0,0 +1,50 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<a class="notebook-list-item" ng-if="navbar.isFilterNote(node) && !node.children" href="#/notebook/{{node.id}}">
+  <i style="font-size: 10px; margin-right: 5px;" ng-class="query.q && node.isTrash ? 'fa fa-trash-o' : 'icon-doc'" ></i>
+  <span>{{noteName(node)}}</span>
+</a>
+
+<li ng-if="node.children">
+  <expand-collapse>
+      <div ng-mouseenter="showFolderButton=true" ng-mouseleave="showFolderButton=false">
+        <a class="notebook-list-item" href="javascript:void(0)">
+          <div ng-if="node.id !== navbar.TRASH_FOLDER_ID">
+            <i style="font-size: 10px; margin-right: 5px;" class="fa fa-folder"></i>
+            <span>{{noteName(node)}}</span>
+            <i data-toggle="modal" data-target="#noteCreateModal" ng-controller="NoteCreateCtrl as noteCreateCtrl"
+              ng-click="noteCreateCtrl.getInterpreterSettings()" data-path="{{node.id}}"
+              style="font-size: 12px; margin-left: 5px; margin-right: 5px;"
+              ng-show="showFolderButton" class="fa fa-plus"
+              uib-tooltip="Create new note"
+              tooltip-placement="{{calculateTooltipPlacement(node)}}">
+            </i>
+          </div>
+          <div ng-if="node.id === navbar.TRASH_FOLDER_ID">
+            <i style="font-size: 12px; margin-right: 5px;" class="fa fa-trash-o"></i>
+            <span>Trash</span>
+          </div>
+        </a>
+      </div>
+      <div class="expandable" style="color: black;">
+        <ul>
+          <li ng-repeat="node in node.children | orderBy:node:false:navbar.arrayOrderingSrv.noteComparator track by $index"
+              ng-class="{'active' : navbar.isActive(node.id)}"
+              ng-include="'components/navbar/navbar-note-list-elem.html'">
+          </li>
+        </ul>
+      </div>
+  </expand-collapse>
+</li>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/navbar/navbar-noteList-elem.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/navbar-noteList-elem.html b/zeppelin-web/src/components/navbar/navbar-noteList-elem.html
deleted file mode 100644
index 6cba04a..0000000
--- a/zeppelin-web/src/components/navbar/navbar-noteList-elem.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!--
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-<a class="notebook-list-item" ng-if="navbar.isFilterNote(node) && !node.children" href="#/notebook/{{node.id}}">
-  <i style="font-size: 10px; margin-right: 5px;" ng-class="query.q && node.isTrash ? 'fa fa-trash-o' : 'icon-doc'" ></i>
-  <span>{{noteName(node)}}</span>
-</a>
-
-<li ng-if="node.children">
-  <expand-collapse>
-      <div ng-mouseenter="showFolderButton=true" ng-mouseleave="showFolderButton=false">
-        <a class="notebook-list-item" href="javascript:void(0)">
-          <div ng-if="node.id !== navbar.TRASH_FOLDER_ID">
-            <i style="font-size: 10px; margin-right: 5px;" class="fa fa-folder"></i>
-            <span>{{noteName(node)}}</span>
-            <i data-toggle="modal" data-target="#noteNameModal" ng-controller="NotenameCtrl as notenamectrl"
-              ng-click="notenamectrl.getInterpreterSettings()" data-path="{{node.id}}"
-              style="font-size: 12px; margin-left: 5px; margin-right: 5px;"
-              ng-show="showFolderButton" class="fa fa-plus"
-              uib-tooltip="Create new note"
-              tooltip-placement="{{calculateTooltipPlacement(node)}}">
-            </i>
-          </div>
-          <div ng-if="node.id === navbar.TRASH_FOLDER_ID">
-            <i style="font-size: 12px; margin-right: 5px;" class="fa fa-trash-o"></i>
-            <span>Trash</span>
-          </div>
-        </a>
-      </div>
-      <div class="expandable" style="color: black;">
-        <ul>
-          <li ng-repeat="node in node.children | orderBy:node:false:navbar.arrayOrderingSrv.noteComparator track by $index"
-              ng-class="{'active' : navbar.isActive(node.id)}"
-              ng-include="'components/navbar/navbar-noteList-elem.html'">
-          </li>
-        </ul>
-      </div>
-  </expand-collapse>
-</li>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/navbar/navbar.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/navbar.controller.js b/zeppelin-web/src/components/navbar/navbar.controller.js
index 28a900e..0ac2f18 100644
--- a/zeppelin-web/src/components/navbar/navbar.controller.js
+++ b/zeppelin-web/src/components/navbar/navbar.controller.js
@@ -15,7 +15,7 @@
 angular.module('zeppelinWebApp').controller('NavCtrl', NavCtrl)
 
 function NavCtrl ($scope, $rootScope, $http, $routeParams, $location,
-                 noteListDataFactory, baseUrlSrv, websocketMsgSrv,
+                 noteListFactory, baseUrlSrv, websocketMsgSrv,
                  arrayOrderingSrv, searchService, TRASH_FOLDER_ID) {
   'ngInject'
 
@@ -24,7 +24,7 @@ function NavCtrl ($scope, $rootScope, $http, $routeParams, $location,
   vm.connected = websocketMsgSrv.isConnected()
   vm.isActive = isActive
   vm.logout = logout
-  vm.notes = noteListDataFactory
+  vm.notes = noteListFactory
   vm.search = search
   vm.searchForm = searchService
   vm.showLoginWindow = showLoginWindow
@@ -123,7 +123,7 @@ function NavCtrl ($scope, $rootScope, $http, $routeParams, $location,
    */
 
   $scope.$on('setNoteMenu', function (event, notes) {
-    noteListDataFactory.setNotes(notes)
+    noteListFactory.setNotes(notes)
     initNotebookListEventListener()
   })
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/navbar/navbar.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/navbar/navbar.html b/zeppelin-web/src/components/navbar/navbar.html
index d5e6668..597ed51 100644
--- a/zeppelin-web/src/components/navbar/navbar.html
+++ b/zeppelin-web/src/components/navbar/navbar.html
@@ -37,23 +37,23 @@ limitations under the License.
             <span>Notebook</span>
             <span class="caret"></span></a>
           <ul class="dropdown-menu" role="menu">
-            <li ng-controller="NotenameCtrl as notenamectrl">
-              <a href="" data-toggle="modal" data-target="#noteNameModal" ng-click="notenamectrl.getInterpreterSettings()">
+            <li ng-controller="NoteCreateCtrl as noteCreateCtrl">
+              <a href="" data-toggle="modal" data-target="#noteCreateModal" ng-click="noteCreateCtrl.getInterpreterSettings()">
                 <i class="fa fa-plus"></i>
                 Create new note
               </a>
             </li>
             <li class="divider hidden-xs"></li>
             <div id="notebook-list" class="scrollbar-container" ng-if="isDrawNavbarNoteList">
-              <li class="filter-names" ng-include="'components/filterNoteNames/filter-note-names.html'"></li>
+              <li class="filter-names" ng-include="'components/note-name-filter/note-name-filter.html'"></li>
               <div ng-if="!query.q || query.q === ''">
               <li ng-repeat="node in navbar.notes.root.children | orderBy:node:false:navbar.arrayOrderingSrv.noteComparator track by node.id"
-                  ng-class="{'active' : navbar.isActive(node.id)}" ng-include="'components/navbar/navbar-noteList-elem.html'">
+                  ng-class="{'active' : navbar.isActive(node.id)}" ng-include="'components/navbar/navbar-note-list-elem.html'">
               </li>
             </div>
             <div ng-if="query.q">
               <li ng-repeat="node in navbar.notes.flatList | filter : query.q | orderBy:navbar.arrayOrderingSrv.noteFlatListOrdering track by node.id"
-                  ng-class="{'active' : navbar.isActive(node.id)}" ng-include="'components/navbar/navbar-noteList-elem.html'">
+                  ng-class="{'active' : navbar.isActive(node.id)}" ng-include="'components/navbar/navbar-note-list-elem.html'">
               </li>
             </div>
             </div>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/ng-enter/ng-enter.directive.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/ng-enter/ng-enter.directive.js b/zeppelin-web/src/components/ng-enter/ng-enter.directive.js
new file mode 100644
index 0000000..98bc067
--- /dev/null
+++ b/zeppelin-web/src/components/ng-enter/ng-enter.directive.js
@@ -0,0 +1,30 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+angular.module('zeppelinWebApp').directive('ngEnter', NgEnterDirective)
+
+function NgEnterDirective() {
+  return function (scope, element, attrs) {
+    element.bind('keydown keypress', function (event) {
+      if (event.which === 13) {
+        if (!event.shiftKey) {
+          scope.$apply(function () {
+            scope.$eval(attrs.ngEnter)
+          })
+        }
+        event.preventDefault()
+      }
+    })
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/ng-enter/ng-enter.directive.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/ng-enter/ng-enter.directive.test.js b/zeppelin-web/src/components/ng-enter/ng-enter.directive.test.js
new file mode 100644
index 0000000..49f97cc
--- /dev/null
+++ b/zeppelin-web/src/components/ng-enter/ng-enter.directive.test.js
@@ -0,0 +1,24 @@
+describe('Directive: ngEnter', function () {
+  // load the directive's module
+  beforeEach(angular.mock.module('zeppelinWebApp'))
+
+  let element
+  let scope
+
+  beforeEach(inject(function ($rootScope) {
+    scope = $rootScope.$new()
+  }))
+
+  it('should be define', inject(function ($compile) {
+    element = angular.element('<ng-enter></ng-enter>')
+    element = $compile(element)(scope)
+    expect(element.text()).toBeDefined()
+  }))
+
+  // Test the rest of function in ngEnter
+  /*  it('should make hidden element visible', inject(function ($compile) {
+      element = angular.element('<ng-enter></ng-enter>');
+      element = $compile(element)(scope);
+      expect(element.text()).toBe('this is the ngEnter directive');
+    })); */
+})

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/ng-escape/ng-escape.directive.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/ng-escape/ng-escape.directive.js b/zeppelin-web/src/components/ng-escape/ng-escape.directive.js
new file mode 100644
index 0000000..a3d35ea
--- /dev/null
+++ b/zeppelin-web/src/components/ng-escape/ng-escape.directive.js
@@ -0,0 +1,28 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+angular.module('zeppelinWebApp').directive('ngEscape', NgEscapeDirective)
+
+function NgEscapeDirective() {
+  return function (scope, element, attrs) {
+    element.bind('keydown keyup', function (event) {
+      if (event.which === 27) {
+        scope.$apply(function () {
+          scope.$eval(attrs.ngEscape)
+        })
+        event.preventDefault()
+      }
+    })
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/ngenter/ngenter.directive.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/ngenter/ngenter.directive.js b/zeppelin-web/src/components/ngenter/ngenter.directive.js
deleted file mode 100644
index 57ec01c..0000000
--- a/zeppelin-web/src/components/ngenter/ngenter.directive.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-angular.module('zeppelinWebApp').directive('ngEnter', ngEnter)
-
-function ngEnter () {
-  return function (scope, element, attrs) {
-    element.bind('keydown keypress', function (event) {
-      if (event.which === 13) {
-        if (!event.shiftKey) {
-          scope.$apply(function () {
-            scope.$eval(attrs.ngEnter)
-          })
-        }
-        event.preventDefault()
-      }
-    })
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/ngenter/ngenter.directive.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/ngenter/ngenter.directive.test.js b/zeppelin-web/src/components/ngenter/ngenter.directive.test.js
deleted file mode 100644
index 49f97cc..0000000
--- a/zeppelin-web/src/components/ngenter/ngenter.directive.test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-describe('Directive: ngEnter', function () {
-  // load the directive's module
-  beforeEach(angular.mock.module('zeppelinWebApp'))
-
-  let element
-  let scope
-
-  beforeEach(inject(function ($rootScope) {
-    scope = $rootScope.$new()
-  }))
-
-  it('should be define', inject(function ($compile) {
-    element = angular.element('<ng-enter></ng-enter>')
-    element = $compile(element)(scope)
-    expect(element.text()).toBeDefined()
-  }))
-
-  // Test the rest of function in ngEnter
-  /*  it('should make hidden element visible', inject(function ($compile) {
-      element = angular.element('<ng-enter></ng-enter>');
-      element = $compile(element)(scope);
-      expect(element.text()).toBe('this is the ngEnter directive');
-    })); */
-})

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/ngescape/ngescape.directive.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/ngescape/ngescape.directive.js b/zeppelin-web/src/components/ngescape/ngescape.directive.js
deleted file mode 100644
index b52a7a7..0000000
--- a/zeppelin-web/src/components/ngescape/ngescape.directive.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-angular.module('zeppelinWebApp').directive('ngEscape', ngEscape)
-
-function ngEscape () {
-  return function (scope, element, attrs) {
-    element.bind('keydown keyup', function (event) {
-      if (event.which === 27) {
-        scope.$apply(function () {
-          scope.$eval(attrs.ngEscape)
-        })
-        event.preventDefault()
-      }
-    })
-  }
-}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/note-action/note-action.service.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/note-action/note-action.service.js b/zeppelin-web/src/components/note-action/note-action.service.js
new file mode 100644
index 0000000..8e00c0f
--- /dev/null
+++ b/zeppelin-web/src/components/note-action/note-action.service.js
@@ -0,0 +1,183 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+angular.module('zeppelinWebApp').service('noteActionService', noteActionService)
+
+function noteActionService(websocketMsgSrv, $location, noteRenameService, noteListFactory) {
+  'ngInject'
+
+  this.moveNoteToTrash = function (noteId, redirectToHome) {
+    BootstrapDialog.confirm({
+      closable: true,
+      title: 'Move this note to trash?',
+      message: 'This note will be moved to <strong>trash</strong>.',
+      callback: function (result) {
+        if (result) {
+          websocketMsgSrv.moveNoteToTrash(noteId)
+          if (redirectToHome) {
+            $location.path('/')
+          }
+        }
+      }
+    })
+  }
+
+  this.moveFolderToTrash = function (folderId) {
+    BootstrapDialog.confirm({
+      closable: true,
+      title: 'Move this folder to trash?',
+      message: 'This folder will be moved to <strong>trash</strong>.',
+      callback: function (result) {
+        if (result) {
+          websocketMsgSrv.moveFolderToTrash(folderId)
+        }
+      }
+    })
+  }
+
+  this.removeNote = function (noteId, redirectToHome) {
+    BootstrapDialog.confirm({
+      type: BootstrapDialog.TYPE_WARNING,
+      closable: true,
+      title: 'WARNING! This note will be removed permanently',
+      message: 'This cannot be undone. Are you sure?',
+      callback: function (result) {
+        if (result) {
+          websocketMsgSrv.deleteNote(noteId)
+          if (redirectToHome) {
+            $location.path('/')
+          }
+        }
+      }
+    })
+  }
+
+  this.removeFolder = function (folderId) {
+    BootstrapDialog.confirm({
+      type: BootstrapDialog.TYPE_WARNING,
+      closable: true,
+      title: 'WARNING! This folder will be removed permanently',
+      message: 'This cannot be undone. Are you sure?',
+      callback: function (result) {
+        if (result) {
+          websocketMsgSrv.removeFolder(folderId)
+        }
+      }
+    })
+  }
+
+  this.restoreAll = function () {
+    BootstrapDialog.confirm({
+      closable: true,
+      title: 'Are you sure want to restore all notes in the trash?',
+      message: 'Folders and notes in the trash will be ' +
+      '<strong>merged</strong> into their original position.',
+      callback: function (result) {
+        if (result) {
+          websocketMsgSrv.restoreAll()
+        }
+      }
+    })
+  }
+
+  this.emptyTrash = function () {
+    BootstrapDialog.confirm({
+      type: BootstrapDialog.TYPE_WARNING,
+      closable: true,
+      title: 'WARNING! Notes under trash will be removed permanently',
+      message: 'This cannot be undone. Are you sure?',
+      callback: function (result) {
+        if (result) {
+          websocketMsgSrv.emptyTrash()
+        }
+      }
+    })
+  }
+
+  this.clearAllParagraphOutput = function (noteId) {
+    BootstrapDialog.confirm({
+      closable: true,
+      title: '',
+      message: 'Do you want to clear all output?',
+      callback: function (result) {
+        if (result) {
+          websocketMsgSrv.clearAllParagraphOutput(noteId)
+        }
+      }
+    })
+  }
+
+  this.renameNote = function (noteId, notePath) {
+    noteRenameService.openRenameModal({
+      title: 'Rename note',
+      oldName: notePath,
+      callback: function (newName) {
+        websocketMsgSrv.renameNote(noteId, newName)
+      }
+    })
+  }
+
+  this.renameFolder = function (folderId) {
+    noteRenameService.openRenameModal({
+      title: 'Rename folder',
+      oldName: folderId,
+      callback: function (newName) {
+        let newFolderId = normalizeFolderId(newName)
+        if (_.has(noteListFactory.flatFolderMap, newFolderId)) {
+          BootstrapDialog.confirm({
+            type: BootstrapDialog.TYPE_WARNING,
+            closable: true,
+            title: 'WARNING! The folder will be MERGED',
+            message: 'The folder will be merged into <strong>' + newFolderId + '</strong>. Are you sure?',
+            callback: function (result) {
+              if (result) {
+                websocketMsgSrv.renameFolder(folderId, newFolderId)
+              }
+            }
+          })
+        } else {
+          websocketMsgSrv.renameFolder(folderId, newFolderId)
+        }
+      }
+    })
+  }
+
+  function normalizeFolderId (folderId) {
+    folderId = folderId.trim()
+
+    while (folderId.indexOf('\\') > -1) {
+      folderId = folderId.replace('\\', '/')
+    }
+
+    while (folderId.indexOf('///') > -1) {
+      folderId = folderId.replace('///', '/')
+    }
+
+    folderId = folderId.replace('//', '/')
+
+    if (folderId === '/') {
+      return '/'
+    }
+
+    if (folderId[0] === '/') {
+      folderId = folderId.substring(1)
+    }
+
+    if (folderId.slice(-1) === '/') {
+      folderId = folderId.slice(0, -1)
+    }
+
+    return folderId
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/note-create/note-create.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/note-create/note-create.controller.js b/zeppelin-web/src/components/note-create/note-create.controller.js
new file mode 100644
index 0000000..c999c20
--- /dev/null
+++ b/zeppelin-web/src/components/note-create/note-create.controller.js
@@ -0,0 +1,106 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import './note-create.css'
+
+angular.module('zeppelinWebApp').controller('NoteCreateCtrl', NoteCreateCtrl)
+
+function NoteCreateCtrl ($scope, noteListFactory, $routeParams, websocketMsgSrv) {
+  'ngInject'
+
+  let vm = this
+  vm.clone = false
+  vm.notes = noteListFactory
+  vm.websocketMsgSrv = websocketMsgSrv
+  $scope.note = {}
+  $scope.interpreterSettings = {}
+  $scope.note.defaultInterpreter = null
+
+  vm.createNote = function () {
+    if (!vm.clone) {
+      let defaultInterpreterId = ''
+      if ($scope.note.defaultInterpreter !== null) {
+        defaultInterpreterId = $scope.note.defaultInterpreter.id
+      }
+      vm.websocketMsgSrv.createNotebook($scope.note.notename, defaultInterpreterId)
+      $scope.note.defaultInterpreter = $scope.interpreterSettings[0]
+    } else {
+      let noteId = $routeParams.noteId
+      vm.websocketMsgSrv.cloneNote(noteId, $scope.note.notename)
+    }
+  }
+
+  vm.handleNameEnter = function () {
+    angular.element('#noteCreateModal').modal('toggle')
+    vm.createNote()
+  }
+
+  vm.preVisible = function(clone, sourceNoteName, path) {
+    vm.clone = clone
+    vm.sourceNoteName = sourceNoteName
+    $scope.note.notename = vm.clone ? vm.cloneNoteName() : vm.newNoteName(path)
+    $scope.$apply()
+  }
+
+  vm.newNoteName = function(path) {
+    let newCount = 1
+    angular.forEach(vm.notes.flatList, function (noteName) {
+      noteName = noteName.name
+      if (noteName.match(/^Untitled Note [0-9]*$/)) {
+        let lastCount = noteName.substr(14) * 1
+        if (newCount <= lastCount) {
+          newCount = lastCount + 1
+        }
+      }
+    })
+    return (path ? path + '/' : '') + 'Untitled Note ' + newCount
+  }
+
+  vm.cloneNoteName = function () {
+    let copyCount = 1
+    let newCloneName = ''
+    let lastIndex = vm.sourceNoteName.lastIndexOf(' ')
+    let endsWithNumber = !!vm.sourceNoteName.match('^.+?\\s\\d$')
+    let noteNamePrefix = endsWithNumber ? vm.sourceNoteName.substr(0, lastIndex) : vm.sourceNoteName
+    let regexp = new RegExp('^' + noteNamePrefix + ' .+')
+
+    angular.forEach(vm.notes.flatList, function (noteName) {
+      noteName = noteName.name
+      if (noteName.match(regexp)) {
+        let lastCopyCount = noteName.substr(lastIndex).trim()
+        newCloneName = noteNamePrefix
+        lastCopyCount = parseInt(lastCopyCount)
+        if (copyCount <= lastCopyCount) {
+          copyCount = lastCopyCount + 1
+        }
+      }
+    })
+
+    if (!newCloneName) {
+      newCloneName = vm.sourceNoteName
+    }
+    return newCloneName + ' ' + copyCount
+  }
+
+  vm.getInterpreterSettings = function () {
+    vm.websocketMsgSrv.getInterpreterSettings()
+  }
+
+  $scope.$on('interpreterSettings', function (event, data) {
+    $scope.interpreterSettings = data.interpreterSettings
+
+    // initialize default interpreter with Spark interpreter
+    $scope.note.defaultInterpreter = data.interpreterSettings[0]
+  })
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/note-create/note-create.controller.test.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/note-create/note-create.controller.test.js b/zeppelin-web/src/components/note-create/note-create.controller.test.js
new file mode 100644
index 0000000..d409a14
--- /dev/null
+++ b/zeppelin-web/src/components/note-create/note-create.controller.test.js
@@ -0,0 +1,39 @@
+describe('Controller: NoteCreateCtrl', function () {
+  beforeEach(angular.mock.module('zeppelinWebApp'))
+
+  let scope
+  let ctrl
+  let noteList
+
+  beforeEach(inject(function ($injector, $rootScope, $controller) {
+    noteList = $injector.get('noteListFactory')
+    scope = $rootScope.$new()
+    ctrl = $controller('NoteCreateCtrl', {
+      $scope: scope,
+      noteListFactory: noteList
+    })
+  }))
+
+  it('should create a new name from current name when cloneNoteName is called', function () {
+    let notesList = [
+      {name: 'dsds 1', id: '1'},
+      {name: 'dsds 2', id: '2'},
+      {name: 'test name', id: '3'},
+      {name: 'aa bb cc', id: '4'},
+      {name: 'Untitled Note 6', id: '4'}
+    ]
+
+    noteList.setNotes(notesList)
+
+    ctrl.sourceNoteName = 'test name'
+    expect(ctrl.cloneNoteName()).toEqual('test name 1')
+    ctrl.sourceNoteName = 'aa bb cc'
+    expect(ctrl.cloneNoteName()).toEqual('aa bb cc 1')
+    ctrl.sourceNoteName = 'Untitled Note 6'
+    expect(ctrl.cloneNoteName()).toEqual('Untitled Note 7')
+    ctrl.sourceNoteName = 'My_note'
+    expect(ctrl.cloneNoteName()).toEqual('My_note 1')
+    ctrl.sourceNoteName = 'dsds 2'
+    expect(ctrl.cloneNoteName()).toEqual('dsds 3')
+  })
+})

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/note-create/note-create.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/note-create/note-create.css b/zeppelin-web/src/components/note-create/note-create.css
new file mode 100644
index 0000000..22249ad
--- /dev/null
+++ b/zeppelin-web/src/components/note-create/note-create.css
@@ -0,0 +1,49 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.modal-header-note-name {
+  background-color: #3071a9;
+  border: 2px solid #3071a9;
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+}
+
+.modal-header-note-name > .modal-title {
+  font-weight: 300;
+  font-size: 20px;
+  color: white;
+}
+
+.modal-header-note-name > .close {
+  color: #cfcfcf;
+  opacity: 1;
+}
+
+.modal-body-note-name label {
+  font-size: 17px;
+  font-weight: 400;
+}
+
+.note-name-create-input {
+  margin-top: 5px;
+}
+
+.note-name-desc-panel {
+  margin-top: 20px;
+  margin-bottom: 4px;
+}
+
+.default-interpreter-select {
+  margin-top: 12px;
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/note-create/note-create.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/note-create/note-create.html b/zeppelin-web/src/components/note-create/note-create.html
new file mode 100644
index 0000000..dbfb9e2
--- /dev/null
+++ b/zeppelin-web/src/components/note-create/note-create.html
@@ -0,0 +1,66 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<div id="noteCreateModal" class="modal fade" role="dialog"
+     modalvisible previsiblecallback="noteCreateCtrl.preVisible"
+     targetinput="noteName" tabindex="-1">
+  <div class="modal-dialog">
+
+    <!-- modal content-->
+    <div class="modal-content" id="NoteCreateCtrl">
+      <!-- modal header -->
+      <div class="modal-header modal-header-note-name">
+        <button type="button" class="close" data-dismiss="modal">&times;</button>
+        <h4 class="modal-title" ng-show="!noteCreateCtrl.clone">Create New Note</h4>
+        <h4 class="modal-title" ng-show="noteCreateCtrl.clone">Clone Note</h4>
+      </div>
+
+      <!-- modal body-->
+      <div class="modal-body modal-body-note-name">
+        <div class="form-group">
+          <!-- note name -->
+          <div>
+            <label for="noteName">Note Name</label>
+            <input placeholder="Insert Note Name" type="text"
+                   class="form-control note-name-create-input"
+                   id="noteName" ng-model="note.notename"
+                   ng-enter="noteCreateCtrl.handleNameEnter()" />
+          </div>
+          <!-- default interpreter -->
+          <div class="btn-group default-interpreter-select" ng-show="!noteCreateCtrl.clone">
+            <label for="defaultInterpreter">Default Interpreter</label>
+            <select id="defaultInterpreter"
+                    name="defaultInterpreter"
+                    class="form-control"
+                    ng-model="note.defaultInterpreter"
+                    ng-options="option.name for option in interpreterSettings">
+            </select>
+          </div>
+        </div> <!-- end: form-group -->
+        <div class="panel panel-default note-name-desc-panel">
+          <div class="panel-heading">
+            Use '/' to create folders. Example: /NoteDirA/Note1
+          </div>
+        </div>
+      </div>
+      <div class="modal-footer">
+        <button type="button" id="createNoteButton"
+                class="btn btn-primary"
+                data-dismiss="modal" ng-click="noteCreateCtrl.createNote()">
+          <span ng-show="!noteCreateCtrl.clone">Create</span>
+          <span ng-show="noteCreateCtrl.clone">Clone</span>
+        </button>
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/note-create/visible.directive.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/note-create/visible.directive.js b/zeppelin-web/src/components/note-create/visible.directive.js
new file mode 100644
index 0000000..48c170f
--- /dev/null
+++ b/zeppelin-web/src/components/note-create/visible.directive.js
@@ -0,0 +1,45 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+angular.module('zeppelinWebApp').directive('modalvisible', modalvisible)
+
+function modalvisible () {
+  return {
+    restrict: 'A',
+    scope: {
+      preVisibleCallback: '&previsiblecallback',
+      postVisibleCallback: '&postvisiblecallback',
+      targetinput: '@targetinput'
+    },
+    link: function (scope, element, attrs) {
+      // Add some listeners
+      let previsibleMethod = scope.preVisibleCallback
+      let postVisibleMethod = scope.postVisibleCallback
+      element.on('show.bs.modal', function (e) {
+        let relatedTarget = angular.element(e.relatedTarget)
+        let clone = relatedTarget.data('clone')
+        let sourceNoteName = relatedTarget.data('source-note-name')
+        let path = relatedTarget.data('path')
+        let cloneNote = clone ? true : false
+        previsibleMethod()(cloneNote, sourceNoteName, path)
+      })
+      element.on('shown.bs.modal', function (e) {
+        if (scope.targetinput) {
+          angular.element(e.target).find('input#' + scope.targetinput).select()
+        }
+        postVisibleMethod()
+      })
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/note-import/note-import.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/note-import/note-import.controller.js b/zeppelin-web/src/components/note-import/note-import.controller.js
new file mode 100644
index 0000000..8cec890
--- /dev/null
+++ b/zeppelin-web/src/components/note-import/note-import.controller.js
@@ -0,0 +1,138 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import './note-import.css'
+
+angular.module('zeppelinWebApp').controller('NoteImportCtrl', NoteImportCtrl)
+
+function NoteImportCtrl ($scope, $timeout, websocketMsgSrv) {
+  'ngInject'
+
+  let vm = this
+  $scope.note = {}
+  $scope.note.step1 = true
+  $scope.note.step2 = false
+  $scope.maxLimit = ''
+  let limit = 0
+
+  websocketMsgSrv.listConfigurations()
+  $scope.$on('configurationsInfo', function (scope, event) {
+    limit = event.configurations['zeppelin.websocket.max.text.message.size']
+    $scope.maxLimit = Math.round(limit / 1048576)
+  })
+
+  vm.resetFlags = function () {
+    $scope.note = {}
+    $scope.note.step1 = true
+    $scope.note.step2 = false
+    angular.element('#noteImportFile').val('')
+  }
+
+  $scope.uploadFile = function () {
+    angular.element('#noteImportFile').click()
+  }
+
+  $scope.importFile = function (element) {
+    $scope.note.errorText = ''
+    $scope.note.importFile = element.files[0]
+    let file = $scope.note.importFile
+    let reader = new FileReader()
+
+    if (file.size > limit) {
+      $scope.note.errorText = 'File size limit Exceeded!'
+      $scope.$apply()
+      return
+    }
+
+    reader.onloadend = function () {
+      vm.processImportJson(reader.result)
+    }
+
+    if (file) {
+      reader.readAsText(file)
+    }
+  }
+
+  $scope.uploadURL = function () {
+    $scope.note.errorText = ''
+    $scope.note.step1 = false
+    $timeout(function () {
+      $scope.note.step2 = true
+    }, 400)
+  }
+
+  vm.importBack = function () {
+    $scope.note.errorText = ''
+    $timeout(function () {
+      $scope.note.step1 = true
+    }, 400)
+    $scope.note.step2 = false
+  }
+
+  vm.importNote = function () {
+    $scope.note.errorText = ''
+    if ($scope.note.importUrl) {
+      jQuery.ajax({
+        url: $scope.note.importUrl,
+        type: 'GET',
+        dataType: 'json',
+        jsonp: false,
+        xhrFields: {
+          withCredentials: false
+        },
+        error: function (xhr, ajaxOptions, thrownError) {
+          $scope.note.errorText = 'Unable to Fetch URL'
+          $scope.$apply()
+        }}).done(function (data) {
+          vm.processImportJson(data)
+        })
+    } else {
+      $scope.note.errorText = 'Enter URL'
+      $scope.$apply()
+    }
+  }
+
+  vm.processImportJson = function (result) {
+    if (typeof result !== 'object') {
+      try {
+        result = JSON.parse(result)
+      } catch (e) {
+        $scope.note.errorText = 'JSON parse exception'
+        $scope.$apply()
+        return
+      }
+    }
+    if (result.paragraphs && result.paragraphs.length > 0) {
+      if (!$scope.note.noteImportName) {
+        $scope.note.noteImportName = result.name
+      } else {
+        result.name = $scope.note.noteImportName
+      }
+      websocketMsgSrv.importNote(result)
+      // angular.element('#noteImportModal').modal('hide');
+    } else {
+      $scope.note.errorText = 'Invalid JSON'
+    }
+    $scope.$apply()
+  }
+
+  /*
+   ** $scope.$on functions below
+   */
+
+  $scope.$on('setNoteMenu', function (event, notes) {
+    vm.resetFlags()
+    angular.element('#noteImportModal').modal('hide')
+  })
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/note-import/note-import.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/note-import/note-import.css b/zeppelin-web/src/components/note-import/note-import.css
new file mode 100644
index 0000000..81e276a
--- /dev/null
+++ b/zeppelin-web/src/components/note-import/note-import.css
@@ -0,0 +1,91 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.modal-header-import {
+  background-color: #3071a9;
+  border: 2px solid #3071a9;
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+}
+
+.modal-header-import .close {
+  color: #cfcfcf;
+  opacity: 1;
+}
+
+.modal-header-import .modal-title {
+  color: white;
+  font-size: 20px;
+  font-weight: 300;
+}
+
+.modal-body-import .note-name-input {
+  margin-left: 7px;
+  margin-right: 7px;
+}
+
+.modal-body-import label {
+  font-size: 15px;
+  font-weight: 400;
+  margin-bottom: 10px;
+  margin-top: 15px;
+}
+
+.modal-body-import {
+  min-height: 420px;
+  overflow: hidden;
+}
+
+.modal-body-import .import-btn-image-group {
+  margin-top: 4px;
+}
+
+.modal-body-import .import-btn-image {
+  display: inline-block;
+  margin-left: 8px;
+}
+
+.modal-body-import .import-btn-image a {
+  background: #fff;
+  border: 1px solid #e6e6e6;
+  /*border-radius: 20px;*/
+  border-radius: 20%;
+  color: #7c828e;
+  cursor: pointer;
+  display: block;
+  float: left;
+  font-size: 98px;
+  text-align: center;
+  text-decoration: none;
+  height: 240px;
+  padding-top: 60px;
+  margin: 0 10px 0px 10px;
+  width: 250px;
+}
+
+.modal-body-import .import-btn-image a:hover {
+  background: #eee;
+}
+
+.modal-body-import .modal-body-import-desc {
+  font-size: 15px;
+  font-weight: 400;
+  margin-top: 30px;
+  color: black;
+  font-family: 'Roboto', sans-serif;
+}
+
+.modal-footer-import {
+  min-height: 65px;
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/6bd6c708/zeppelin-web/src/components/note-import/note-import.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/note-import/note-import.html b/zeppelin-web/src/components/note-import/note-import.html
new file mode 100644
index 0000000..848a93b
--- /dev/null
+++ b/zeppelin-web/src/components/note-import/note-import.html
@@ -0,0 +1,80 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<div id="noteImportModal" class="modal fade" role="dialog" tabindex="-1"
+     data-backdrop="static" data-keyboard="false">
+
+  <div class="modal-dialog">
+    <div class="modal-content" id="NoteImportCtrl" ng-init="NoteImportInit">
+
+      <!-- modal-header -->
+      <div class="modal-header modal-header-import">
+        <button type="button" class="close" data-dismiss="modal"
+                ng-click="noteImportCtrl.resetFlags()">&times;</button>
+        <h4 class="modal-title">Import New Note</h4>
+      </div>
+
+      <!-- modal-body -->
+      <div class="modal-body modal-body-import">
+        <div class="form-group">
+          <label for="noteImportName">Import As</label>
+          <input class="form-control note-name-input" id="noteImportName"
+                 placeholder="Insert Note Name" type="text"
+                 ng-model="note.noteImportName" />
+        </div>
+
+        <div class="form-group" ng-show="note.errorText">
+          <div class="alert alert-danger">{{note.errorText}}</div>
+        </div>
+
+        <label>JSON file size cannot exceed {{maxLimit}} MB</label>
+
+        <div class="form-group slide-left import-btn-image-group" ng-show="note.step1">
+          <div class="import-btn-image">
+            <a class="fa fa-cloud-upload import-file-upload" ng-click="uploadFile()">
+              <p class="modal-body-import-desc">Select JSON File </p>
+            </a>
+            <div style="display: none">
+              <input class="form-control note-name-input" id="noteImportFile"
+                     placeholder="Note name" type="file"
+                     ng-model="note.importFile" onchange="angular.element(this).scope().importFile(this)" />
+            </div>
+          </div>
+          <div class="import-btn-image">
+            <a href="javascript:void(0);" ng-click="uploadURL()" class="fa fa-link">
+              <p class="modal-body-import-desc">Add from URL</p>
+            </a>
+          </div>
+        </div>
+
+        <div class="form-group slide-right" ng-show="note.step2">
+
+          <label for="noteImportUrl">URL</label>
+          <input placeholder="Note URL" type="text" class="form-control" id="noteImportUrl"
+                 ng-model="note.importUrl" />
+        </div>
+
+      </div>
+      <div class="modal-footer modal-footer-import" ng-show="note.step2">
+        <button type="button" id="importBackButton"
+                class="btn btn-default"
+                ng-click="noteImportCtrl.importBack()">Back
+        </button>
+        <button type="button" id="importNoteButton"
+                class="btn btn-default"
+                ng-click="noteImportCtrl.importNote()">Import Note
+        </button>
+      </div>
+    </div>
+  </div>
+</div>