From f946b0beab0ff15e99ff99c34d38df271fb46e1e Mon Sep 17 00:00:00 2001 From: Jamie Date: Mon, 18 Apr 2016 16:27:00 +0800 Subject: [PATCH 01/58] Add style to allow word to be break and wrap --- src/styles/base.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/styles/base.css b/src/styles/base.css index 8caa00f..26b1d20 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -41,3 +41,7 @@ .text-center { text-align: center; } + +.break-word { + word-break: break-word; +} From 6230d9c143c4b6558d9ab0a2cbd2df0b1c4a57f2 Mon Sep 17 00:00:00 2001 From: Jamie Date: Mon, 18 Apr 2016 16:32:41 +0800 Subject: [PATCH 02/58] Update the style to place in the middle of the table --- src/styles/table.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/table.css b/src/styles/table.css index 7f43265..5e84570 100644 --- a/src/styles/table.css +++ b/src/styles/table.css @@ -27,7 +27,7 @@ th { .table > tfoot > tr > td { padding: 8px; line-height: 1.42857143; - vertical-align: top; + vertical-align: middle; border-top: 1px solid #dddddd; } From 3b1c6e888a5978ab9e235a495957234c01c0f83e Mon Sep 17 00:00:00 2001 From: jigsawye Date: Thu, 21 Apr 2016 15:37:15 +0800 Subject: [PATCH 03/58] Remove angular-breadcrumb & implement breadcrumb component Remove `angular-breadcrumb` because it doesn't support nested path. And I re-implement a new breadcrumb component. * Remove angular-breadcrumb from dependencies * Add layout/breadcrumb component * Add a method call to $bucket for update the bucket length --- package.json | 1 - src/components/bucket/bucket.js | 3 --- src/components/bucket/bucket.service.js | 5 +++-- .../breadcrumb/breadcrumb.controller.js | 13 +++++++++++++ .../layout/breadcrumb/breadcrumb.html | 8 ++++++++ .../layout/breadcrumb/breadcrumb.service.js | 19 +++++++++++++++++++ src/components/layout/layout.html | 2 +- src/components/layout/layout.js | 9 +++++++++ 8 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 src/components/layout/breadcrumb/breadcrumb.controller.js create mode 100644 src/components/layout/breadcrumb/breadcrumb.html create mode 100644 src/components/layout/breadcrumb/breadcrumb.service.js diff --git a/package.json b/package.json index 68f8bf6..9af6ecf 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ "angular": "^1.5.0", "angular-animate": "^1.5.0", "angular-aria": "^1.5.0", - "angular-breadcrumb": "^0.4.1", "angular-material": "^1.0.5", "angular-messages": "^1.5.0", "angular-translate": "^2.9.2", diff --git a/src/components/bucket/bucket.js b/src/components/bucket/bucket.js index 050007a..7037565 100644 --- a/src/components/bucket/bucket.js +++ b/src/components/bucket/bucket.js @@ -25,9 +25,6 @@ const route = $stateProvider => { controllerAs: 'nav', }, }, - ncyBreadcrumb: { - label: 'All Buckets ( {{ bucket.data.length }} )', - }, }); }; diff --git a/src/components/bucket/bucket.service.js b/src/components/bucket/bucket.service.js index 6f053f1..58c77eb 100644 --- a/src/components/bucket/bucket.service.js +++ b/src/components/bucket/bucket.service.js @@ -5,9 +5,9 @@ import BucketCreateTemplate from './create/create.html'; export default class BucketService { /** @ngInject */ - constructor($fetch, $toast, $mdDialog) { + constructor($fetch, $toast, $mdDialog, $breadcrumb) { Object.assign(this, { - $fetch, $toast, $mdDialog, + $fetch, $toast, $mdDialog, $breadcrumb, }); this.initState(); @@ -105,6 +105,7 @@ export default class BucketService { }) .finally(() => { this.state.lists.requesting = false; + this.$breadcrumb.updateBucketPath(this.state.lists.data.length); }); } diff --git a/src/components/layout/breadcrumb/breadcrumb.controller.js b/src/components/layout/breadcrumb/breadcrumb.controller.js new file mode 100644 index 0000000..9eb320a --- /dev/null +++ b/src/components/layout/breadcrumb/breadcrumb.controller.js @@ -0,0 +1,13 @@ +export default class BreadcrumbController { + /** @ngInject */ + constructor($scope, $bucket, $breadcrumb) { + Object.assign(this, { + $scope, $bucket, $breadcrumb, + }); + + this.$scope.$watch( + () => $breadcrumb.paths, + newVal => (this.paths = newVal) + , true); + } +} diff --git a/src/components/layout/breadcrumb/breadcrumb.html b/src/components/layout/breadcrumb/breadcrumb.html new file mode 100644 index 0000000..8f44a1f --- /dev/null +++ b/src/components/layout/breadcrumb/breadcrumb.html @@ -0,0 +1,8 @@ + diff --git a/src/components/layout/breadcrumb/breadcrumb.service.js b/src/components/layout/breadcrumb/breadcrumb.service.js new file mode 100644 index 0000000..a4b517d --- /dev/null +++ b/src/components/layout/breadcrumb/breadcrumb.service.js @@ -0,0 +1,19 @@ +export default class BreadcrumbService { + /** @ngInject */ + constructor() { + this.initPaths(); + } + + initPaths() { + this.paths = [{ + link: '/bucket', + text: 'All Bucket', + isBucket: true, + len: 0, + }]; + } + + updateBucketPath(len) { + this.paths[0].len = len; + } +} diff --git a/src/components/layout/layout.html b/src/components/layout/layout.html index 363d63c..5000fb0 100644 --- a/src/components/layout/layout.html +++ b/src/components/layout/layout.html @@ -3,7 +3,7 @@
- +
diff --git a/src/components/layout/layout.js b/src/components/layout/layout.js index 907f2b5..289313a 100644 --- a/src/components/layout/layout.js +++ b/src/components/layout/layout.js @@ -4,6 +4,9 @@ import router from 'angular-ui-router'; import LayoutTemplate from './layout.html'; import TopNavbarController from './top-navbar/top-navbar.controller'; import TopNavbarTemplate from './top-navbar/top-navbar.html'; +import BreadcrumbController from './breadcrumb/breadcrumb.controller'; +import BreadcrumbTemplate from './breadcrumb/breadcrumb.html'; +import BreadcrumbService from './breadcrumb/breadcrumb.service'; import './layout.css'; @@ -21,6 +24,11 @@ const route = $stateProvider => { controller: TopNavbarController, controllerAs: 'nav', }, + 'breadcrumb@root': { + template: BreadcrumbTemplate, + controller: BreadcrumbController, + controllerAs: 'bc', + }, }, }); }; @@ -28,6 +36,7 @@ const route = $stateProvider => { const Layout = module('layout', [ router, ]) +.service('$breadcrumb', BreadcrumbService) .config(route); export default Layout.name; From 2f1e1dcbd37b583fdfcf66f53ac1f96a8b5dc565 Mon Sep 17 00:00:00 2001 From: Jamie Date: Thu, 21 Apr 2016 15:46:12 +0800 Subject: [PATCH 04/58] Add base style for display property --- src/styles/base.css | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/styles/base.css b/src/styles/base.css index 26b1d20..abdf654 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -45,3 +45,17 @@ .break-word { word-break: break-word; } + +/* display */ + +.inline{ + display: inline; +} + +.block{ + display: block; +} + +.inline-block{ + display: inline-block; +} From d0227f25360434076fee31576c72ad6f6c67a407 Mon Sep 17 00:00:00 2001 From: Jamie Date: Thu, 21 Apr 2016 15:50:21 +0800 Subject: [PATCH 05/58] Fix flexbox type layout issues in IE10 --- src/styles/s3.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/styles/s3.css b/src/styles/s3.css index 1351233..2a033f3 100644 --- a/src/styles/s3.css +++ b/src/styles/s3.css @@ -127,3 +127,8 @@ md-input-container md-progress-circular { .load-fail-state { margin-top: 10%; } + +/* fix flexbox type layout issues in IE10 */ +span.flex { + display: block; +} From ce606a8cdea4da778948a01eb9fb04a16e1e3eef Mon Sep 17 00:00:00 2001 From: Jamie Date: Thu, 21 Apr 2016 16:18:50 +0800 Subject: [PATCH 06/58] Add list item style for file list --- src/styles/s3.css | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/styles/s3.css b/src/styles/s3.css index 2a033f3..d5e7de4 100644 --- a/src/styles/s3.css +++ b/src/styles/s3.css @@ -128,6 +128,31 @@ md-input-container md-progress-circular { margin-top: 10%; } +/* list item --------------------------------------------- */ +md-list-item.checked { + background: #E8EAF6; +} + +md-list-item > .md-list-item-inner > p { + padding: 0 8px; +} + +md-list-item > p.flex-none, +md-list-item > .md-list-item-inner > p.flex-none, +md-list-item .md-list-item-inner > p.flex-none, +md-list-item .md-list-item-inner > .md-list-item-inner > p.flex-none { + flex: 0 0 auto; + -ms-flex: 0 0 auto; +} + +md-list-item > p.flex-grow, +md-list-item > .md-list-item-inner > p.flex-grow, +md-list-item .md-list-item-inner > p.flex-grow, +md-list-item .md-list-item-inner > .md-list-item-inner > p.flex-grow { + flex: 1 1 100%; + -ms-flex: 1 1 100%; +} + /* fix flexbox type layout issues in IE10 */ span.flex { display: block; From ef3ccc90e825c3ab0ce2ffbece5b1a29502d4291 Mon Sep 17 00:00:00 2001 From: Jamie Date: Thu, 21 Apr 2016 16:42:30 +0800 Subject: [PATCH 07/58] Design file list * Add file.css * Add file.html --- src/components/file/file.css | 24 +++++++++ src/components/file/file.html | 98 +++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 src/components/file/file.css create mode 100644 src/components/file/file.html diff --git a/src/components/file/file.css b/src/components/file/file.css new file mode 100644 index 0000000..551d8f5 --- /dev/null +++ b/src/components/file/file.css @@ -0,0 +1,24 @@ + +/** + * @author Jamie jamie.h@inwinstack.com + */ + +.checkbox-icon-width { + width: 80px; +} + +.storage-class-width { + width: 140px; +} + +.size-width { + width: 84px; +} + +.time-width { + width: 270px; +} + +.time-title-width { + width: 286px; +} \ No newline at end of file diff --git a/src/components/file/file.html b/src/components/file/file.html new file mode 100644 index 0000000..f6dd562 --- /dev/null +++ b/src/components/file/file.html @@ -0,0 +1,98 @@ + +
+ + + + + + + + + + +
NameStorage ClassSizeLast Modified
+ + + + insert_drive_file +

+ +

+

+ +

+

+ +

+

+ +

+
+
+
+ +
+ +
Loading...
+
+ +
+
This bucket is empty
+
You can do the following actions
+ +
+ + add + Upload File + + + or + + + Create Folder + +
+
+ +
+
Oops, your connection seems off...
+
Don't worry. You can refresh to try again.
+ + + refresh + +
+
\ No newline at end of file From e7ad6708d5e0eb8fe3b6d58272f26ef093bf492d Mon Sep 17 00:00:00 2001 From: Jamie Date: Thu, 21 Apr 2016 16:47:10 +0800 Subject: [PATCH 08/58] Change the accent theme grey to indigo --- src/config/material.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/material.config.js b/src/config/material.config.js index 8916f5e..81663d3 100644 --- a/src/config/material.config.js +++ b/src/config/material.config.js @@ -4,5 +4,5 @@ export default ($mdThemingProvider) => { .theme('default') .primaryPalette('blue') .warnPalette('orange') - .accentPalette('grey'); + .accentPalette('indigo'); }; From b17959dbbfaced74cf3eb72145c779418f385b74 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Thu, 21 Apr 2016 17:10:48 +0800 Subject: [PATCH 09/58] Add File component --- src/components/file/file.controller.js | 7 +++++++ src/components/file/file.html | 1 + src/components/file/file.js | 25 +++++++++++++++++++++++++ src/components/file/file.service.js | 3 +++ src/components/index.js | 2 ++ 5 files changed, 38 insertions(+) create mode 100644 src/components/file/file.controller.js create mode 100644 src/components/file/file.html create mode 100644 src/components/file/file.js create mode 100644 src/components/file/file.service.js diff --git a/src/components/file/file.controller.js b/src/components/file/file.controller.js new file mode 100644 index 0000000..8ad9b6a --- /dev/null +++ b/src/components/file/file.controller.js @@ -0,0 +1,7 @@ +export default class FileController { + /** @ngInject */ + constructor($stateParams) { + this.path = $stateParams.path; + console.log(this.path.split('/')); // ['bucketName', 'folderA', 'folderB']; + } +} diff --git a/src/components/file/file.html b/src/components/file/file.html new file mode 100644 index 0000000..ce13f14 --- /dev/null +++ b/src/components/file/file.html @@ -0,0 +1 @@ +

File List

diff --git a/src/components/file/file.js b/src/components/file/file.js new file mode 100644 index 0000000..35def55 --- /dev/null +++ b/src/components/file/file.js @@ -0,0 +1,25 @@ +import { module } from 'angular'; +import router from 'angular-ui-router'; + +import FileController from './file.controller'; +import FileService from './file.service'; +import FileTemplate from './file.html'; + +/** @ngInject */ +const route = $stateProvider => { + $stateProvider.state('file', { + url: '/bucket/*path', + parent: 'root', + controller: FileController, + controllerAs: 'file', + template: FileTemplate, + }); +}; + +const File = module('file', [ + router, +]) +.service('$file', FileService) +.config(route); + +export default File.name; diff --git a/src/components/file/file.service.js b/src/components/file/file.service.js new file mode 100644 index 0000000..2a93618 --- /dev/null +++ b/src/components/file/file.service.js @@ -0,0 +1,3 @@ +export default class FileService { + +} diff --git a/src/components/index.js b/src/components/index.js index 8c1c994..d209813 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -3,12 +3,14 @@ import Layout from './layout/layout'; import NotFound from './not-found/not-found'; import Auth from './auth/auth'; import Bucket from './bucket/bucket'; +import File from './file/file'; const Components = module('app.components', [ Layout, NotFound, Auth, Bucket, + File, ]); export default Components.name; From 0a18a116ce09d46ac394b74a5e93785e86bd94b1 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Thu, 21 Apr 2016 17:25:07 +0800 Subject: [PATCH 10/58] Remove angular-breadcrumb from source code --- src/config/breadcrumb.config.js | 4 ---- src/config/breadcrumb.html | 5 ----- src/config/index.js | 2 -- 3 files changed, 11 deletions(-) delete mode 100644 src/config/breadcrumb.config.js delete mode 100644 src/config/breadcrumb.html diff --git a/src/config/breadcrumb.config.js b/src/config/breadcrumb.config.js deleted file mode 100644 index c4c08e7..0000000 --- a/src/config/breadcrumb.config.js +++ /dev/null @@ -1,4 +0,0 @@ -import template from './breadcrumb.html'; - -/** @ngInject */ -export default $breadcrumbProvider => $breadcrumbProvider.setOptions({ template }); diff --git a/src/config/breadcrumb.html b/src/config/breadcrumb.html deleted file mode 100644 index fc71562..0000000 --- a/src/config/breadcrumb.html +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/src/config/index.js b/src/config/index.js index 87b1861..3e4cd5f 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -5,7 +5,6 @@ import satellizer from './satellizer.config'; import material from './material.config'; import authenticateGuard from './AuthenticateGuard'; import http from './http.config'; -import breadcrumb from './breadcrumb.config'; const Config = module('app.config', []) .config(router) @@ -13,7 +12,6 @@ const Config = module('app.config', []) .config(satellizer) .config(material) .config(http) - .config(breadcrumb) .constant('Config', { API_URL: `${process.env.SERVER_HOST}/api`, }) From 9ea4a82a170339c837275799088c659423ffd7e4 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Fri, 22 Apr 2016 17:27:23 +0800 Subject: [PATCH 11/58] Add click event to bucket component When user clicked the bucket on bucket list, we will change the state whcih is the user selected. * Add `selectBucket` method to BucketController * Update the view of bucket component --- src/components/bucket/bucket.controller.js | 8 ++++++-- src/components/bucket/bucket.html | 5 ++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/bucket/bucket.controller.js b/src/components/bucket/bucket.controller.js index 766be3c..c7dafe5 100644 --- a/src/components/bucket/bucket.controller.js +++ b/src/components/bucket/bucket.controller.js @@ -1,8 +1,8 @@ export default class BucketController { /** @ngInject */ - constructor($scope, $bucket) { + constructor($scope, $bucket, $state) { Object.assign(this, { - $scope, $bucket, + $scope, $bucket, $state, }); this.$scope.$watch( @@ -16,4 +16,8 @@ export default class BucketController { createBucket($event) { this.$bucket.createDialog($event); } + + selectBucket(bucket) { + this.$state.go('file', { path: bucket }); + } } diff --git a/src/components/bucket/bucket.html b/src/components/bucket/bucket.html index fd50d39..0044eeb 100644 --- a/src/components/bucket/bucket.html +++ b/src/components/bucket/bucket.html @@ -12,14 +12,13 @@ - + info_outline - - + From dfb26b311fe9fee7c9259869c80d7e9a71ab8cc5 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Fri, 22 Apr 2016 17:29:33 +0800 Subject: [PATCH 12/58] Add sample view & service to file component When the user enter into `file` state, the FileController will set the path to $file service and get file list. For testing the UI flow, I add a fake API call to $file service. * Add `getFiles` method to $file service for fetch file list * Add `setPaths` method to $file service for set the API prefix * Add basic view for view the state of FileController --- src/components/file/file.controller.js | 15 ++++++-- src/components/file/file.html | 3 ++ src/components/file/file.service.js | 50 ++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/components/file/file.controller.js b/src/components/file/file.controller.js index 8ad9b6a..c687fe1 100644 --- a/src/components/file/file.controller.js +++ b/src/components/file/file.controller.js @@ -1,7 +1,16 @@ export default class FileController { /** @ngInject */ - constructor($stateParams) { - this.path = $stateParams.path; - console.log(this.path.split('/')); // ['bucketName', 'folderA', 'folderB']; + constructor($scope, $stateParams, $file) { + Object.assign(this, { + $scope, $file, + }); + + this.$scope.$watch( + () => $file.state.lists, + newVal => Object.assign(this, newVal) + , true); + + this.$file.setPaths($stateParams.path); + this.$file.getFiles(); } } diff --git a/src/components/file/file.html b/src/components/file/file.html index ce13f14..b8a612c 100644 --- a/src/components/file/file.html +++ b/src/components/file/file.html @@ -1 +1,4 @@

File List

+

Requesting: {{ file.requesting }}

+

Error: {{ file.error }}

+

{{ f }}

diff --git a/src/components/file/file.service.js b/src/components/file/file.service.js index 2a93618..329d568 100644 --- a/src/components/file/file.service.js +++ b/src/components/file/file.service.js @@ -1,3 +1,53 @@ export default class FileService { + /** @ngInject */ + constructor($q, $fetch, $bucket) { + Object.assign(this, { + $q, $fetch, $bucket, + }); + this.initState(); + } + + initState() { + this.state = { + paths: { + bucket: '', + folders: '', + }, + lists: { + data: [], + requesting: false, + error: false, + }, + create: { + checking: false, + checked: false, + duplicated: false, + }, + }; + } + + setPaths(path) { + const [bucket, ...folders] = path.split('/'); + this.paths = { bucket, folders }; + } + + getFiles() { + this.state.lists.requesting = true; + this.state.lists.data = []; + + const fakeList = ['folder1', 'folder2', 'folder3', 'folder4']; + + this.$q(resolve => setTimeout(() => resolve(fakeList), 2000)) + .then(list => { + this.state.lists.error = false; + this.state.lists.data = list; + }) + .catch(() => { + this.state.lists.error = true; + }) + .finally(() => { + this.state.lists.requesting = false; + }); + } } From 3146d6eb4e80e3b268f9b610cf97bd2b14b04155 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Mon, 25 Apr 2016 13:30:54 +0800 Subject: [PATCH 13/58] Rename utils to services --- src/index.js | 4 ++-- src/{utils => services}/fetch/fetch.js | 0 src/{utils => services}/fetch/fetch.service.js | 0 src/{utils => services}/index.js | 4 ++-- src/{utils => services}/toast/toast.js | 0 src/{utils => services}/toast/toast.service.js | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename src/{utils => services}/fetch/fetch.js (100%) rename src/{utils => services}/fetch/fetch.service.js (100%) rename src/{utils => services}/index.js (64%) rename src/{utils => services}/toast/toast.js (100%) rename src/{utils => services}/toast/toast.service.js (100%) diff --git a/src/index.js b/src/index.js index ccbe9dd..3b4eb52 100644 --- a/src/index.js +++ b/src/index.js @@ -4,14 +4,14 @@ import './index.css'; import './templates'; import Vendor from './vendor'; import Config from './config'; -import Utils from './utils'; +import Services from './services'; import Directives from './directives'; import Components from './components'; module('app', [ Vendor, Config, - Utils, + Services, Directives, Components, ]); diff --git a/src/utils/fetch/fetch.js b/src/services/fetch/fetch.js similarity index 100% rename from src/utils/fetch/fetch.js rename to src/services/fetch/fetch.js diff --git a/src/utils/fetch/fetch.service.js b/src/services/fetch/fetch.service.js similarity index 100% rename from src/utils/fetch/fetch.service.js rename to src/services/fetch/fetch.service.js diff --git a/src/utils/index.js b/src/services/index.js similarity index 64% rename from src/utils/index.js rename to src/services/index.js index 623084f..7297e7b 100644 --- a/src/utils/index.js +++ b/src/services/index.js @@ -2,9 +2,9 @@ import { module } from 'angular'; import Toast from './toast/toast'; import Fetch from './fetch/fetch'; -const Utils = module('app.utils', [ +const Services = module('app.services', [ Toast, Fetch, ]); -export default Utils.name; +export default Services.name; diff --git a/src/utils/toast/toast.js b/src/services/toast/toast.js similarity index 100% rename from src/utils/toast/toast.js rename to src/services/toast/toast.js diff --git a/src/utils/toast/toast.service.js b/src/services/toast/toast.service.js similarity index 100% rename from src/utils/toast/toast.service.js rename to src/services/toast/toast.service.js From e782e353843de56dfa2c46ea49318eada81858ea Mon Sep 17 00:00:00 2001 From: jigsawye Date: Mon, 25 Apr 2016 13:39:52 +0800 Subject: [PATCH 14/58] Move natural sotr function to utils for reusable --- src/components/bucket/bucket.service.js | 20 +++----------------- src/utils/sort.js | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 17 deletions(-) create mode 100644 src/utils/sort.js diff --git a/src/components/bucket/bucket.service.js b/src/components/bucket/bucket.service.js index 6fee2d9..d651b20 100644 --- a/src/components/bucket/bucket.service.js +++ b/src/components/bucket/bucket.service.js @@ -1,5 +1,5 @@ import { element } from 'angular'; -import natural from 'javascript-natural-sort'; +import { sortByName } from '../../utils/sort'; import BucketCreateController from './create/create.controller'; import BucketCreateTemplate from './create/create.html'; @@ -73,20 +73,6 @@ export default class BucketService { this.resetCheckBucketState(); } - /** - * Natural sort for the specified object key. - * - * @param {Object} a - * @param {Object} b - * @return {Integer} - */ - sortByName(a, b) { - const x = a.Name; - const y = b.Name; - - return natural(x, y); - } - /** * Call the bucket list API and modify the state of service. * @@ -99,7 +85,7 @@ export default class BucketService { this.$fetch.post('/v1/bucket/list') .then(({ data }) => { this.state.lists.error = false; - this.state.lists.data = data.Buckets.sort(this.sortByName); + this.state.lists.data = data.Buckets.sort(sortByName); }) .catch(() => { this.state.lists.error = true; @@ -140,7 +126,7 @@ export default class BucketService { createBucket(bucket) { this.$fetch.post('/v1/bucket/create', { bucket }) .then(({ data }) => { - this.state.lists.data = data.Buckets.sort(this.sortByName); + this.state.lists.data = data.Buckets.sort(sortByName); this.$toast.show(`Bucket ${bucket} has created!`); }) .catch(() => { diff --git a/src/utils/sort.js b/src/utils/sort.js new file mode 100644 index 0000000..20a07d5 --- /dev/null +++ b/src/utils/sort.js @@ -0,0 +1,18 @@ +import natural from 'javascript-natural-sort'; + +/** + * Return a function that will sort by given key. + * + * @param {String} x + * @param {String} y + * + * @return {Function} + */ +const sortKey = key => (x, y) => natural(x[key], y[key]); + +/** + * Natural sort by Name. + * + * @return {Function} + */ +export const sortByName = sortKey('Name'); From 55f211c7fc2062b53fe561455075c9d68a724f8b Mon Sep 17 00:00:00 2001 From: Jamie Date: Tue, 26 Apr 2016 15:37:04 +0800 Subject: [PATCH 15/58] Replace upload and create folder icon --- src/components/file/file.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/file/file.html b/src/components/file/file.html index f6dd562..2ad71a5 100644 --- a/src/components/file/file.html +++ b/src/components/file/file.html @@ -65,7 +65,7 @@ class="md-raised md-primary" aria-label="Upload File" ng-click="@A.6" > - add + file_upload Upload File @@ -75,6 +75,7 @@ class="md-raised" aria-label="Create Folder" ng-click="@A.7" > + create_new_folder Create Folder From dd78031e4945c03e752f5fc8367a8d35b47bd013 Mon Sep 17 00:00:00 2001 From: Jamie Date: Wed, 27 Apr 2016 15:42:57 +0800 Subject: [PATCH 16/58] Add dialog-footer and list-dialog style --- src/styles/dialog.css | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/styles/dialog.css b/src/styles/dialog.css index 1ae5712..dfdca9c 100644 --- a/src/styles/dialog.css +++ b/src/styles/dialog.css @@ -20,3 +20,18 @@ md-dialog.input-dialog { .dialog-description { margin-bottom: 30px; } + +.dialog-footer { + margin-left: 20px; + margin-top: 25px; + text-align: center; + width: 100%; +} + +.dialog-footer span { + padding-right: 10px; +} + +.list-dialog md-list-item p { + margin-right: 40px; +} \ No newline at end of file From 57bc03a884d1c5f4b867e9f1cedb96a0f1060f04 Mon Sep 17 00:00:00 2001 From: Jamie Date: Wed, 27 Apr 2016 15:44:41 +0800 Subject: [PATCH 17/58] Add the ui of upload file --- src/components/file/upload/upload.html | 78 ++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/components/file/upload/upload.html diff --git a/src/components/file/upload/upload.html b/src/components/file/upload/upload.html new file mode 100644 index 0000000..ae18adc --- /dev/null +++ b/src/components/file/upload/upload.html @@ -0,0 +1,78 @@ + +
+ +
+

Upload Files

+ + + + + clear + +
+
+ +
+
+

+ To upload files to S3 Portal, click Add Files. To remove files already selected, click the ✖ to the far right of the file name. +

+
+ + + +

Add Files

+ add +
+ + + + + photo + insert_drive_file + +

+

+ + clear +
+ + + +
+
+
+ + + + Cancel + + + + Upload + + + +
+
\ No newline at end of file From 7f836dd404c8b978ec22528d900b81558a598707 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Fri, 6 May 2016 16:12:59 +0800 Subject: [PATCH 18/58] Real api call --- src/components/file/file.service.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/file/file.service.js b/src/components/file/file.service.js index 329d568..5880739 100644 --- a/src/components/file/file.service.js +++ b/src/components/file/file.service.js @@ -36,12 +36,10 @@ export default class FileService { this.state.lists.requesting = true; this.state.lists.data = []; - const fakeList = ['folder1', 'folder2', 'folder3', 'folder4']; - - this.$q(resolve => setTimeout(() => resolve(fakeList), 2000)) - .then(list => { + this.$fetch.get(`/v1/file/list/${this.paths.bucket}`) + .then(({ data }) => { this.state.lists.error = false; - this.state.lists.data = list; + this.state.lists.data = data.files || []; }) .catch(() => { this.state.lists.error = true; From ad02be379bcac43e7a944c42163a8bd638d68a71 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Fri, 6 May 2016 16:25:27 +0800 Subject: [PATCH 19/58] Bind controller properties to view Add file controller properties to file.html for UI display. * import file styles in file module * bind properties --- src/components/file/file.html | 18 +++++++++--------- src/components/file/file.js | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/file/file.html b/src/components/file/file.html index a5f67c7..d6207ad 100644 --- a/src/components/file/file.html +++ b/src/components/file/file.html @@ -1,7 +1,7 @@
@@ -15,28 +15,28 @@
- + insert_drive_file

- +

@@ -46,7 +46,7 @@
Loading...
@@ -55,7 +55,7 @@
This bucket is empty
You can do the following actions
@@ -84,7 +84,7 @@
Oops, your connection seems off...
Don't worry. You can refresh to try again.
diff --git a/src/components/file/file.js b/src/components/file/file.js index 35def55..688374b 100644 --- a/src/components/file/file.js +++ b/src/components/file/file.js @@ -4,6 +4,7 @@ import router from 'angular-ui-router'; import FileController from './file.controller'; import FileService from './file.service'; import FileTemplate from './file.html'; +import './file.css'; /** @ngInject */ const route = $stateProvider => { From 6fc82ff78c8f17d214a6008c129348c5927e8ded Mon Sep 17 00:00:00 2001 From: jigsawye Date: Fri, 6 May 2016 16:36:48 +0800 Subject: [PATCH 20/58] Update $file service * paths.folders is Array * add `prefix` parameters to api call --- src/components/file/file.service.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/file/file.service.js b/src/components/file/file.service.js index 5880739..c87a1fc 100644 --- a/src/components/file/file.service.js +++ b/src/components/file/file.service.js @@ -1,8 +1,8 @@ export default class FileService { /** @ngInject */ - constructor($q, $fetch, $bucket) { + constructor($fetch, $bucket) { Object.assign(this, { - $q, $fetch, $bucket, + $fetch, $bucket, }); this.initState(); @@ -12,7 +12,7 @@ export default class FileService { this.state = { paths: { bucket: '', - folders: '', + folders: [], }, lists: { data: [], @@ -36,7 +36,8 @@ export default class FileService { this.state.lists.requesting = true; this.state.lists.data = []; - this.$fetch.get(`/v1/file/list/${this.paths.bucket}`) + this.$fetch + .get(`/v1/file/list/${this.paths.bucket}?prefix=${this.paths.folders.join('/')}`) .then(({ data }) => { this.state.lists.error = false; this.state.lists.data = data.files || []; From ce3cdb1d8bc7fe88c4c435ce92eb7df0477d38fb Mon Sep 17 00:00:00 2001 From: jigsawye Date: Mon, 16 May 2016 12:27:47 +0800 Subject: [PATCH 21/58] fix bug in action-navbar.html --- src/components/layout/action-navbar/action-navbar.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 8cbd1cb..5a094fb 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -11,7 +11,7 @@ add From 6679b8378cb3ff4e93fd65b9912c4350894a7348 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Mon, 16 May 2016 13:58:06 +0800 Subject: [PATCH 22/58] Update file module Add method to breadcrumb for update the paths and update file module. This commit can display bucket and files, but not yet support display folder. * add `updateFilePath` to $breadcrumb * add necessary method call to file controller --- src/components/file/file.controller.js | 11 +++++--- src/components/file/file.js | 1 + src/components/file/file.service.js | 8 +++--- .../layout/breadcrumb/breadcrumb.service.js | 26 +++++++++++++++++++ 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/components/file/file.controller.js b/src/components/file/file.controller.js index c687fe1..6d1ba78 100644 --- a/src/components/file/file.controller.js +++ b/src/components/file/file.controller.js @@ -1,8 +1,8 @@ export default class FileController { /** @ngInject */ - constructor($scope, $stateParams, $file) { + constructor($scope, $stateParams, $file, $bucket, $breadcrumb) { Object.assign(this, { - $scope, $file, + $scope, $file, $bucket, $breadcrumb, }); this.$scope.$watch( @@ -10,7 +10,12 @@ export default class FileController { newVal => Object.assign(this, newVal) , true); - this.$file.setPaths($stateParams.path); + const [bucket, ...folders] = $stateParams.path.split('/'); + + this.$file.setPaths(bucket, folders); + this.$breadcrumb.updateFilePath(folders); + + this.$bucket.getBuckets(); this.$file.getFiles(); } } diff --git a/src/components/file/file.js b/src/components/file/file.js index 688374b..2b1b585 100644 --- a/src/components/file/file.js +++ b/src/components/file/file.js @@ -14,6 +14,7 @@ const route = $stateProvider => { controller: FileController, controllerAs: 'file', template: FileTemplate, + onEnter: $nav => $nav.setTypeToFile(), }); }; diff --git a/src/components/file/file.service.js b/src/components/file/file.service.js index c87a1fc..83d14bd 100644 --- a/src/components/file/file.service.js +++ b/src/components/file/file.service.js @@ -27,17 +27,19 @@ export default class FileService { }; } - setPaths(path) { - const [bucket, ...folders] = path.split('/'); + setPaths(bucket, folders) { this.paths = { bucket, folders }; } getFiles() { + const { bucket, folders } = this.paths; + const endpoint = `/v1/file/list/${bucket}?prefix=${folders.join('/')}`; + this.state.lists.requesting = true; this.state.lists.data = []; this.$fetch - .get(`/v1/file/list/${this.paths.bucket}?prefix=${this.paths.folders.join('/')}`) + .get(endpoint) .then(({ data }) => { this.state.lists.error = false; this.state.lists.data = data.files || []; diff --git a/src/components/layout/breadcrumb/breadcrumb.service.js b/src/components/layout/breadcrumb/breadcrumb.service.js index a4b517d..9e7fdea 100644 --- a/src/components/layout/breadcrumb/breadcrumb.service.js +++ b/src/components/layout/breadcrumb/breadcrumb.service.js @@ -4,6 +4,11 @@ export default class BreadcrumbService { this.initPaths(); } + /** + * Initial the paths state. + * + * @return {void} + */ initPaths() { this.paths = [{ link: '/bucket', @@ -13,7 +18,28 @@ export default class BreadcrumbService { }]; } + /** + * Update the files length of bucket. + * + * @param {integer} len + * + * @return {void} + */ updateBucketPath(len) { this.paths[0].len = len; } + + /** + * Update paths in breadcrumb bar. + * + * @param {Array} paths + * + * @return {void} + */ + updateFilePath(paths) { + paths.forEach(path => { + const pathLink = this.paths.map(({ link }) => link).join(''); + this.paths.push({ link: pathLink, text: path }); + }); + } } From 0a58ba8e9a832b9479132b87553ad30470e5c769 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Mon, 16 May 2016 14:50:45 +0800 Subject: [PATCH 23/58] Add ng-file-upload to dependencies --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 9af6ecf..bfbb6fb 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "javascript-natural-sort": "^0.7.1", "lodash": "^4.5.1", "material-design-icons": "^2.2.0", + "ng-file-upload": "^12.0.4", "satellizer": "^0.14.0" }, "devDependencies": { From d11309aacdb248f87dcde3b9ef5c3d499c9bac8a Mon Sep 17 00:00:00 2001 From: jigsawye Date: Tue, 17 May 2016 14:16:34 +0800 Subject: [PATCH 24/58] Add fileUpload to vendor and remove angular-breadcrumb --- src/vendor/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vendor/index.js b/src/vendor/index.js index 7c92515..eb26892 100644 --- a/src/vendor/index.js +++ b/src/vendor/index.js @@ -3,8 +3,8 @@ import router from 'angular-ui-router'; import material from 'angular-material'; import translate from 'angular-translate'; import validationMatch from 'angular-validation-match'; +import fileUpload from 'ng-file-upload'; import satellizer from 'satellizer'; -import 'angular-breadcrumb'; const Vendor = module('app.vendor', [ router, @@ -12,7 +12,7 @@ const Vendor = module('app.vendor', [ translate, validationMatch, satellizer, - 'ncy-angular-breadcrumb', + fileUpload, ]); export default Vendor.name; From 6b3d4afc66ad4a570ed4d5e1a31c72f25f1e10ef Mon Sep 17 00:00:00 2001 From: jigsawye Date: Tue, 17 May 2016 14:57:12 +0800 Subject: [PATCH 25/58] Add filesize filter for size format The source file size is 'bytes', so we need a filter to format size for display * Add `src/filters/filesize.js` --- src/filters/filesize.js | 28 ++++++++++++++++++++++++++++ src/filters/index.js | 7 +++++++ src/index.js | 2 ++ 3 files changed, 37 insertions(+) create mode 100644 src/filters/filesize.js create mode 100644 src/filters/index.js diff --git a/src/filters/filesize.js b/src/filters/filesize.js new file mode 100644 index 0000000..b95cf6c --- /dev/null +++ b/src/filters/filesize.js @@ -0,0 +1,28 @@ +const units = [ + 'bytes', + 'KB', + 'MB', + 'GB', + 'TB', + 'PB', +]; + +/** + * Format file size. + * + * @return {String} + */ +export default () => bytes => { + if (isNaN(parseFloat(bytes)) || ! isFinite(bytes)) { + return '?'; + } + + let unit = 0; + + while (bytes >= 1024) { + bytes /= 1024; + unit ++; + } + + return `${bytes.toFixed(2)} ${units[unit]}`; +}; diff --git a/src/filters/index.js b/src/filters/index.js new file mode 100644 index 0000000..5e45983 --- /dev/null +++ b/src/filters/index.js @@ -0,0 +1,7 @@ +import { module } from 'angular'; +import filesize from './filesize'; + +const Filters = module('app.Filters', []) + .filter('filesize', filesize); + +export default Filters.name; diff --git a/src/index.js b/src/index.js index 3b4eb52..14364b5 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ import Vendor from './vendor'; import Config from './config'; import Services from './services'; import Directives from './directives'; +import Filters from './filters'; import Components from './components'; module('app', [ @@ -13,5 +14,6 @@ module('app', [ Config, Services, Directives, + Filters, Components, ]); From f71b02c1b1c74b686c7daa45cd9554a0c0f05279 Mon Sep 17 00:00:00 2001 From: Jamie Date: Tue, 17 May 2016 17:47:57 +0800 Subject: [PATCH 26/58] Add align style for set the vertical alignment --- src/styles/base.css | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/styles/base.css b/src/styles/base.css index 8caa00f..ae5f323 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -41,3 +41,35 @@ .text-center { text-align: center; } + +.break-word { + word-break: break-word; +} + +/* display */ + +.inline{ + display: inline; +} + +.block{ + display: block; +} + +.inline-block{ + display: inline-block; +} + +/* align */ + +.valign-bottom{ + vertical-align: bottom; +} + +.valign-middle{ + vertical-align: middle; +} + +.valign-top{ + vertical-align: top; +} From 4fc9ec78a15a9f5f529b4b7a675d03e7fdbe6f0e Mon Sep 17 00:00:00 2001 From: Jamie Date: Tue, 17 May 2016 17:50:22 +0800 Subject: [PATCH 27/58] Add style for highlight the messages Add style for highlight the messages that are important to user --- src/styles/s3.css | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/styles/s3.css b/src/styles/s3.css index 1351233..15dfb34 100644 --- a/src/styles/s3.css +++ b/src/styles/s3.css @@ -127,3 +127,40 @@ md-input-container md-progress-circular { .load-fail-state { margin-top: 10%; } + +/* list item --------------------------------------------- */ +md-list-item.checked { + background: #E8EAF6; +} + +md-list-item > .md-list-item-inner > p { + padding: 0 8px; +} + +md-list-item > p.flex-none, +md-list-item > .md-list-item-inner > p.flex-none, +md-list-item .md-list-item-inner > p.flex-none, +md-list-item .md-list-item-inner > .md-list-item-inner > p.flex-none { + flex: 0 0 auto; + -ms-flex: 0 0 auto; +} + +md-list-item > p.flex-grow, +md-list-item > .md-list-item-inner > p.flex-grow, +md-list-item .md-list-item-inner > p.flex-grow, +md-list-item .md-list-item-inner > .md-list-item-inner > p.flex-grow { + flex: 1 1 100%; + -ms-flex: 1 1 100%; +} + +md-list.md-default-theme md-list-item.md-2-line .md-list-item-text p.text-warn, +md-list md-list-item.md-2-line .md-list-item-text p.text-warn, +md-list.md-default-theme md-list-item.md-3-line .md-list-item-text p.text-warn, +md-list md-list-item.md-3-line .md-list-item-text p.text-warn { + color: #FF6D00; +} + +/* fix flexbox type layout issues in IE10 */ +span.flex { + display: block; +} \ No newline at end of file From 37cc662b8279595859c85bcede6e19a59529b98e Mon Sep 17 00:00:00 2001 From: Jamie Date: Tue, 17 May 2016 17:54:00 +0800 Subject: [PATCH 28/58] Design transfer view * Add transfer.css * Add transfer.html --- src/components/transfer/transfer.css | 20 ++++++ src/components/transfer/transfer.html | 96 +++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 src/components/transfer/transfer.css create mode 100644 src/components/transfer/transfer.html diff --git a/src/components/transfer/transfer.css b/src/components/transfer/transfer.css new file mode 100644 index 0000000..70da214 --- /dev/null +++ b/src/components/transfer/transfer.css @@ -0,0 +1,20 @@ + +/** + * @author Jamie jamie.h@inwinstack.com + */ + +.transfer-list md-list-item { + border-bottom: 1px solid #eee; +} + +.transfer-list md-list-item:last-child { + border-bottom: none; +} + +.transfer-loaded { + padding-right: 20px; +} + +.transfer-rate { + margin: 10px 20px 10px 0; +} \ No newline at end of file diff --git a/src/components/transfer/transfer.html b/src/components/transfer/transfer.html new file mode 100644 index 0000000..7af9c37 --- /dev/null +++ b/src/components/transfer/transfer.html @@ -0,0 +1,96 @@ + +
+ +
+

+ Transfers +

+ + + + + clear + +
+
+ + + + + +

Automatically clear finished transfers

+
+ + + file_upload + delete + +
+

+ +
+ +
+ +

+ + + + + 1.87MB + / + 2GB + + + + + % + +

+
+ + check_circle + + +
+ +
+
+
+
+
+
\ No newline at end of file From 5bbc8afdf27dc8607cfdf20c60cd3acf3cc240d3 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 13:55:54 +0800 Subject: [PATCH 29/58] Update file.html The file size should be formated. * Add filesize filter to file size * Add refresh method to click event --- src/components/file/file.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/file/file.html b/src/components/file/file.html index d6207ad..86eb9cd 100644 --- a/src/components/file/file.html +++ b/src/components/file/file.html @@ -30,13 +30,13 @@

@@ -63,7 +63,7 @@
file_upload Upload File @@ -73,7 +73,7 @@ create_new_folder Create Folder @@ -91,7 +91,7 @@ refresh From 3d1c5c6daedd5e17bf516432d71bf99fc358bbcd Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 13:58:10 +0800 Subject: [PATCH 30/58] Remove unnecessary state and dependence in file.service.js --- src/components/file/file.service.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/file/file.service.js b/src/components/file/file.service.js index 83d14bd..54c721e 100644 --- a/src/components/file/file.service.js +++ b/src/components/file/file.service.js @@ -1,8 +1,8 @@ export default class FileService { /** @ngInject */ - constructor($fetch, $bucket) { + constructor($mdDialog, $fetch, $bucket) { Object.assign(this, { - $fetch, $bucket, + $mdDialog, $fetch, $bucket, }); this.initState(); @@ -19,11 +19,6 @@ export default class FileService { requesting: false, error: false, }, - create: { - checking: false, - checked: false, - duplicated: false, - }, }; } From d90dfd1c49dd91cca3b133873d78b6080bac51ea Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 13:59:36 +0800 Subject: [PATCH 31/58] Add file upload component Add a upload component for file uploading. The component allow user can upload multiple files to s3 protal. * Add file upload service for handle file upload. * Add some method(upload, refresh) to file controller. * Add file upload controller for connect service and dialog. * Apply file upload UI design. --- src/components/file/file.controller.js | 18 ++- src/components/file/file.js | 2 + .../file/upload/upload.controller.js | 29 +++++ src/components/file/upload/upload.html | 59 +++++---- src/components/file/upload/upload.servce.js | 113 ++++++++++++++++++ 5 files changed, 192 insertions(+), 29 deletions(-) create mode 100644 src/components/file/upload/upload.controller.js create mode 100644 src/components/file/upload/upload.servce.js diff --git a/src/components/file/file.controller.js b/src/components/file/file.controller.js index 6d1ba78..7d2fc13 100644 --- a/src/components/file/file.controller.js +++ b/src/components/file/file.controller.js @@ -1,11 +1,11 @@ export default class FileController { /** @ngInject */ - constructor($scope, $stateParams, $file, $bucket, $breadcrumb) { + constructor($scope, $stateParams, $file, $bucket, $breadcrumb, $upload) { Object.assign(this, { - $scope, $file, $bucket, $breadcrumb, + $file, $upload, $bucket, $breadcrumb, }); - this.$scope.$watch( + $scope.$watch( () => $file.state.lists, newVal => Object.assign(this, newVal) , true); @@ -18,4 +18,16 @@ export default class FileController { this.$bucket.getBuckets(); this.$file.getFiles(); } + + createFolder($event) { + this.$file.createFolder($event); + } + + upload($event) { + this.$upload.createDialog($event); + } + + refresh() { + this.$file.getFiles(); + } } diff --git a/src/components/file/file.js b/src/components/file/file.js index 2b1b585..469bb64 100644 --- a/src/components/file/file.js +++ b/src/components/file/file.js @@ -4,6 +4,7 @@ import router from 'angular-ui-router'; import FileController from './file.controller'; import FileService from './file.service'; import FileTemplate from './file.html'; +import UploadService from './upload/upload.servce'; import './file.css'; /** @ngInject */ @@ -22,6 +23,7 @@ const File = module('file', [ router, ]) .service('$file', FileService) +.service('$upload', UploadService) .config(route); export default File.name; diff --git a/src/components/file/upload/upload.controller.js b/src/components/file/upload/upload.controller.js new file mode 100644 index 0000000..a9f246a --- /dev/null +++ b/src/components/file/upload/upload.controller.js @@ -0,0 +1,29 @@ +export default class FileUploadController { + /** @ngInject */ + constructor($file, $upload, $scope) { + Object.assign(this, { + $file, $upload, $scope, + }); + + $scope.$watch( + () => $upload.state, + newVal => Object.assign(this, newVal) + , true); + } + + upload() { + this.$upload.upload(); + } + + select(files) { + this.$upload.select(files); + } + + delete(name) { + this.$upload.delete(name); + } + + cancel() { + this.$upload.closeDialog(); + } +} diff --git a/src/components/file/upload/upload.html b/src/components/file/upload/upload.html index ae18adc..b2b322e 100644 --- a/src/components/file/upload/upload.html +++ b/src/components/file/upload/upload.html @@ -1,14 +1,14 @@ -
+

Upload Files

- + clear @@ -21,58 +21,65 @@

Upload Files

To upload files to S3 Portal, click Add Files. To remove files already selected, click the ✖ to the far right of the file name.

- + -

Add Files

- add +
+

Add Files

+ add +
- + - - - photo - insert_drive_file - -

-

- + + + photo + insert_drive_file + +

+

+ clear
- + -
- + Cancel Upload - \ No newline at end of file + diff --git a/src/components/file/upload/upload.servce.js b/src/components/file/upload/upload.servce.js new file mode 100644 index 0000000..9caf81f --- /dev/null +++ b/src/components/file/upload/upload.servce.js @@ -0,0 +1,113 @@ +import { element } from 'angular'; +import FileUploadController from './upload.controller'; +import FileUploadTemplate from './upload.html'; + +export default class FileUploadService { + /** @ngInject */ + constructor(Config, Upload, $mdDialog, $file, $toast) { + Object.assign(this, { + Config, Upload, $mdDialog, $file, $toast, + }); + + this.initState(); + } + + initState() { + this.state = { + files: [], + size: 0, + uploadingFiles: [], + }; + } + + select(selectFiles) { + const filterFiles = selectFiles.filter(selectFile => + this.state.files.every(file => file.name !== selectFile.name) + ); + const files = this.state.files.concat(filterFiles); + const size = this.size(files); + this.state = { ...this.state, files, size }; + } + + delete(name) { + const files = this.state.files.filter(file => file.name !== name); + const size = this.size(files); + + this.state = { ...this.state, files, size }; + } + + isUploading() { + return !! this.state.uploadingFiles.length; + } + + abort() { + this.state.uploadingFiles.forEach(file => file.abort()); + this.state.uploadingFiles = []; + } + + upload() { + const { bucket, folders } = this.$file.paths; + const prefix = folders.length ? '' : `${folders.join('/')}/`; + const url = `${this.Config.API_URL}/v1/file/create`; + + this.state.files.forEach(file => + this.uploadFile(url, { bucket, prefix, file }) + ); + + this.closeDialog(); + } + + size(files) { + return files.reduce((previous, current) => previous + current.size, 0); + } + + uploadFile = (url, data) => { + const { name } = data.file; + const upload = this.Upload.upload({ url, data }); + this.state.uploadingFiles.push(upload); + + upload.then( + () => this.handleUploadSuccess(name), + () => this.handleUploadFailure(name), + this.handleEvent + ); + } + + handleEvent = evt => { + console.log(evt); + } + + handleUploadSuccess(name) { + this.removeUploadingFile(name); + this.$file.getFiles(); + this.$toast.show(`${name} is uploaded successfully!`); + } + + handleUploadFailure(name) { + this.removeUploadingFile(name); + this.$toast.show(`${name} is uploaded failure!`); + } + + removeUploadingFile(name) { + this.state.uploadingFiles.filter(uploadingFile => + uploadingFile.name !== name + ); + } + + createDialog($event) { + this.$mdDialog.show({ + controller: FileUploadController, + controllerAs: 'upload', + template: FileUploadTemplate, + parent: element(document.body), + targetEvent: $event, + clickOutsideToClose: true, + }); + } + + closeDialog() { + this.$mdDialog.cancel(); + this.state.files = []; + this.state.size = 0; + } +} From 0054bd712ee4678e62da48757356d12d4afeff21 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 14:03:31 +0800 Subject: [PATCH 32/58] Add sign out handler Add a handler to sign out event, because we need let user know they have files are uploading. If user want to sign out and have some file are uploading, then we will abort all uploading file and log out the user. * Add a condition to signOut and abort file upload when sign out --- .../layout/top-navbar/top-navbar.controller.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/layout/top-navbar/top-navbar.controller.js b/src/components/layout/top-navbar/top-navbar.controller.js index 80be162..742e24a 100644 --- a/src/components/layout/top-navbar/top-navbar.controller.js +++ b/src/components/layout/top-navbar/top-navbar.controller.js @@ -1,8 +1,8 @@ export default class TopNavbarController { /** @ngInject */ - constructor($translate, $auth, $state, $toast, $mdDialog, AuthService) { + constructor($scope, $translate, $auth, $state, $toast, $mdDialog, $upload, AuthService) { Object.assign(this, { - $translate, $auth, $state, $toast, $mdDialog, AuthService, + $scope, $translate, $auth, $state, $toast, $mdDialog, $upload, AuthService, }); this.languages = [ @@ -32,7 +32,11 @@ export default class TopNavbarController { * @return {void} */ signOut($event) { - this.showConfirmMessage($event).then(this.executedSignOut); + if (this.$upload.isUploading()) { + this.showConfirmMessage($event).then(this.executedSignOut); + } else { + this.executedSignOut(); + } } /** @@ -61,6 +65,7 @@ or uploads and leaving now will cancel them.Still leaving?`) */ executedSignOut = () => this.AuthService.signOut() .then(() => { + this.$upload.abort(); this.$auth.logout(); this.$state.go('auth.signin'); this.$toast.show('Sign Out Success!'); From 30283b7de0e9948048e8086a8767d2cd73180ec5 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 14:09:55 +0800 Subject: [PATCH 33/58] Add method to Upload button in action navbar --- .../layout/action-navbar/action-navbar.controller.js | 12 ++++++------ .../layout/action-navbar/action-navbar.html | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/layout/action-navbar/action-navbar.controller.js b/src/components/layout/action-navbar/action-navbar.controller.js index 34da8c9..62cbdf2 100644 --- a/src/components/layout/action-navbar/action-navbar.controller.js +++ b/src/components/layout/action-navbar/action-navbar.controller.js @@ -1,8 +1,8 @@ export default class ActionNavbarController { /** @ngInject */ - constructor($scope, $bucket, $nav) { + constructor($scope, $bucket, $nav, $file, $upload) { Object.assign(this, { - $scope, $bucket, + $scope, $bucket, $file, $upload, }); this.$scope.$watch( @@ -28,8 +28,8 @@ export default class ActionNavbarController { // } - upload() { - // + upload($event) { + this.$upload.createDialog($event); } delete() { @@ -56,7 +56,7 @@ export default class ActionNavbarController { */ create($event) { if (this.isFile()) { - // create file dialog + // } else { this.$bucket.createDialog($event); } @@ -69,7 +69,7 @@ export default class ActionNavbarController { */ refresh() { if (this.isFile()) { - // get the files + this.$file.getFiles(); } else { this.$bucket.getBuckets(); } diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 5a094fb..2e57048 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -2,7 +2,7 @@
file_upload From f024de07dad80c48d131b25cb7dc788934e2a261 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 14:28:18 +0800 Subject: [PATCH 34/58] Fix breadcrumb bar The current breadcrumb have loop bugs, this commit just fixed it. * Should reset paths when upload file path * Should update path when enter bucket list --- src/components/bucket/bucket.controller.js | 3 ++- src/components/file/file.controller.js | 5 +++-- src/components/layout/breadcrumb/breadcrumb.service.js | 10 ++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/components/bucket/bucket.controller.js b/src/components/bucket/bucket.controller.js index c7dafe5..c3fb2c7 100644 --- a/src/components/bucket/bucket.controller.js +++ b/src/components/bucket/bucket.controller.js @@ -1,6 +1,6 @@ export default class BucketController { /** @ngInject */ - constructor($scope, $bucket, $state) { + constructor($scope, $bucket, $state, $breadcrumb) { Object.assign(this, { $scope, $bucket, $state, }); @@ -10,6 +10,7 @@ export default class BucketController { newVal => Object.assign(this, newVal) , true); + $breadcrumb.initPaths(); this.$bucket.getBuckets(); } diff --git a/src/components/file/file.controller.js b/src/components/file/file.controller.js index 7d2fc13..ac164d4 100644 --- a/src/components/file/file.controller.js +++ b/src/components/file/file.controller.js @@ -10,10 +10,11 @@ export default class FileController { newVal => Object.assign(this, newVal) , true); - const [bucket, ...folders] = $stateParams.path.split('/'); + const paths = $stateParams.path.split('/'); + const [bucket, ...folders] = paths; this.$file.setPaths(bucket, folders); - this.$breadcrumb.updateFilePath(folders); + this.$breadcrumb.updateFilePath(paths); this.$bucket.getBuckets(); this.$file.getFiles(); diff --git a/src/components/layout/breadcrumb/breadcrumb.service.js b/src/components/layout/breadcrumb/breadcrumb.service.js index 9e7fdea..259fd4a 100644 --- a/src/components/layout/breadcrumb/breadcrumb.service.js +++ b/src/components/layout/breadcrumb/breadcrumb.service.js @@ -37,9 +37,11 @@ export default class BreadcrumbService { * @return {void} */ updateFilePath(paths) { - paths.forEach(path => { - const pathLink = this.paths.map(({ link }) => link).join(''); - this.paths.push({ link: pathLink, text: path }); - }); + this.initPaths(); + paths.reduce((previous, current) => { + const link = `${previous}/${current}`; + this.paths.push({ link, text: current }); + return link; + }, '/bucket'); } } From b8f6cffad92f40a66d072e5ca12b9db8cd7a87bb Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 15:46:33 +0800 Subject: [PATCH 35/58] Add transfer UI & update layout component Add layout controller & layout service for control transfer display state. * Apply the UI design * Add LayoutController & LayoutService * Add toggleTransfer() to the transfer button click event --- src/components/index.js | 2 ++ .../action-navbar/action-navbar.controller.js | 8 +++--- .../layout/action-navbar/action-navbar.html | 2 +- src/components/layout/layout.controller.js | 12 +++++++++ src/components/layout/layout.html | 6 ++++- src/components/layout/layout.js | 12 +++++++++ src/components/layout/layout.service.js | 15 +++++++++++ .../layout/transfer/transfer.controller.js | 12 +++++++++ .../{ => layout}/transfer/transfer.css | 0 .../{ => layout}/transfer/transfer.html | 26 +++++++++---------- 10 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 src/components/layout/layout.controller.js create mode 100644 src/components/layout/layout.service.js create mode 100644 src/components/layout/transfer/transfer.controller.js rename src/components/{ => layout}/transfer/transfer.css (100%) rename src/components/{ => layout}/transfer/transfer.html (94%) diff --git a/src/components/index.js b/src/components/index.js index d209813..a6d0113 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,6 +1,7 @@ import { module } from 'angular'; import Layout from './layout/layout'; import NotFound from './not-found/not-found'; +import Transfer from './transfer/transfer'; import Auth from './auth/auth'; import Bucket from './bucket/bucket'; import File from './file/file'; @@ -8,6 +9,7 @@ import File from './file/file'; const Components = module('app.components', [ Layout, NotFound, + Transfer, Auth, Bucket, File, diff --git a/src/components/layout/action-navbar/action-navbar.controller.js b/src/components/layout/action-navbar/action-navbar.controller.js index 62cbdf2..4b6940e 100644 --- a/src/components/layout/action-navbar/action-navbar.controller.js +++ b/src/components/layout/action-navbar/action-navbar.controller.js @@ -1,8 +1,8 @@ export default class ActionNavbarController { /** @ngInject */ - constructor($scope, $bucket, $nav, $file, $upload) { + constructor($scope, $bucket, $nav, $file, $upload, $layout) { Object.assign(this, { - $scope, $bucket, $file, $upload, + $scope, $bucket, $file, $upload, $layout, }); this.$scope.$watch( @@ -44,8 +44,8 @@ export default class ActionNavbarController { // } - transfers() { - // + toggleTransfer() { + this.$layout.toggleTransfer(); } /** diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 2e57048..0c4bb48 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -122,7 +122,7 @@ Transfers diff --git a/src/components/layout/layout.controller.js b/src/components/layout/layout.controller.js new file mode 100644 index 0000000..854e082 --- /dev/null +++ b/src/components/layout/layout.controller.js @@ -0,0 +1,12 @@ +export default class LayoutController { + /** @ngInject */ + constructor($layout) { + Object.assign(this, { + $layout, + }); + } + + toggleTransfer() { + this.$layout.toggleTransfer(); + } +} diff --git a/src/components/layout/layout.html b/src/components/layout/layout.html index 5000fb0..7e99a0f 100644 --- a/src/components/layout/layout.html +++ b/src/components/layout/layout.html @@ -9,5 +9,9 @@
- +
diff --git a/src/components/layout/layout.js b/src/components/layout/layout.js index d230579..819b2d5 100644 --- a/src/components/layout/layout.js +++ b/src/components/layout/layout.js @@ -1,6 +1,8 @@ import { module } from 'angular'; import router from 'angular-ui-router'; +import LayoutController from './layout.controller'; +import LayoutService from './layout.service'; import LayoutTemplate from './layout.html'; import TopNavbarController from './top-navbar/top-navbar.controller'; import TopNavbarTemplate from './top-navbar/top-navbar.html'; @@ -10,6 +12,8 @@ import BreadcrumbService from './breadcrumb/breadcrumb.service'; import ActionNavbarController from './action-navbar/action-navbar.controller'; import ActionNavbarTemplate from './action-navbar/action-navbar.html'; import ActionNavbarService from './action-navbar/action-navbar.service'; +import TransferController from './transfer/transfer.controller'; +import TransferTemplate from './transfer/transfer.html'; import './layout.css'; @@ -21,6 +25,8 @@ const route = $stateProvider => { views: { '': { template: LayoutTemplate, + controller: LayoutController, + controllerAs: 'layout', }, 'top-navbar@root': { template: TopNavbarTemplate, @@ -37,6 +43,11 @@ const route = $stateProvider => { controller: BreadcrumbController, controllerAs: 'bc', }, + 'transfer@root': { + template: TransferTemplate, + controller: TransferController, + controllerAs: 'transfer', + }, }, }); }; @@ -46,6 +57,7 @@ const Layout = module('layout', [ ]) .service('$breadcrumb', BreadcrumbService) .service('$nav', ActionNavbarService) +.service('$layout', LayoutService) .config(route); export default Layout.name; diff --git a/src/components/layout/layout.service.js b/src/components/layout/layout.service.js new file mode 100644 index 0000000..9115abb --- /dev/null +++ b/src/components/layout/layout.service.js @@ -0,0 +1,15 @@ +export default class LayoutService { + constructor() { + this.initState(); + } + + initState() { + this.state = { + transfer: false, + }; + } + + toggleTransfer() { + this.state.transfer = ! this.state.transfer; + } +} diff --git a/src/components/layout/transfer/transfer.controller.js b/src/components/layout/transfer/transfer.controller.js new file mode 100644 index 0000000..a3691e5 --- /dev/null +++ b/src/components/layout/transfer/transfer.controller.js @@ -0,0 +1,12 @@ +export default class TransferController { + /** @ngInject */ + constructor($layout) { + Object.assign(this, { + $layout, + }); + } + + close() { + this.$layout.toggleTransfer(); + } +} diff --git a/src/components/transfer/transfer.css b/src/components/layout/transfer/transfer.css similarity index 100% rename from src/components/transfer/transfer.css rename to src/components/layout/transfer/transfer.css diff --git a/src/components/transfer/transfer.html b/src/components/layout/transfer/transfer.html similarity index 94% rename from src/components/transfer/transfer.html rename to src/components/layout/transfer/transfer.html index 7af9c37..0cd3d15 100644 --- a/src/components/transfer/transfer.html +++ b/src/components/layout/transfer/transfer.html @@ -5,18 +5,18 @@

Transfers

- + - + clear
- + @@ -25,7 +25,7 @@

>

Automatically clear finished transfers

- + delete - +

- +
- +

- + 1.87MB / 2GB - + %

- + class="material-icons md-warn" ng-if="@A.21" ng-click="@A.24" >refresh--> - +
- \ No newline at end of file + From f46b0b1abdeae9dfb0a0f2d2f03e74e9bc76e7d3 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 16:02:00 +0800 Subject: [PATCH 36/58] Add transfer service --- src/components/layout/layout.js | 3 +++ src/components/layout/transfer/transfer.service.js | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 src/components/layout/transfer/transfer.service.js diff --git a/src/components/layout/layout.js b/src/components/layout/layout.js index 819b2d5..a5c8c11 100644 --- a/src/components/layout/layout.js +++ b/src/components/layout/layout.js @@ -14,8 +14,10 @@ import ActionNavbarTemplate from './action-navbar/action-navbar.html'; import ActionNavbarService from './action-navbar/action-navbar.service'; import TransferController from './transfer/transfer.controller'; import TransferTemplate from './transfer/transfer.html'; +import TransferService from './transfer/transfer.service'; import './layout.css'; +import './transfer/transfer.css'; /** @ngInject */ const route = $stateProvider => { @@ -58,6 +60,7 @@ const Layout = module('layout', [ .service('$breadcrumb', BreadcrumbService) .service('$nav', ActionNavbarService) .service('$layout', LayoutService) +.service('$transfer', TransferService) .config(route); export default Layout.name; diff --git a/src/components/layout/transfer/transfer.service.js b/src/components/layout/transfer/transfer.service.js new file mode 100644 index 0000000..496d855 --- /dev/null +++ b/src/components/layout/transfer/transfer.service.js @@ -0,0 +1,11 @@ +export default class TransferService { + constructor() { + this.initState(); + } + + initState() { + this.state = { + transfers: {}, + }; + } +} From cf833f43864a839a870234adac267099f27c2792 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 16:24:05 +0800 Subject: [PATCH 37/58] Remove transfer import in components/index.js --- src/components/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/index.js b/src/components/index.js index a6d0113..d209813 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,7 +1,6 @@ import { module } from 'angular'; import Layout from './layout/layout'; import NotFound from './not-found/not-found'; -import Transfer from './transfer/transfer'; import Auth from './auth/auth'; import Bucket from './bucket/bucket'; import File from './file/file'; @@ -9,7 +8,6 @@ import File from './file/file'; const Components = module('app.components', [ Layout, NotFound, - Transfer, Auth, Bucket, File, From c931e89ba549239ed1862f511cd5c1f6e93806c5 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 16:26:54 +0800 Subject: [PATCH 38/58] Use boolean to control upadting status --- src/components/file/upload/upload.servce.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/components/file/upload/upload.servce.js b/src/components/file/upload/upload.servce.js index 9caf81f..2ab3381 100644 --- a/src/components/file/upload/upload.servce.js +++ b/src/components/file/upload/upload.servce.js @@ -16,6 +16,7 @@ export default class FileUploadService { this.state = { files: [], size: 0, + uploading: false, uploadingFiles: [], }; } @@ -37,7 +38,7 @@ export default class FileUploadService { } isUploading() { - return !! this.state.uploadingFiles.length; + return this.state.uploading; } abort() { @@ -61,19 +62,20 @@ export default class FileUploadService { return files.reduce((previous, current) => previous + current.size, 0); } - uploadFile = (url, data) => { + uploadFile(url, data) { const { name } = data.file; const upload = this.Upload.upload({ url, data }); this.state.uploadingFiles.push(upload); + this.state.uploading = true; upload.then( () => this.handleUploadSuccess(name), - () => this.handleUploadFailure(name), - this.handleEvent + err => this.handleUploadFailure(name, err), + evt => this.handleEvent(name, evt) ); } - handleEvent = evt => { + handleEvent(name, evt) { console.log(evt); } @@ -83,15 +85,19 @@ export default class FileUploadService { this.$toast.show(`${name} is uploaded successfully!`); } - handleUploadFailure(name) { + handleUploadFailure(name, err) { this.removeUploadingFile(name); - this.$toast.show(`${name} is uploaded failure!`); + this.$toast.show(`${name} is uploaded failure! Error: ${err}`); } removeUploadingFile(name) { this.state.uploadingFiles.filter(uploadingFile => uploadingFile.name !== name ); + + if (! this.state.uploadingFiles.length) { + this.state.uploading = false; + } } createDialog($event) { From 48fadf8c89d5aedb579ce94bb0b25210bc54e73e Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 16:30:15 +0800 Subject: [PATCH 39/58] Move toal size method to utils --- src/components/file/upload/upload.servce.js | 9 +++------ src/utils/totalSize.js | 9 +++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 src/utils/totalSize.js diff --git a/src/components/file/upload/upload.servce.js b/src/components/file/upload/upload.servce.js index 2ab3381..4da84ec 100644 --- a/src/components/file/upload/upload.servce.js +++ b/src/components/file/upload/upload.servce.js @@ -1,4 +1,5 @@ import { element } from 'angular'; +import totalSize from '../../../utils/totalSize'; import FileUploadController from './upload.controller'; import FileUploadTemplate from './upload.html'; @@ -26,13 +27,13 @@ export default class FileUploadService { this.state.files.every(file => file.name !== selectFile.name) ); const files = this.state.files.concat(filterFiles); - const size = this.size(files); + const size = totalSize(files); this.state = { ...this.state, files, size }; } delete(name) { const files = this.state.files.filter(file => file.name !== name); - const size = this.size(files); + const size = totalSize(files); this.state = { ...this.state, files, size }; } @@ -58,10 +59,6 @@ export default class FileUploadService { this.closeDialog(); } - size(files) { - return files.reduce((previous, current) => previous + current.size, 0); - } - uploadFile(url, data) { const { name } = data.file; const upload = this.Upload.upload({ url, data }); diff --git a/src/utils/totalSize.js b/src/utils/totalSize.js new file mode 100644 index 0000000..e88454d --- /dev/null +++ b/src/utils/totalSize.js @@ -0,0 +1,9 @@ +/** + * Calculate the total size of files. + * + * @type {Array} + */ +export default files => files + .reduce((previous, current) => + previous + current.size, 0 + ); From d26b84b86cb89e5034b7571c75db53c4d45aedcd Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 16:34:09 +0800 Subject: [PATCH 40/58] Update method name --- src/components/file/upload/upload.servce.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/file/upload/upload.servce.js b/src/components/file/upload/upload.servce.js index 4da84ec..e202721 100644 --- a/src/components/file/upload/upload.servce.js +++ b/src/components/file/upload/upload.servce.js @@ -66,8 +66,8 @@ export default class FileUploadService { this.state.uploading = true; upload.then( - () => this.handleUploadSuccess(name), - err => this.handleUploadFailure(name, err), + () => this.handleSuccess(name), + err => this.handleFailure(name, err), evt => this.handleEvent(name, evt) ); } @@ -76,13 +76,13 @@ export default class FileUploadService { console.log(evt); } - handleUploadSuccess(name) { + handleSuccess(name) { this.removeUploadingFile(name); this.$file.getFiles(); this.$toast.show(`${name} is uploaded successfully!`); } - handleUploadFailure(name, err) { + handleFailure(name, err) { this.removeUploadingFile(name); this.$toast.show(`${name} is uploaded failure! Error: ${err}`); } From 89fac79e9aa2168a37da29e9e412ec172dda8371 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Wed, 18 May 2016 18:25:56 +0800 Subject: [PATCH 41/58] Refactor upload component Modify the state of upload service, because the privous are not useable in transfer. All files(pending, uploading, success...) in state.files now, and use `status` for control. * Refactor state tree. * Refactor methods. * Update totalSize --- .../file/upload/upload.controller.js | 5 +- src/components/file/upload/upload.html | 10 +- src/components/file/upload/upload.servce.js | 97 ++++++++++++------- src/utils/totalSize.js | 2 +- 4 files changed, 71 insertions(+), 43 deletions(-) diff --git a/src/components/file/upload/upload.controller.js b/src/components/file/upload/upload.controller.js index a9f246a..d20aabe 100644 --- a/src/components/file/upload/upload.controller.js +++ b/src/components/file/upload/upload.controller.js @@ -7,7 +7,10 @@ export default class FileUploadController { $scope.$watch( () => $upload.state, - newVal => Object.assign(this, newVal) + newVal => Object.assign(this, { + ...newVal, + files: newVal.files.filter(file => file.status === 'PENDING'), + }) , true); } diff --git a/src/components/file/upload/upload.html b/src/components/file/upload/upload.html index b2b322e..3ed64e6 100644 --- a/src/components/file/upload/upload.html +++ b/src/components/file/upload/upload.html @@ -41,15 +41,15 @@

Upload Files

- photo - insert_drive_file + photo + insert_drive_file -

-

+

+

clear
diff --git a/src/components/file/upload/upload.servce.js b/src/components/file/upload/upload.servce.js index e202721..65cb307 100644 --- a/src/components/file/upload/upload.servce.js +++ b/src/components/file/upload/upload.servce.js @@ -18,21 +18,29 @@ export default class FileUploadService { files: [], size: 0, uploading: false, - uploadingFiles: [], }; } - select(selectFiles) { - const filterFiles = selectFiles.filter(selectFile => - this.state.files.every(file => file.name !== selectFile.name) - ); - const files = this.state.files.concat(filterFiles); + select(selectedFiles) { + const additionalFiles = selectedFiles.filter(selectedFile => + this.state.files.every(({ detail, status }) => + (detail.name === selectedFile.name && status !== 'PENDING') || + (detail.name !== selectedFile.name && status === 'PENDING') + ) + ).map(detail => ({ + id: Symbol('unique id'), + status: 'PENDING', + detail, + })); + + const files = [...this.state.files, ...additionalFiles]; + const size = totalSize(files); this.state = { ...this.state, files, size }; } - delete(name) { - const files = this.state.files.filter(file => file.name !== name); + delete(id) { + const files = this.state.files.filter(file => file.id !== id); const size = totalSize(files); this.state = { ...this.state, files, size }; @@ -43,8 +51,12 @@ export default class FileUploadService { } abort() { - this.state.uploadingFiles.forEach(file => file.abort()); - this.state.uploadingFiles = []; + this.state.files.forEach(file => file.upload.abort()); + this.state.files = []; + } + + findFileIndex(id) { + return this.state.files.findIndex(file => file.id === id); } upload() { @@ -52,49 +64,63 @@ export default class FileUploadService { const prefix = folders.length ? '' : `${folders.join('/')}/`; const url = `${this.Config.API_URL}/v1/file/create`; - this.state.files.forEach(file => - this.uploadFile(url, { bucket, prefix, file }) - ); + this.state = { + uploading: true, + files: this.state.files.map(file => ({ + ...file, + status: 'UPLOADING', + upload: this.uploadFile(file.id, { + bucket, prefix, file: file.detail, + }, url), + })), + }; this.closeDialog(); } - uploadFile(url, data) { - const { name } = data.file; + uploadFile(id, data, url) { const upload = this.Upload.upload({ url, data }); - this.state.uploadingFiles.push(upload); - this.state.uploading = true; upload.then( - () => this.handleSuccess(name), - err => this.handleFailure(name, err), - evt => this.handleEvent(name, evt) + res => this.handleSuccess(id, res), + err => this.handleFailure(id, err), + evt => this.handleEvent(id, evt) ); + + return upload; } - handleEvent(name, evt) { - console.log(evt); + handleEvent(id, evt) { + const i = this.findFileIndex(id); + this.state.files[i].process = evt; + console.log(this.state.files[i].process); + console.log(this.state); } - handleSuccess(name) { - this.removeUploadingFile(name); + handleSuccess(id, res) { + const i = this.findFileIndex(id); + this.state.files[i].status = 'UPLOADED'; + this.updateUpdateStatus(); this.$file.getFiles(); - this.$toast.show(`${name} is uploaded successfully!`); + console.log(res); } - handleFailure(name, err) { - this.removeUploadingFile(name); - this.$toast.show(`${name} is uploaded failure! Error: ${err}`); + handleFailure(id, err) { + const i = this.findFileIndex(id); + this.state.files[i].status = 'FAILURE'; + this.updateUpdateStatus(); + console.log(err); } - removeUploadingFile(name) { - this.state.uploadingFiles.filter(uploadingFile => - uploadingFile.name !== name - ); + removeUploadFile(id) { + const i = this.findFileIndex(id); + delete this.state.files[i]; + } - if (! this.state.uploadingFiles.length) { - this.state.uploading = false; - } + updateUpdateStatus() { + this.state.uploading = this.state.files.every( + file => file.status === 'UPLOADING' + ); } createDialog($event) { @@ -110,7 +136,6 @@ export default class FileUploadService { closeDialog() { this.$mdDialog.cancel(); - this.state.files = []; this.state.size = 0; } } diff --git a/src/utils/totalSize.js b/src/utils/totalSize.js index e88454d..61d9b6e 100644 --- a/src/utils/totalSize.js +++ b/src/utils/totalSize.js @@ -5,5 +5,5 @@ */ export default files => files .reduce((previous, current) => - previous + current.size, 0 + previous + current.detail.size, 0 ); From c0a0904c28c2271268523fd779888f2a8a38a538 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Thu, 19 May 2016 14:56:17 +0800 Subject: [PATCH 42/58] Update TokenInterceptor for other error handler The authentication will throw a `token_invalid` fails so add new condition for handle it. * Update config/http.config.js --- src/config/http.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config/http.config.js b/src/config/http.config.js index 7270500..25869aa 100644 --- a/src/config/http.config.js +++ b/src/config/http.config.js @@ -1,7 +1,8 @@ const TokenInterceptor = ($q, $injector) => ({ responseError(rejection) { const { data } = rejection; - if (data.error && data.error === 'token_not_provided') { + if (data.error && data.error === 'token_not_provided' || data.error === 'token_invalid') { + $injector.get('$auth').logout(); $injector.get('$state').go('auth.signin'); $injector.get('$toast').show('Your token has expired, please sign in again!'); } From c98ab5bda72f6aa91ba33550fb2d92eccf7695a1 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Thu, 19 May 2016 15:01:21 +0800 Subject: [PATCH 43/58] Complete transfer component Move all upload object to transfer service, because the transfer should display upload status and delete status, so the both data must be handle in same service. * Move methods to transfer service * Add some translations * Move app's updating status to $transfer and renamed to processing --- .../file/upload/upload.controller.js | 5 +- src/components/file/upload/upload.servce.js | 90 +++++-------------- .../top-navbar/top-navbar.controller.js | 8 +- .../layout/transfer/transfer.controller.js | 40 ++++++++- src/components/layout/transfer/transfer.html | 42 ++++----- .../layout/transfer/transfer.service.js | 83 ++++++++++++++++- src/translations/EN.js | 12 +++ 7 files changed, 179 insertions(+), 101 deletions(-) diff --git a/src/components/file/upload/upload.controller.js b/src/components/file/upload/upload.controller.js index d20aabe..a9f246a 100644 --- a/src/components/file/upload/upload.controller.js +++ b/src/components/file/upload/upload.controller.js @@ -7,10 +7,7 @@ export default class FileUploadController { $scope.$watch( () => $upload.state, - newVal => Object.assign(this, { - ...newVal, - files: newVal.files.filter(file => file.status === 'PENDING'), - }) + newVal => Object.assign(this, newVal) , true); } diff --git a/src/components/file/upload/upload.servce.js b/src/components/file/upload/upload.servce.js index 65cb307..15ef8a6 100644 --- a/src/components/file/upload/upload.servce.js +++ b/src/components/file/upload/upload.servce.js @@ -5,9 +5,9 @@ import FileUploadTemplate from './upload.html'; export default class FileUploadService { /** @ngInject */ - constructor(Config, Upload, $mdDialog, $file, $toast) { + constructor(Config, Upload, $mdDialog, $file, $transfer) { Object.assign(this, { - Config, Upload, $mdDialog, $file, $toast, + Config, Upload, $mdDialog, $file, $transfer, }); this.initState(); @@ -17,20 +17,14 @@ export default class FileUploadService { this.state = { files: [], size: 0, - uploading: false, }; } select(selectedFiles) { const additionalFiles = selectedFiles.filter(selectedFile => - this.state.files.every(({ detail, status }) => - (detail.name === selectedFile.name && status !== 'PENDING') || - (detail.name !== selectedFile.name && status === 'PENDING') - ) + this.state.files.every(({ detail }) => detail.name !== selectedFile.name) ).map(detail => ({ - id: Symbol('unique id'), - status: 'PENDING', - detail, + id: Symbol('unique id'), detail, })); const files = [...this.state.files, ...additionalFiles]; @@ -46,34 +40,24 @@ export default class FileUploadService { this.state = { ...this.state, files, size }; } - isUploading() { - return this.state.uploading; - } - - abort() { - this.state.files.forEach(file => file.upload.abort()); - this.state.files = []; - } - - findFileIndex(id) { - return this.state.files.findIndex(file => file.id === id); - } - upload() { const { bucket, folders } = this.$file.paths; const prefix = folders.length ? '' : `${folders.join('/')}/`; const url = `${this.Config.API_URL}/v1/file/create`; - this.state = { - uploading: true, - files: this.state.files.map(file => ({ - ...file, - status: 'UPLOADING', - upload: this.uploadFile(file.id, { - bucket, prefix, file: file.detail, - }, url), - })), - }; + this.state.uploading = true; + this.$transfer.put(this.state.files.map(({ + id, detail, + }) => ({ + id, + bucket, + name: detail.name, + type: 'UPLOAD', + status: 'UPLOADING', + upload: this.uploadFile(id, { + bucket, prefix, file: detail, + }, url), + }))); this.closeDialog(); } @@ -82,47 +66,14 @@ export default class FileUploadService { const upload = this.Upload.upload({ url, data }); upload.then( - res => this.handleSuccess(id, res), - err => this.handleFailure(id, err), - evt => this.handleEvent(id, evt) + res => this.$transfer.handleSuccess(id, res), + err => this.$transfer.handleFailure(id, err), + evt => this.$transfer.handleEvent(id, evt) ); return upload; } - handleEvent(id, evt) { - const i = this.findFileIndex(id); - this.state.files[i].process = evt; - console.log(this.state.files[i].process); - console.log(this.state); - } - - handleSuccess(id, res) { - const i = this.findFileIndex(id); - this.state.files[i].status = 'UPLOADED'; - this.updateUpdateStatus(); - this.$file.getFiles(); - console.log(res); - } - - handleFailure(id, err) { - const i = this.findFileIndex(id); - this.state.files[i].status = 'FAILURE'; - this.updateUpdateStatus(); - console.log(err); - } - - removeUploadFile(id) { - const i = this.findFileIndex(id); - delete this.state.files[i]; - } - - updateUpdateStatus() { - this.state.uploading = this.state.files.every( - file => file.status === 'UPLOADING' - ); - } - createDialog($event) { this.$mdDialog.show({ controller: FileUploadController, @@ -137,5 +88,6 @@ export default class FileUploadService { closeDialog() { this.$mdDialog.cancel(); this.state.size = 0; + this.state.files = []; } } diff --git a/src/components/layout/top-navbar/top-navbar.controller.js b/src/components/layout/top-navbar/top-navbar.controller.js index 742e24a..dd8e829 100644 --- a/src/components/layout/top-navbar/top-navbar.controller.js +++ b/src/components/layout/top-navbar/top-navbar.controller.js @@ -1,8 +1,8 @@ export default class TopNavbarController { /** @ngInject */ - constructor($scope, $translate, $auth, $state, $toast, $mdDialog, $upload, AuthService) { + constructor($scope, $translate, $auth, $state, $toast, $mdDialog, $transfer, AuthService) { Object.assign(this, { - $scope, $translate, $auth, $state, $toast, $mdDialog, $upload, AuthService, + $scope, $translate, $auth, $state, $toast, $mdDialog, $transfer, AuthService, }); this.languages = [ @@ -32,7 +32,7 @@ export default class TopNavbarController { * @return {void} */ signOut($event) { - if (this.$upload.isUploading()) { + if (this.$transfer.isProcessing()) { this.showConfirmMessage($event).then(this.executedSignOut); } else { this.executedSignOut(); @@ -65,7 +65,7 @@ or uploads and leaving now will cancel them.Still leaving?`) */ executedSignOut = () => this.AuthService.signOut() .then(() => { - this.$upload.abort(); + this.$transfer.abort(); this.$auth.logout(); this.$state.go('auth.signin'); this.$toast.show('Sign Out Success!'); diff --git a/src/components/layout/transfer/transfer.controller.js b/src/components/layout/transfer/transfer.controller.js index a3691e5..12b4a1a 100644 --- a/src/components/layout/transfer/transfer.controller.js +++ b/src/components/layout/transfer/transfer.controller.js @@ -1,12 +1,48 @@ export default class TransferController { /** @ngInject */ - constructor($layout) { + constructor($scope, $layout, $transfer) { Object.assign(this, { - $layout, + $layout, $transfer, }); + + $scope.$watch( + () => $transfer.state, + newVal => Object.assign(this, newVal) + , true); + } + + toggleAutoClear() { + this.$transfer.toggleAutoClear(); } close() { this.$layout.toggleTransfer(); } + + md2line(t) { + const status = ['FAILED', 'DELETED', 'PAUSED', 'COMPLETED']; + return status.indexOf(t.status) >= 0; + } + + md3line(t) { + const status = ['UPLOADING', 'RESUMING']; + return status.indexOf(t.status) >= 0; + } + + isUpload(t) { + return t.type === 'UPLOAD'; + } + + isDelete(t) { + return t.type === 'DELETE'; + } + + isUploading(t) { + return t.status === 'UPLOADING'; + } + + showInfo(t) { + const status = ['FAILED', 'PAUSED']; + return status.indexOf(t.status) < 0; + } } diff --git a/src/components/layout/transfer/transfer.html b/src/components/layout/transfer/transfer.html index 0cd3d15..fcc6b48 100644 --- a/src/components/layout/transfer/transfer.html +++ b/src/components/layout/transfer/transfer.html @@ -21,49 +21,51 @@

Automatically clear finished transfers

file_upload delete

-
+

- - + + - - 1.87MB + + / - 2GB + - - + + %

@@ -71,7 +73,7 @@

check_circle -
+
{ + if (transfer.status === 'UPLOADING') { + transfer.upload.abort(); + } + }); + this.state.transfers = []; + } + + remove(id) { + this.state.transfers = this.state.transfers.filter( + (transfer, index) => index !== id + ); + } + + findTransferIndex(id) { + return this.state.transfers.findIndex(transfer => transfer.id === id); + } + + handleEvent(id, { loaded, total }) { + const i = this.findTransferIndex(id); + const precentage = (loaded / total * 100).toFixed(2); + this.state.transfers[i].process = { + loaded, total, precentage, + }; + } + + handleSuccess(id) { + const i = this.findTransferIndex(id); + this.state.transfers[i].status = 'COMPLETED'; + this.$toast.show(`${name} is uploaded successfully!`); + + if (this.state.autoClear) { + this.remove(i); + } + + this.updateProcessStatus(); + this.$file.getFiles(); + } + + handleFailure(id, { statusText }) { + const i = this.findTransferIndex(id); + this.state.transfers[i] = { + ...this.state.transfers[i], + status: 'FAILED', + message: statusText, + }; + this.$toast.show(`${name} is uploaded failure! Error message: ${statusText}`); + this.updateProcessStatus(); + } + + updateProcessStatus() { + this.state.process = this.state.transfers.every( + transfer => transfer.status !== 'UPLOADING' && transfer.status !== 'RESUMING' + ); + } } diff --git a/src/translations/EN.js b/src/translations/EN.js index e0bf219..836bfda 100644 --- a/src/translations/EN.js +++ b/src/translations/EN.js @@ -2,4 +2,16 @@ export default { SETTINGS: { SIGN_OUT: 'Sign Out', }, + TRANSFER: { + TITLE: { + UPLOAD: 'Upload {{ name }} to {{ bucket }}', + DELETE: 'Delete {{ name }} from {{ bucket }}', + }, + STATUS: { + UPLOADING: 'Uploading', + COMPLETED: 'Completed', + DELETE: 'Deleted', + RESUMING: 'Resuming', + }, + }, }; From f5df9e0e1d41e34607f150530af2626f6ce3243c Mon Sep 17 00:00:00 2001 From: jigsawye Date: Thu, 19 May 2016 15:09:13 +0800 Subject: [PATCH 44/58] Fix bugs of toast message --- src/components/layout/transfer/transfer.service.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/layout/transfer/transfer.service.js b/src/components/layout/transfer/transfer.service.js index 01b6eec..c13a977 100644 --- a/src/components/layout/transfer/transfer.service.js +++ b/src/components/layout/transfer/transfer.service.js @@ -61,7 +61,7 @@ export default class TransferService { handleSuccess(id) { const i = this.findTransferIndex(id); this.state.transfers[i].status = 'COMPLETED'; - this.$toast.show(`${name} is uploaded successfully!`); + this.$toast.show(`${this.state.transfers[i].name} is uploaded successfully!`); if (this.state.autoClear) { this.remove(i); @@ -78,7 +78,9 @@ export default class TransferService { status: 'FAILED', message: statusText, }; - this.$toast.show(`${name} is uploaded failure! Error message: ${statusText}`); + this.$toast.show( + `${this.state.transfers[i].name} is uploaded failure! Error message: ${statusText}` + ); this.updateProcessStatus(); } From e6b383d3dc61e19532fe845dd4bb40e3ae901f04 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Thu, 19 May 2016 15:11:42 +0800 Subject: [PATCH 45/58] Add $file dependence to $transfer --- src/components/layout/transfer/transfer.service.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/layout/transfer/transfer.service.js b/src/components/layout/transfer/transfer.service.js index c13a977..a8128ae 100644 --- a/src/components/layout/transfer/transfer.service.js +++ b/src/components/layout/transfer/transfer.service.js @@ -1,8 +1,8 @@ export default class TransferService { /** @ngInject */ - constructor($toast) { + constructor($toast, $file) { Object.assign(this, { - $toast, + $toast, $file, }); this.initState(); } From 891ea2dbc15d0ceb0f2b1dca2d80bf1179297fc8 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Thu, 19 May 2016 16:06:59 +0800 Subject: [PATCH 46/58] Update transfers & properties button of action navbar Implement the `none`, `properties`, `transfers` button. * Add `properties` to layout state * Add `openTransfers`, `openProperties` and `closeSidePanels` methods --- .../action-navbar/action-navbar.controller.js | 17 ++++++++----- .../layout/action-navbar/action-navbar.html | 7 +++--- src/components/layout/layout.html | 2 +- src/components/layout/layout.service.js | 24 ++++++++++++++++--- .../layout/transfer/transfer.controller.js | 2 +- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/components/layout/action-navbar/action-navbar.controller.js b/src/components/layout/action-navbar/action-navbar.controller.js index 4b6940e..eea25e3 100644 --- a/src/components/layout/action-navbar/action-navbar.controller.js +++ b/src/components/layout/action-navbar/action-navbar.controller.js @@ -9,6 +9,11 @@ export default class ActionNavbarController { () => $nav.type, newVal => (this.type = newVal) ); + + this.$scope.$watch( + () => $layout.state, + newVal => Object.assign(this, newVal) + ); } /** @@ -36,16 +41,16 @@ export default class ActionNavbarController { // } - none() { - // + closeSidePanels() { + this.$layout.closeSidePanels(); } - properties() { - // + openProperties() { + this.$layout.openProperties(); } - toggleTransfer() { - this.$layout.toggleTransfer(); + openTransfers() { + this.$layout.openTransfers(); } /** diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 0c4bb48..f1d7898 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -107,14 +107,15 @@ None info_outline Properties @@ -122,7 +123,7 @@ Transfers diff --git a/src/components/layout/layout.html b/src/components/layout/layout.html index 7e99a0f..ca51d50 100644 --- a/src/components/layout/layout.html +++ b/src/components/layout/layout.html @@ -11,7 +11,7 @@

diff --git a/src/components/layout/layout.service.js b/src/components/layout/layout.service.js index 9115abb..7e43a64 100644 --- a/src/components/layout/layout.service.js +++ b/src/components/layout/layout.service.js @@ -5,11 +5,29 @@ export default class LayoutService { initState() { this.state = { - transfer: false, + transfers: false, + properties: false, }; } - toggleTransfer() { - this.state.transfer = ! this.state.transfer; + openProperties() { + this.state = { + transfers: false, + properties: true, + }; + } + + openTransfers() { + this.state = { + transfers: true, + properties: false, + }; + } + + closeSidePanels() { + this.state = { + transfers: false, + properties: false, + }; } } diff --git a/src/components/layout/transfer/transfer.controller.js b/src/components/layout/transfer/transfer.controller.js index 12b4a1a..78b2590 100644 --- a/src/components/layout/transfer/transfer.controller.js +++ b/src/components/layout/transfer/transfer.controller.js @@ -16,7 +16,7 @@ export default class TransferController { } close() { - this.$layout.toggleTransfer(); + this.$layout.closeSidePanels(); } md2line(t) { From 3b7d1e4de963b930096559132e24412ed4b9ca4e Mon Sep 17 00:00:00 2001 From: jigsawye Date: Thu, 19 May 2016 16:20:22 +0800 Subject: [PATCH 47/58] Update properties event in actions button of action navbar --- src/components/layout/action-navbar/action-navbar.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index f1d7898..264008d 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -95,7 +95,7 @@ Properties From f9114a350af593aca580cc00f5dfdd8fce5f1977 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Fri, 20 May 2016 12:07:42 +0800 Subject: [PATCH 48/58] Fix bug when file size small than 1024 bytes --- src/filters/filesize.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/filters/filesize.js b/src/filters/filesize.js index b95cf6c..070dfe9 100644 --- a/src/filters/filesize.js +++ b/src/filters/filesize.js @@ -24,5 +24,7 @@ export default () => bytes => { unit ++; } - return `${bytes.toFixed(2)} ${units[unit]}`; + const result = (unit === 0) ? +bytes : bytes.toFixed(2); + + return `${result} ${units[unit]}`; }; From e0c66b0d7d9e245978c295a8fa6b38a7eb369731 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Fri, 20 May 2016 12:37:29 +0800 Subject: [PATCH 49/58] Fix file icon in upload.html --- src/components/file/upload/upload.html | 4 ++-- src/components/file/upload/upload.servce.js | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/file/upload/upload.html b/src/components/file/upload/upload.html index 3ed64e6..5b60208 100644 --- a/src/components/file/upload/upload.html +++ b/src/components/file/upload/upload.html @@ -41,8 +41,8 @@

Upload Files

- photo - insert_drive_file + photo + insert_drive_file

diff --git a/src/components/file/upload/upload.servce.js b/src/components/file/upload/upload.servce.js index 15ef8a6..f4e6ace 100644 --- a/src/components/file/upload/upload.servce.js +++ b/src/components/file/upload/upload.servce.js @@ -28,16 +28,16 @@ export default class FileUploadService { })); const files = [...this.state.files, ...additionalFiles]; - const size = totalSize(files); - this.state = { ...this.state, files, size }; + + this.state = { files, size }; } delete(id) { const files = this.state.files.filter(file => file.id !== id); const size = totalSize(files); - this.state = { ...this.state, files, size }; + this.state = { files, size }; } upload() { @@ -87,7 +87,6 @@ export default class FileUploadService { closeDialog() { this.$mdDialog.cancel(); - this.state.size = 0; - this.state.files = []; + this.initState(); } } From 9d9f9bb68f582272788bc199bf4fbbf5833a4beb Mon Sep 17 00:00:00 2001 From: jigsawye Date: Fri, 20 May 2016 13:19:49 +0800 Subject: [PATCH 50/58] Fix bug when action navbar switch --- .../action-navbar/action-navbar.controller.js | 10 ++++----- .../layout/action-navbar/action-navbar.html | 21 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/components/layout/action-navbar/action-navbar.controller.js b/src/components/layout/action-navbar/action-navbar.controller.js index eea25e3..a2e41c1 100644 --- a/src/components/layout/action-navbar/action-navbar.controller.js +++ b/src/components/layout/action-navbar/action-navbar.controller.js @@ -33,10 +33,6 @@ export default class ActionNavbarController { // } - upload($event) { - this.$upload.createDialog($event); - } - delete() { // } @@ -61,12 +57,16 @@ export default class ActionNavbarController { */ create($event) { if (this.isFile()) { - // + this.$upload.createDialog($event); } else { this.$bucket.createDialog($event); } } + createFolder($event) { + // handle the create folder event + } + /** * Refresh the list by `this.type` * diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 264008d..4dd90f7 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -2,22 +2,21 @@
- file_upload - Upload + add + file_upload + Create Bucket + Upload - add - create_new_folder - Create Bucket - Create Folder + create_new_folder + Create Folder From 14d0269a4dff9f0979a11f58e72480e1dc7ed8b6 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Mon, 23 May 2016 15:30:38 +0800 Subject: [PATCH 51/58] Fix menu items of actions button --- .../layout/action-navbar/action-navbar.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 4dd90f7..7455063 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -49,22 +49,22 @@ - + - Upload + Create Bucket + Upload - + - Create Bucket - Create Folder + Create Folder From d8a99317f8835e44e71e7680f782c451dc07bb31 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Fri, 20 May 2016 13:19:49 +0800 Subject: [PATCH 52/58] Fix bug when action navbar switch --- .../action-navbar/action-navbar.controller.js | 10 ++++----- .../layout/action-navbar/action-navbar.html | 21 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/components/layout/action-navbar/action-navbar.controller.js b/src/components/layout/action-navbar/action-navbar.controller.js index 62cbdf2..22b65c0 100644 --- a/src/components/layout/action-navbar/action-navbar.controller.js +++ b/src/components/layout/action-navbar/action-navbar.controller.js @@ -28,10 +28,6 @@ export default class ActionNavbarController { // } - upload($event) { - this.$upload.createDialog($event); - } - delete() { // } @@ -56,12 +52,16 @@ export default class ActionNavbarController { */ create($event) { if (this.isFile()) { - // + this.$upload.createDialog($event); } else { this.$bucket.createDialog($event); } } + createFolder($event) { + // handle the create folder event + } + /** * Refresh the list by `this.type` * diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 2e57048..436f260 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -2,22 +2,21 @@
- file_upload - Upload + add + file_upload + Create Bucket + Upload - add - create_new_folder - Create Bucket - Create Folder + create_new_folder + Create Folder From 854f75171ba462633ca2be1f62d6585e8d4cbf36 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Mon, 23 May 2016 17:13:07 +0800 Subject: [PATCH 53/58] Revert "Fix bug when action navbar switch" This reverts commit 9d9f9bb68f582272788bc199bf4fbbf5833a4beb. --- .../action-navbar/action-navbar.controller.js | 10 ++++----- .../layout/action-navbar/action-navbar.html | 21 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/components/layout/action-navbar/action-navbar.controller.js b/src/components/layout/action-navbar/action-navbar.controller.js index a2e41c1..eea25e3 100644 --- a/src/components/layout/action-navbar/action-navbar.controller.js +++ b/src/components/layout/action-navbar/action-navbar.controller.js @@ -33,6 +33,10 @@ export default class ActionNavbarController { // } + upload($event) { + this.$upload.createDialog($event); + } + delete() { // } @@ -57,16 +61,12 @@ export default class ActionNavbarController { */ create($event) { if (this.isFile()) { - this.$upload.createDialog($event); + // } else { this.$bucket.createDialog($event); } } - createFolder($event) { - // handle the create folder event - } - /** * Refresh the list by `this.type` * diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 7455063..f988e39 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -2,21 +2,22 @@
- add - file_upload - Create Bucket - Upload + file_upload + Upload - create_new_folder - Create Folder + add + create_new_folder + Create Bucket + Create Folder From c9c7b006c8398a31459716f03a091d64f1436931 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Mon, 23 May 2016 15:30:38 +0800 Subject: [PATCH 54/58] Fix menu items of actions button --- .../layout/action-navbar/action-navbar.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 436f260..1849982 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -49,22 +49,22 @@ - + - Upload + Create Bucket + Upload - + - Create Bucket - Create Folder + Create Folder From aa3b91639ca67eb128f45676f5daf407c61ca619 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Mon, 23 May 2016 17:27:53 +0800 Subject: [PATCH 55/58] Revert "Fix menu items of actions button" This reverts commit 14d0269a4dff9f0979a11f58e72480e1dc7ed8b6. --- .../layout/action-navbar/action-navbar.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/layout/action-navbar/action-navbar.html b/src/components/layout/action-navbar/action-navbar.html index 7455063..4dd90f7 100644 --- a/src/components/layout/action-navbar/action-navbar.html +++ b/src/components/layout/action-navbar/action-navbar.html @@ -49,22 +49,22 @@ - + - Create Bucket - Upload + Upload - + - Create Folder + Create Bucket + Create Folder From 58a77488a7eac72b1d3eabd95f5f96877441c432 Mon Sep 17 00:00:00 2001 From: jigsawye Date: Tue, 24 May 2016 16:48:46 +0800 Subject: [PATCH 56/58] Fix issue display upload completed icon --- src/components/layout/transfer/transfer.controller.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/layout/transfer/transfer.controller.js b/src/components/layout/transfer/transfer.controller.js index 78b2590..f6be220 100644 --- a/src/components/layout/transfer/transfer.controller.js +++ b/src/components/layout/transfer/transfer.controller.js @@ -41,6 +41,10 @@ export default class TransferController { return t.status === 'UPLOADING'; } + isCompleted(t) { + return t.status === 'COMPLETED'; + } + showInfo(t) { const status = ['FAILED', 'PAUSED']; return status.indexOf(t.status) < 0; From d1d3b78bd24a493dd610ac38adaf16dd929814a6 Mon Sep 17 00:00:00 2001 From: chaoen Date: Tue, 24 May 2016 12:26:29 +0000 Subject: [PATCH 57/58] Add unit test for upload component Add test that testing method in file controller. Done upload controller unit test. Add when init service, select and delete method in service unit test. --- src/components/file/file.spec.js | 213 +++++++++++++++++++ src/components/file/upload/upload.spec.js | 244 ++++++++++++++++++++++ 2 files changed, 457 insertions(+) create mode 100644 src/components/file/file.spec.js create mode 100644 src/components/file/upload/upload.spec.js diff --git a/src/components/file/file.spec.js b/src/components/file/file.spec.js new file mode 100644 index 0000000..0d0d51f --- /dev/null +++ b/src/components/file/file.spec.js @@ -0,0 +1,213 @@ +import app from './../../index.js'; +import fileCtrl from './file.controller'; +import fileService from './file.service'; +import bucketService from '../bucket/bucket.service'; +import uploadService from './upload/upload.servce'; + +describe('File Unit Test', function() { + let $rootScope; + let makeService; + let BucService; + let makeUpService; + let makeDeferred; + let makeController; + let $fetch; + let $toast; + let $mdDialog; + let $breadcrumb; + let Upload; + let Config = { API_URL: '0.0.0.0:0000' }; + let $stateParams = { + path: 'BucketName/FolderA/FolderB' + }; + + beforeEach(angular.mock.module('app')); + + beforeEach(inject(($q, _Upload_, _$rootScope_, _$mdDialog_, _$toast_, _$breadcrumb_, _$fetch_) => { + $rootScope = _$rootScope_; + + $toast = _$toast_; + + $fetch = _$fetch_; + + $mdDialog = _$mdDialog_; + + Upload = _Upload_; + + $breadcrumb = _$breadcrumb_; + + makeService = () => { + return new fileService($mdDialog, $fetch, BucService); + }; + + makeUpService = (service) => { + return new uploadService(Config, Upload, $mdDialog, service, $toast); + }; + + makeDeferred = () => { + return $q.defer(); + }; + + BucService = new bucketService($fetch, $toast, $mdDialog, $breadcrumb); + + + makeController = (service, upService) => { + return new fileCtrl($rootScope, $stateParams, service, BucService, $breadcrumb, upService); + }; + })); + describe('when init service', function() { + let service; + + beforeEach(function() { + service = makeService(); + }); + + it('should declare paths', function() { + expect(service.state.paths.bucket).to.eq(''); + expect(service.state.paths.folders).to.be.empty; + }); + it('should declare lists', function() { + expect(service.state.lists.data).to.be.empty; + expect(service.state.lists.requesting).to.eq(false); + expect(service.state.lists.error).to.eq(false); + }); + }); + + describe('when setPaths in service', function() { + let service; + + beforeEach(function() { + service = makeService(); + service.setPaths('BucketName', ["FolderA", "FolderB"]); + }); + it('should put value to service.paths', function() { + expect(service.paths).to.have.property('bucket', 'BucketName'); + expect(service.paths.folders).to.have.property([0], 'FolderA'); + expect(service.paths.folders).to.have.property([1], 'FolderB'); + }); + }); + + describe('when getFiles in service and response success', function() { + let service; + let testMock; + let fetchMock; + let deferred; + let res; + beforeEach(function() { + service = makeService(); + deferred = makeDeferred(); + fetchMock = sinon.mock(service.$fetch); + fetchMock.expects('get').returns(deferred.promise); + res = { + "files": [ + { + "name": "fileName", + "Size": "323844" + } + ] + } + service.paths = { bucket: 'BucketName', folders: ['FolderA', 'FolderB']}; + deferred.resolve({ data:res }); + service.getFiles(); + $rootScope.$digest(); + }); + it('should requesting to be false', function() { + expect(service.state.lists.requesting).to.eq(false); + }); + it('should let data have files information', function() { + expect(service.state.lists.data).to.have.deep.property('[0].name', "fileName"); + expect(service.state.lists.data).to.have.deep.property('[0].Size', "323844") + }); + it('should let error to be false', function() { + expect(service.state.lists.error).to.eq(false); + }) + }); + + describe('when getFiles in service and response fail', function() { + let service; + let testMock; + let fetchMock; + let deferred; + beforeEach(function() { + service = makeService(); + deferred = makeDeferred(); + fetchMock = sinon.mock(service.$fetch); + fetchMock.expects('get').returns(deferred.promise); + service.paths = { bucket: 'BucketName', folders: ['FolderA', 'FolderB']}; + deferred.reject(); + service.getFiles(); + $rootScope.$digest(); + }); + it('should requesting to be false', function() { + expect(service.state.lists.requesting).to.eq(false); + }); + it('should let error to be true', function() { + expect(service.state.lists.error).to.eq(true); + }) + }); + + describe('when init controller', function() { + let service; + let controller; + let mockSetPaths; + let mockGetFiles; + let mockUpdateFP; + let mockGetBucket; + beforeEach(function() { + service = makeService(); + service.getFiles = () => {}; + mockSetPaths = sinon.spy(service, 'setPaths'); + mockUpdateFP = sinon.spy($breadcrumb, 'updateFilePath'); + mockGetBucket = sinon.spy(BucService, 'getBuckets') + mockGetFiles = sinon.spy(service, 'getFiles'); + controller = makeController(service); + }); + it('should invoke setPaths in fileService and call by PATH', function() { + expect(mockSetPaths).to.have.been.calledWith('BucketName', ["FolderA", "FolderB"]); + }); + it('should invoke $breadcrumb.updateFilePath by folders', function() { + expect(mockUpdateFP).to.have.been.calledWith($stateParams.path.split('/')); + }); + it('should invoke getbuckets in bucketService', function() { + expect(mockGetBucket.called).to.eq(true); + }); + it('should invoke getFiles in fileService', function() { + expect(mockGetFiles.called).to.eq(true) + }); + }); + describe('when refresh in controller', function() { + let service; + let controller; + let mockGetFiles; + let upService; + beforeEach(function() { + service = makeService(); + service.getFiles = () => {}; + upService = makeUpService(service); + controller = makeController(service); + mockGetFiles = sinon.spy(service, 'getFiles'); + }); + it('should invoke getFiles in service', function() { + expect(mockGetFiles.called).to.eq(false); + controller.refresh(); + expect(mockGetFiles.called).to.eq(true); + }); + }); + describe('when upload in controller', function() { + let service; + let controller; + let mockCreateDialog; + let upService; + beforeEach(function() { + service = makeService(); + upService = makeUpService(service); + controller = makeController(service, upService); + mockCreateDialog = sinon.spy(upService, 'createDialog'); + }); + it('should invoke createDialog in service', function() { + expect(mockCreateDialog.called).to.eq(false); + controller.upload(); + expect(mockCreateDialog.called).to.eq(true); + }); + }); +}); \ No newline at end of file diff --git a/src/components/file/upload/upload.spec.js b/src/components/file/upload/upload.spec.js new file mode 100644 index 0000000..c9aed27 --- /dev/null +++ b/src/components/file/upload/upload.spec.js @@ -0,0 +1,244 @@ +import app from '../../../index.js'; +import upCtrl from './upload.controller'; +import fileService from '../file.service'; +import uploadService from './upload.servce'; +import totalSize from '../../../utils/totalSize' + +describe('Upload Unit Test', function() { + let $rootScope; + let makeFileService; + let BucService; + let makeUpService; + let makeDeferred; + let makeController; + let $fetch; + let $toast; + let $mdDialog; + let $breadcrumb; + let Upload; + let Config = { API_URL: '0.0.0.0:0000' }; + let $stateParams = { + path: 'BucketName/FolderA/FolderB' + }; + + beforeEach(angular.mock.module('app')); + + beforeEach(inject(($q, _Upload_, _$rootScope_, _$mdDialog_, _$toast_, _$breadcrumb_, _$fetch_) => { + $rootScope = _$rootScope_; + + $fetch = _$fetch_; + + $toast = _$toast_; + + $mdDialog = _$mdDialog_; + + Upload = _Upload_; + + BucService = {}; + + makeFileService = () => { + return new fileService($mdDialog, $fetch, BucService); + }; + + makeUpService = (service) => { + return new uploadService(Config, Upload, $mdDialog, service, $toast); + }; + + makeDeferred = () => { + return $q.defer(); + }; + + makeController = (fileService, upService) => { + return new upCtrl(fileService, upService, $rootScope); + }; + })); + describe('when upload in controller', function() { + let service; + let controller; + let mockUpload; + beforeEach(function() { + service = makeUpService(makeFileService()); + controller = makeController(makeFileService(), service); + service.upload = () => {}; + mockUpload = sinon.spy(service, 'upload'); + }); + + it('should invoke upload in service', function() { + expect(mockUpload.called).to.eq(false); + controller.upload(); + expect(mockUpload.called).to.eq(true); + }); + }); + describe('when select in controller', function() { + let service; + let controller; + let mockSelect; + beforeEach(function() { + service = makeUpService(makeFileService()); + controller = makeController(makeFileService(), service); + service.select = () => {}; + mockSelect = sinon.spy(service, 'select'); + }); + + it('should invoke upload in service', function() { + expect(mockSelect.called).to.eq(false); + controller.select(123); + expect(mockSelect).to.have.been.calledWith(123); + }); + }); + describe('when delete in controller', function() { + let service; + let controller; + let mockDelete; + beforeEach(function() { + service = makeUpService(makeFileService()); + controller = makeController(makeFileService(), service); + service.delete = () => {}; + mockDelete = sinon.spy(service, 'delete'); + }); + + it('should invoke upload in service', function() { + expect(mockDelete.called).to.eq(false); + controller.delete(321); + expect(mockDelete).to.have.been.calledWith(321); + }); + }); + describe('when cancel in controller', function() { + let service; + let controller; + let mockCloseDialog; + beforeEach(function() { + service = makeUpService(makeFileService()); + controller = makeController(makeFileService(), service); + service.closeDialog = () => {}; + mockCloseDialog = sinon.spy(service, 'closeDialog'); + }); + + it('should invoke upload in service', function() { + expect(mockCloseDialog.called).to.eq(false); + controller.cancel(); + expect(mockCloseDialog.called).to.eq(true); + }); + }); + describe('when init service', function() { + let service; + beforeEach(function() { + service = makeUpService(makeFileService()); + }); + it('should declare service.state.files', function() { + expect(service.state.files).to.be.empty; + }); + it('should declare service.state.size', function() { + expect(service.state.size).to.eq(0); + }); + }); + describe('when select non-repeat files in service', function() { + let service; + let mockTotal; + let file = [ + { + 'name': 'fileName', + 'size': 555 + }, + { + 'name': 'fileName2', + 'size': 5858 + } + ] + beforeEach(function() { + service = makeUpService(makeFileService()); + service.select(file); + $rootScope.$digest(); + }); + it('should declare service.state.files', function() { + expect(service.state.files[0].id).to.be.a('symbol'); + expect(service.state.files[0].detail).to.have.property('name', 'fileName'); + expect(service.state.files[0].detail).to.have.property('size', 555); + expect(service.state.files[1].id).to.be.a('symbol'); + expect(service.state.files[1].detail).to.have.property('name', 'fileName2'); + expect(service.state.files[1].detail).to.have.property('size', 5858); + }); + it('should total size', function() { + expect(service.state.size).to.eq(file.reduce((p, c) => p+c.size,0)); + }); + }); + describe('when select same name files', function() { + let service; + let mockTotal; + let file = [ + { + 'name': 'fileName', + 'size': 555 + }, + { + 'name': 'fileName2', + 'size': 5858 + } + ] + beforeEach(function() { + service = makeUpService(makeFileService()); + service.state.files = [ { + id: Symbol('unique id'), + detail: { + name: 'fileName2', + size: 808 + } + }]; + service.select(file); + $rootScope.$digest(); + }); + it('should not insert repeat files', function() { + expect(service.state.files[0].id).to.be.a('symbol'); + expect(service.state.files[0].detail).to.have.property('name', 'fileName2'); + expect(service.state.files[0].detail).to.have.property('size', 808); + expect(service.state.files[1].id).to.be.a('symbol'); + expect(service.state.files[1].detail).to.have.property('name', 'fileName'); + expect(service.state.files[1].detail).to.have.property('size', 555); + }); + it('should total size', function() { + expect(service.state.size).to.eq(service.state.files.reduce((p, c) => p+c.detail.size,0)); + }); + }); + describe('when delete in service', function() { + let service; + let mockTotal; + let file = [ + { + id: Symbol('unique id'), + detail: { + name: 'fileName1', + size: 8585 + } + }, + { + id: Symbol('unique id'), + detail: { + name: 'fileName2', + size: 808 + } + } + ]; + beforeEach(function() { + service = makeUpService(makeFileService()); + service.state.files = file; + }); + it('should delete files', function() { + expect(service.state.files[0].id).to.be.a('symbol'); + expect(service.state.files[0].detail).to.have.property('name', 'fileName1'); + expect(service.state.files[0].detail).to.have.property('size', 8585); + expect(service.state.files[1].id).to.be.a('symbol'); + expect(service.state.files[1].detail).to.have.property('name', 'fileName2'); + expect(service.state.files[1].detail).to.have.property('size', 808); + service.delete(service.state.files[0].id); + expect(service.state.files[0].id).to.be.a('symbol'); + expect(service.state.files[0].detail).to.have.property('name', 'fileName2'); + expect(service.state.files[0].detail).to.have.property('size', 808); + }); + it('should total size', function() { + service.delete(service.state.files[0].id); + expect(service.state.size).to.eq(service.state.files.reduce((p, c) => p+c.detail.size,0)); + // console.log(service.state.size); + // console.log(service.state.files.reduce((p, c) => p+c.detail.size,0)) + }); + }); +}); \ No newline at end of file From 5251cfd1ebaa75c37141dc5134d4053389c76f0d Mon Sep 17 00:00:00 2001 From: chaoen Date: Tue, 24 May 2016 14:32:48 +0000 Subject: [PATCH 58/58] Add Testing method upload, createDialog, closeDialog in uploadService. --- src/components/file/upload/upload.spec.js | 112 +++++++++++++++++++++- 1 file changed, 107 insertions(+), 5 deletions(-) diff --git a/src/components/file/upload/upload.spec.js b/src/components/file/upload/upload.spec.js index c9aed27..c89e3ff 100644 --- a/src/components/file/upload/upload.spec.js +++ b/src/components/file/upload/upload.spec.js @@ -2,13 +2,14 @@ import app from '../../../index.js'; import upCtrl from './upload.controller'; import fileService from '../file.service'; import uploadService from './upload.servce'; -import totalSize from '../../../utils/totalSize' +import transService from '../../layout/transfer/transfer.service'; describe('Upload Unit Test', function() { let $rootScope; let makeFileService; let BucService; let makeUpService; + let makeTransService; let makeDeferred; let makeController; let $fetch; @@ -40,8 +41,8 @@ describe('Upload Unit Test', function() { return new fileService($mdDialog, $fetch, BucService); }; - makeUpService = (service) => { - return new uploadService(Config, Upload, $mdDialog, service, $toast); + makeUpService = (fileService, transService) => { + return new uploadService(Config, Upload, $mdDialog, fileService, transService); }; makeDeferred = () => { @@ -51,6 +52,10 @@ describe('Upload Unit Test', function() { makeController = (fileService, upService) => { return new upCtrl(fileService, upService, $rootScope); }; + + makeTransService = (fileService) => { + return new transService($toast, fileService); + }; })); describe('when upload in controller', function() { let service; @@ -237,8 +242,105 @@ describe('Upload Unit Test', function() { it('should total size', function() { service.delete(service.state.files[0].id); expect(service.state.size).to.eq(service.state.files.reduce((p, c) => p+c.detail.size,0)); - // console.log(service.state.size); - // console.log(service.state.files.reduce((p, c) => p+c.detail.size,0)) + }); + }); + describe('when upload in service', function() { + let service; + let fileService; + let transService; + let mockPut; + let mockCloseDialog; + let mockUploadFile; + beforeEach(function() { + fileService = makeFileService(); + transService = makeTransService(fileService); + fileService.paths = { bucket: 'BucketName', folders: ['FolderA', 'FolderB']}; + service = makeUpService(fileService, transService); + service.state.files = [ + { + id: Symbol('unique id'), + detail: { + name: 'FileName', + size: 888 + } + } + ]; + service.uploadFile = () => { return 'aPromise' }; + service.closeDialog = () => {}; + mockCloseDialog = sinon.spy(service, 'closeDialog'); + mockUploadFile = sinon.spy(service, 'uploadFile'); + mockPut = sinon.spy(transService, 'put'); + service.upload(); + $rootScope.$digest(); + }); + it('should let uploading to be true', function() { + expect(service.state.uploading).to.eq(true); + }); + it('should invoke $transfer.put and call by right way', function() { + const { bucket, folders } = fileService.paths; + const called = [{ + id: service.state.files[0].id, + bucket: bucket, + name: service.state.files[0].detail.name, + type: 'UPLOAD', + status: 'UPLOADING', + upload: 'aPromise' + }]; + expect(mockPut).to.have.been.calledWith(called); + }); + it('should invoke uploadFile and call by id, data and url', function() { + const { bucket, folders } = fileService.paths; + const prefix = folders.length ? '' : `${folders.join('/')}/`; + const called = { + id: service.state.files[0].id, + data: { + bucket: bucket, + prefix: prefix, + file: service.state.files[0].detail + }, + url:`${Config.API_URL}/v1/file/create` + } + expect(mockUploadFile).to.have.been.calledWith(called.id, called.data, called.url); + }); + it('should invoke closeDialog', function() { + expect(mockCloseDialog.called).to.eq(true); + }); + }); + describe('when createDialog in service', function() { + let service; + let fileService; + let transService; + let mockCreateDialog; + beforeEach(function() { + fileService = makeFileService(); + transService = makeTransService(fileService); + service = makeUpService(fileService, transService); + mockCreateDialog = sinon.spy($mdDialog, 'show'); + service.createDialog(); + }); + it('should invoke mdDialog.show', function() { + expect(mockCreateDialog.called).to.eq(true); + }); + }); + describe('when closeDialog in service', function() { + let service; + let fileService; + let transService; + let mockCancelDialog; + let mockInitState; + beforeEach(function() { + fileService = makeFileService(); + transService = makeTransService(fileService); + service = makeUpService(fileService, transService); + mockInitState = sinon.spy(service, 'initState'); + mockCancelDialog = sinon.spy($mdDialog, 'cancel'); + service.closeDialog(); + }); + it('should invoke mdDialog.cancel', function() { + expect(mockCancelDialog.called).to.eq(true); + }); + it('should invoke initState in service', function() { + expect(mockInitState.called).to.eq(true); }); }); }); \ No newline at end of file