diff --git a/app/assets/javascripts/app/controllers/footer.js b/app/assets/javascripts/app/controllers/footer.js index 4da3b6ba1..74f1d7c12 100644 --- a/app/assets/javascripts/app/controllers/footer.js +++ b/app/assets/javascripts/app/controllers/footer.js @@ -23,7 +23,26 @@ angular.module('app') } }) .controller('FooterCtrl', function ($rootScope, authManager, modelManager, $timeout, dbManager, - syncManager, storageManager, passcodeManager, componentManager, singletonManager) { + syncManager, storageManager, passcodeManager, componentManager, singletonManager, nativeExtManager) { + + $rootScope.$on("reload-ext-data", () => { + if(this.reloadInProgress) { return; } + this.reloadInProgress = true; + + // A reload occurs when the extensions manager window is opened. We can close it after a delay + let extWindow = this.rooms.find((room) => {return room.package_info.identifier == nativeExtManager.extensionsManagerIdentifier}); + if(!extWindow) { + return; + } + + this.selectRoom(extWindow); + + $timeout(() => { + this.selectRoom(extWindow); + this.reloadInProgress = false; + $rootScope.$broadcast("ext-reload-complete"); + }, 2000) + }); this.getUser = function() { return authManager.user; @@ -151,4 +170,6 @@ angular.module('app') this.selectRoom = function(room) { room.showRoom = !room.showRoom; } + + }); diff --git a/app/assets/javascripts/app/directives/views/componentView.js b/app/assets/javascripts/app/directives/views/componentView.js index 445b9b9ee..dc383043f 100644 --- a/app/assets/javascripts/app/directives/views/componentView.js +++ b/app/assets/javascripts/app/directives/views/componentView.js @@ -1,6 +1,6 @@ class ComponentView { - constructor(componentManager, desktopManager, $timeout) { + constructor($rootScope, componentManager, desktopManager, $timeout) { this.restrict = "E"; this.templateUrl = "directives/component-view.html"; this.scope = { @@ -8,6 +8,7 @@ class ComponentView { manualDealloc: "=" }; + this.$rootScope = $rootScope; this.componentManager = componentManager; this.desktopManager = desktopManager; this.timeout = $timeout; @@ -49,7 +50,7 @@ class ComponentView { }); } - controller($scope, $timeout, componentManager, desktopManager) { + controller($scope, $rootScope, $timeout, componentManager, desktopManager) { 'ngInject'; this.componentValueChanging = (component, prevComponent) => { @@ -66,6 +67,10 @@ class ComponentView { } } + $scope.$on("ext-reload-complete", () => { + $scope.reloadStatus(); + }) + $scope.reloadComponent = function() { console.log("Reloading component", $scope.component); componentManager.reloadComponent($scope.component); @@ -100,6 +105,12 @@ class ComponentView { } } + if(expired && !$scope.triedReloading) { + // Try reloading, handled by footer, which will open Extensions window momentarily to pull in latest data + $scope.triedReloading = true; + $rootScope.$broadcast("reload-ext-data"); + } + $timeout(() => { $scope.reloading = false; }, 500) @@ -124,4 +135,4 @@ class ComponentView { } -angular.module('app').directive('componentView', (componentManager, desktopManager, $timeout) => new ComponentView(componentManager, desktopManager, $timeout)); +angular.module('app').directive('componentView', ($rootScope, componentManager, desktopManager, $timeout) => new ComponentView($rootScope, componentManager, desktopManager, $timeout)); diff --git a/app/assets/stylesheets/app/_editor.scss b/app/assets/stylesheets/app/_editor.scss index 5eecad5b0..0f720e9fb 100644 --- a/app/assets/stylesheets/app/_editor.scss +++ b/app/assets/stylesheets/app/_editor.scss @@ -72,6 +72,8 @@ $heading-height: 75px; #note-tags-component-container { height: 50px; + overflow: scroll; // Required for expired sub to not overflow + iframe { height: 50px; width: 100%; diff --git a/app/assets/templates/directives/component-view.html.haml b/app/assets/templates/directives/component-view.html.haml index 6eab98611..44bafb048 100644 --- a/app/assets/templates/directives/component-view.html.haml +++ b/app/assets/templates/directives/component-view.html.haml @@ -7,8 +7,19 @@ %p Please visit %a{"href" => "https://dashboard.standardnotes.org", "target" => "_blank"} dashboard.standardnotes.org - to renew your subscription, then open the "Extensions" menu via the bottom menu of the app to refresh your account data. - Afterwards, press the button below to attempt to reload this component. + to renew your subscription. + .panel-row + .panel-column + %p + %strong To reload your account status: + %p + %ol + %li + Open the + %strong Extensions + menu located in the lower left corner of the app to refresh your account status. + %li Click Reload below. + .panel-row .button.info{"ng-if" => "!reloading", "ng-click" => "reloadStatus()"} .label Reload diff --git a/app/assets/templates/frontend/directives/account-menu.html.haml b/app/assets/templates/frontend/directives/account-menu.html.haml deleted file mode 100644 index 1537cbda5..000000000 --- a/app/assets/templates/frontend/directives/account-menu.html.haml +++ /dev/null @@ -1,165 +0,0 @@ -.panel.panel-default.panel-right.account-data-menu - .panel-body.large-padding - %div{"ng-if" => "!user"} - - -# Account Section - .mb-10 - - .step-one{"ng-if" => "!formData.showLogin && !formData.showRegister"} - %h3 Sign in or register to enable sync and end-to-end encryption. - .small-v-space - - .button-group.mt-5 - %button.ui-button.half-button{"ng-click" => "formData.showLogin = true"} - %span Sign In - %button.ui-button.half-button{"ng-click" => "formData.showRegister = true"} - %span Register - - .step-two{"ng-if" => "formData.showLogin || formData.showRegister"} - .float-group.h20 - %h3.pull-left {{formData.showLogin ? "Sign In" : "Register (free)"}} - %a.pull-right.pt-5{"ng-click" => "formData.showLogin = false; formData.showRegister = false;"} Cancel - - %form.mt-5 - %input.form-control.mt-10{:autofocus => 'autofocus', :name => 'email', :placeholder => 'Email', :required => true, :type => 'email', 'ng-model' => 'formData.email'} - %input.form-control{:placeholder => 'Password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'formData.user_password'} - %input.form-control{:placeholder => 'Confirm Password', "ng-if" => "formData.showRegister", :name => 'password', :required => true, :type => 'password', 'ng-model' => 'formData.password_conf'} - - %a.block{"ng-click" => "formData.showAdvanced = !formData.showAdvanced"} Advanced Options - .advanced-options.mt-10{"ng-if" => "formData.showAdvanced"} - .float-group - %label.pull-left Sync Server Domain - %input.form-control.mt-5{:name => 'server', :placeholder => 'Server URL', :required => true, :type => 'text', 'ng-model' => 'formData.url'} - - .checkbox.mt-10 - %p - %input{"type" => "checkbox", "ng-model" => "formData.ephemeral", "ng-true-value" => "false", "ng-false-value" => "true"} - Stay signed in - .checkbox.mt-10{"ng-if" => "notesAndTagsCount() > 0"} - %p - %input{"type" => "checkbox", "ng-model" => "formData.mergeLocal", "ng-bind" => "true", "ng-change" => "mergeLocalChanged()"} - Merge local data ({{notesAndTagsCount()}} notes and tags) - %button.ui-button.block.mt-10{"ng-click" => "submitAuthForm()"} {{formData.showLogin ? "Sign In" : "Register"}} - - .mt-15{"ng-if" => "formData.showRegister"} - %h3 No Password Reset. - %p.mt-5 Because your notes are encrypted using your password, Standard Notes does not have a password reset option. You cannot forget your password. - - %em.block.center-align.mt-10{"ng-if" => "formData.status", "style" => "font-size: 14px;"} {{formData.status}} - - -# End account section - - %div{"ng-if" => "user"} - %h2 {{user.email}} - %p {{server}} - %div.bold.mt-10.tinted{"delay-hide" => "true", "show" => "syncStatus.syncOpInProgress || syncStatus.needsMoreSync", "delay" => "1000"} - .spinner.inline.mr-5.tinted - {{"Syncing" + (syncStatus.total > 0 ? ":" : "")}} - %span{"ng-if" => "syncStatus.total > 0"} {{syncStatus.current}}/{{syncStatus.total}} - %p.bold.mt-10.red.block{"ng-if" => "syncStatus.error"} Error syncing: {{syncStatus.error.message}} - - - - %a.block.mt-5{"ng-click" => "newPasswordData.changePassword = !newPasswordData.changePassword"} Change Password - %section.gray-bg.mt-10.medium-padding{"ng-if" => "newPasswordData.changePassword"} - %p.bold Change Password (Beta) - %p.mt-10 Since your encryption key is based on your password, changing your password requires all your notes and tags to be re-encrypted using your new key. - %p.mt-5 If you have thousands of items, this can take several minutes — you must keep the application window open during this process. - %p.mt-5 After changing your password, you must log out of all other applications currently signed in to your account. - %p.bold.mt-5 It is highly recommended you download a backup of your data before proceeding. - %div.mt-10{"ng-if" => "!newPasswordData.status"} - %a.red.mr-5{"ng-if" => "!newPasswordData.showForm", "ng-click" => "showPasswordChangeForm()"} Continue - %a{"ng-click" => "newPasswordData.changePassword = false; newPasswordData.showForm = false"} Cancel - %div.mt-10{"ng-if" => "newPasswordData.showForm"} - %form - %input.form-control{:type => 'password', "ng-model" => "newPasswordData.newPassword", "placeholder" => "Enter new password"} - %input.form-control{:type => 'password', "ng-model" => "newPasswordData.newPasswordConfirmation", "placeholder" => "Confirm new password"} - %button.ui-button.block{"ng-click" => "submitPasswordChange()"} Submit - %p.italic.mt-10{"ng-if" => "newPasswordData.status"} {{newPasswordData.status}} - - - - - %a.block.mt-5{"ng-click" => "showAdvanced = !showAdvanced"} Advanced - %div{"ng-if" => "showAdvanced"} - %a.block.mt-15{"href" => "{{dashboardURL()}}", "target" => "_blank"} Data Dashboard - %a.block.mt-5{"ng-click" => "reencryptPressed()"} Re-encrypt All Items - %a.block.mt-5{"ng-click" => "showCredentials = !showCredentials"} Show Credentials - %section.gray-bg.mt-10.medium-padding{"ng-if" => "showCredentials"} - %label.block - Encryption key: - .wrap.normal.mt-1.selectable {{encryptionKey()}} - %label.block.mt-5.mb-0 - Authentication key: - .wrap.normal.mt-1.selectable {{authKey() ? authKey() : 'Not available. Sign out then sign back in to compute.'}} - - - %div{"ng-if" => "securityUpdateAvailable()"} - %a.block.mt-5{"ng-click" => "clickedSecurityUpdate()"} Security Update Available - %section.gray-bg.mt-10.medium-padding{"ng-if" => "securityUpdateData.showForm"} - %p - %a{"href" => "https://standardnotes.org/help/security-update", "target" => "_blank"} Learn more. - %div.mt-10{"ng-if" => "!securityUpdateData.processing"} - %p.bold Enter your password to update: - %form.mt-5 - %input.form-control{:type => 'password', "ng-model" => "securityUpdateData.password", "placeholder" => "Enter password"} - %button.ui-button.block{"ng-click" => "submitSecurityUpdateForm()"} Update - %div.mt-5{"ng-if" => "securityUpdateData.processing"} - %p.tinted Processing... - - - .mt-25 - %h4 Encryption Status - %p - {{encryptionStatusString()}} - %div.mt-5{"ng-if" => "encryptionEnabled()"} - %i {{encryptionStatusForNotes()}} - - .mt-25 - %h4 Passcode Lock - %div{"ng-if" => "!hasPasscode() && passcodeOptionAvailable()"} - %p Add an app passcode to lock the app and encrypt on-device key storage. - %a.block.mt-5{"ng-click" => "addPasscodeClicked()", "ng-if" => "!formData.showPasscodeForm"} Add Passcode - - %form.mt-5{"ng-if" => "formData.showPasscodeForm", "ng-submit" => "submitPasscodeForm()"} - %p.bold Choose a passcode: - %input.form-control.mt-10{:type => 'password', "ng-model" => "formData.passcode", "placeholder" => "Passcode", "autofocus" => "true"} - %input.form-control.mt-10{:type => 'password', "ng-model" => "formData.confirmPasscode", "placeholder" => "Confirm Passcode"} - %button.standard.ui-button.block.tinted.mt-5{"type" => "submit"} Set Passcode - %div{"ng-if" => "hasPasscode()"} - %p - Passcode lock is enabled. - %span{"ng-if" => "isDesktopApplication()"} Your passcode will be required on new sessions after app quit. - %a.block.mt-5{"ng-click" => "removePasscodePressed()"} Remove Passcode - %div{"ng-if" => "!passcodeOptionAvailable()"} - %p Passcode lock is only available to permanent sessions. (You chose not to stay signed in.) - - - - .mt-25{"ng-if" => "!importData.loading"} - %h4 Data Archives - .mt-5{"ng-if" => "encryptedBackupsAvailable()"} - %label.normal.inline - %input{"type" => "radio", "ng-model" => "archiveFormData.encrypted", "ng-value" => "true", "ng-change" => "archiveFormData.encrypted = true"} - Encrypted - %label.normal.inline - %input{"type" => "radio", "ng-model" => "archiveFormData.encrypted", "ng-value" => "false", "ng-change" => "archiveFormData.encrypted = false"} - Decrypted - - %a.block.mt-5{"ng-click" => "downloadDataArchive()", "ng-class" => "{'mt-5' : !user}"} Download Data Archive - - %label.block.mt-5 - %input{"type" => "file", "style" => "display: none;", "file-change" => "->", "handler" => "importFileSelected(files)"} - .fake-link.tinted Import Data from Archive - - %div{"ng-if" => "importData.requestPassword"} - %form{"ng-submit" => "submitImportPassword()"} - %p Enter the account password associated with the import file. - %input.form-control.mt-5{:type => 'password', "ng-model" => "importData.password", "autofocus" => "true"} - %button.standard.ui-button.block.tinted.mt-5{"type" => "submit"} Decrypt & Import - - %p.mt-5{"ng-if" => "user"} Notes are downloaded in the Standard File format, which allows you to re-import back into this app easily. To download as plain text files, choose "Decrypted". - - .spinner.mt-10{"ng-if" => "importData.loading"} - - %a.block.mt-25.red{"ng-click" => "destroyLocalData()"} {{ user ? "Sign out and clear local data" : "Clear all local data" }}