mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
Merge remote-tracking branch 'upstream/master' into build/angular-10-upgrade
* upstream/master: (131 commits) 5.9.15 fix: prevent adding tags via short syntax for child tasks #568 fix: app not closing on windows for some people #567 fix: make tests work again fix: special case #568 fix: throw error for inconsistent sub task data #568 feat: write auto repair for wrongly unarchived archived sub tasks #568 feat: write auto repair for wrongly archived sub tasks 5.9.14 fix: about for mas... fix: text overlap Improve portuguese translation build: fix syntax error in mac deploy script build: fix syntax error in mac deploy script build: fix mac deploy script 2 build: fix mac deploy script 5.9.13 build: remove productName again for mas 5.9.12 build: add correct author name ...
This commit is contained in:
commit
2199eb2c12
79 changed files with 2744 additions and 451 deletions
|
|
@ -1,5 +1,13 @@
|
|||
---
|
||||
name: Bug Report
|
||||
labels: bug
|
||||
about: Report a bug you encountered
|
||||
title: ''
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--- Your issue may already be reported!
|
||||
Please search the issues before creating one. -->
|
||||
!!! Please search the issues before creating one !!! -->
|
||||
|
||||
### Your Environment
|
||||
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||
|
|
@ -9,12 +17,10 @@ Please search the issues before creating one. -->
|
|||
* Browser Name and version: <!-- if using the web version-->
|
||||
|
||||
### Expected Behavior
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||
<!--- Tell us what should happen -->
|
||||
|
||||
### Current Behavior
|
||||
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||
<!--- Tell us what happens instead of the expected behavior -->
|
||||
|
||||
### Steps to Reproduce (for bugs)
|
||||
<!--- Provide a link to a live example or an unambiguous set of steps to -->
|
||||
32
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: Feature Request
|
||||
assignees: ''
|
||||
labels: enhancement
|
||||
---
|
||||
<!--
|
||||
Thank for taking the time to fill this feature request fully! This will help a lot to communicate what this is about and to focus the discussion of the feature.
|
||||
|
||||
Please also make sure that there is no similar feature already opened up!
|
||||
-->
|
||||
|
||||
## Problem Statement
|
||||
<!--
|
||||
A clear and concise description of what the problem is. E.g. I'm always frustrated when [...]
|
||||
-->
|
||||
|
||||
## :grey_question: Possible Solution <!--
|
||||
A clear and concise description of what you want to happen.
|
||||
-->
|
||||
|
||||
## :arrow_heading_up: Describe alternatives you've considered
|
||||
<!--
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
-->
|
||||
|
||||
## :heavy_plus_sign: Additional context
|
||||
<!--
|
||||
Add any other context about the problem here. e.g. related issues or existing pull requests.
|
||||
-->
|
||||
53
.github/workflows/build-create-windows-store-on-release.yml
vendored
Normal file
53
.github/workflows/build-create-windows-store-on-release.yml
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
name: Win Store File on Release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs: null
|
||||
|
||||
jobs:
|
||||
windows-store-artifact:
|
||||
runs-on: windows-latest
|
||||
|
||||
if: "!github.event.release.prerelease"
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Load Electron Builder Windows Store Config
|
||||
run: echo $WIN_STORE_ELECTRON_BUILDER_YML | base64 --decode > electron-builder.yaml
|
||||
shell: bash
|
||||
env:
|
||||
WIN_STORE_ELECTRON_BUILDER_YML: ${{secrets.WIN_STORE_ELECTRON_BUILDER_YML}}
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Install Yarn Packages
|
||||
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
||||
run: yarn install
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
- name: Test Unit
|
||||
run: yarn test
|
||||
|
||||
- name: Build Frontend & Electron
|
||||
run: yarn build
|
||||
|
||||
- name: Build/Release Electron app
|
||||
uses: samuelmeuli/action-electron-builder@v1
|
||||
with:
|
||||
build_script_name: empty
|
||||
release: false
|
||||
github_token: ${{ secrets.github_token }}
|
||||
|
||||
- name: 'Upload Artifact'
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: WinStoreRelease
|
||||
path: app-builds/*.appx
|
||||
62
.github/workflows/build-publish-to-mac-store-on-release.yml
vendored
Normal file
62
.github/workflows/build-publish-to-mac-store-on-release.yml
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
name: Mac Store Release on Release
|
||||
on:
|
||||
release:
|
||||
types: [ published ]
|
||||
workflow_dispatch:
|
||||
inputs: null
|
||||
|
||||
jobs:
|
||||
mac-store-release:
|
||||
runs-on: macos-latest
|
||||
|
||||
if: "!github.event.release.prerelease"
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Install Yarn Packages
|
||||
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
||||
run: yarn install
|
||||
|
||||
- run: 'echo "$PROVISION_PROFILE" | base64 --decode > embedded.provisionprofile'
|
||||
shell: bash
|
||||
env:
|
||||
PROVISION_PROFILE: ${{secrets.mas_provision_profile}}
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
- name: Test Unit
|
||||
run: yarn test
|
||||
|
||||
# - name: Test E2E
|
||||
# run: yarn e2e
|
||||
|
||||
- name: Build Frontend & Electron
|
||||
run: yarn build
|
||||
|
||||
- uses: apple-actions/import-codesign-certs@v1
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.mac_certs }}
|
||||
p12-password: ${{ secrets.mac_certs_password }}
|
||||
|
||||
- name: Build Electron app
|
||||
run: yarn dist:mac:mas:buildOnly
|
||||
|
||||
- name: Validate App
|
||||
run: ls app-builds; ls app-builds/mas; xcrun altool --validate-app -f app-builds/mas/Super*.pkg -u ${{secrets.APPLEID}} -p ${{secrets.APPLEIDPASS}}
|
||||
env:
|
||||
APPLEID: ${{secrets.APPLEID}}
|
||||
APPLEIDPASS: ${{secrets.APPLEIDPASS}}
|
||||
|
||||
- name: Push to Store
|
||||
run: xcrun altool --upload-app -f app-builds/mas/Super*.pkg -u ${{secrets.APPLEID}} -p ${{secrets.APPLEIDPASS}}
|
||||
env:
|
||||
APPLEID: ${{secrets.APPLEID}}
|
||||
APPLEIDPASS: ${{secrets.APPLEIDPASS}}
|
||||
53
.github/workflows/build-update-web-app-on-release.yml
vendored
Normal file
53
.github/workflows/build-update-web-app-on-release.yml
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
name: Web App on Release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs: null
|
||||
|
||||
jobs:
|
||||
upload-to-app-super-productivity:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: "!github.event.release.prerelease"
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node.js, NPM and Yarn
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Install Yarn Packages
|
||||
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
||||
run: yarn install
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
- name: Test Unit
|
||||
run: yarn test
|
||||
|
||||
- name: Test E2E
|
||||
run: yarn e2e
|
||||
|
||||
- name: Build Frontend & Electron
|
||||
run: yarn buildFrontend:prodWeb
|
||||
|
||||
- name: Deploy to Web Server
|
||||
uses: easingthemes/ssh-deploy@v2.1.5
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.WEB_SERVER_SSH_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "dist/"
|
||||
REMOTE_HOST: ${{ secrets.WEB_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.WEB_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.WEB_REMOTE_TARGET }}
|
||||
|
||||
147
.github/workflows/build.yml
vendored
Normal file
147
.github/workflows/build.yml
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
name: Build All & Release
|
||||
on:
|
||||
push:
|
||||
branches: [ master, test/git-actions ]
|
||||
tags:
|
||||
- v*
|
||||
|
||||
|
||||
jobs:
|
||||
linux-bin-and-snap-release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Install Yarn Packages
|
||||
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
||||
run: yarn install
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
- name: Test Unit
|
||||
run: yarn test
|
||||
|
||||
- name: Test E2E
|
||||
run: yarn e2e
|
||||
|
||||
- name: Build Frontend & Electron
|
||||
run: yarn build
|
||||
|
||||
- name: Build/Release Electron app
|
||||
uses: samuelmeuli/action-electron-builder@v1
|
||||
with:
|
||||
build_script_name: empty
|
||||
github_token: ${{ secrets.github_token }}
|
||||
release: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
|
||||
- name: Install Snapcraft
|
||||
uses: samuelmeuli/action-snapcraft@v1
|
||||
with:
|
||||
# Log in to Snap Store
|
||||
snapcraft_token: ${{ secrets.snapcraft_token }}
|
||||
|
||||
# Release to edge if no tag and to candidate if tag
|
||||
- run: snapcraft push app-builds/superProductivity*.snap --release edge
|
||||
if: false == startsWith(github.ref, 'refs/tags/v')
|
||||
- run: snapcraft push app-builds/superProductivity*.snap --release candidate
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
|
||||
mac-bin:
|
||||
runs-on: macos-latest
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
steps:
|
||||
- name: Echo is Release
|
||||
run: echo "IS_RELEASE $IS_RELEASE, ${{ startsWith(github.ref, 'refs/tags/v') }}"
|
||||
env:
|
||||
IS_RELEASE: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Install Yarn Packages
|
||||
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
||||
run: yarn install
|
||||
|
||||
- run: 'echo "$PROVISION_PROFILE" | base64 --decode > embedded.provisionprofile'
|
||||
shell: bash
|
||||
env:
|
||||
PROVISION_PROFILE: ${{secrets.dl_provision_profile}}
|
||||
|
||||
- name: Prepare for app notarization
|
||||
# Import Apple API key for app notarization on macOS
|
||||
run: |
|
||||
mkdir -p ~/private_keys/
|
||||
echo '${{ secrets.mac_api_key }}' > ~/private_keys/AuthKey_${{ secrets.mac_api_key_id }}.p8
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
- name: Test Unit
|
||||
run: yarn test
|
||||
|
||||
- name: Test E2E
|
||||
run: yarn e2e
|
||||
|
||||
- name: Build Frontend & Electron
|
||||
run: yarn build
|
||||
|
||||
- name: Build/Release Electron app
|
||||
uses: samuelmeuli/action-electron-builder@v1
|
||||
with:
|
||||
build_script_name: empty
|
||||
github_token: ${{ secrets.github_token }}
|
||||
mac_certs: ${{ secrets.mac_certs }}
|
||||
mac_certs_password: ${{ secrets.mac_certs_password }}
|
||||
release: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
env:
|
||||
# macOS notarization API key
|
||||
API_KEY_ID: ${{ secrets.mac_api_key_id }}
|
||||
API_KEY_ISSUER_ID: ${{ secrets.mac_api_key_issuer_id }}
|
||||
|
||||
windows-bin:
|
||||
runs-on: windows-latest
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Install Yarn Packages
|
||||
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
||||
run: yarn install
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
- name: Test Unit
|
||||
run: yarn test
|
||||
|
||||
- name: Build Frontend & Electron
|
||||
run: yarn build
|
||||
|
||||
- name: Build/Release Electron app
|
||||
uses: samuelmeuli/action-electron-builder@v1
|
||||
with:
|
||||
build_script_name: empty
|
||||
github_token: ${{ secrets.github_token }}
|
||||
release: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
71
.github/workflows/codeql-analysis.yml
vendored
Normal file
71
.github/workflows/codeql-analysis.yml
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 3 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['javascript']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
31
.github/workflows/lint-and-test-pr.yml
vendored
Normal file
31
.github/workflows/lint-and-test-pr.yml
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
name: "Lint & Test PRs"
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
test-on-linux:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node.js, NPM and Yarn
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Install Yarn Packages
|
||||
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
||||
run: yarn install
|
||||
|
||||
- run: yarn lint
|
||||
- run: yarn test
|
||||
- run: yarn e2e
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -61,4 +61,5 @@ electron/**/*.js.map
|
|||
all-certs.p12
|
||||
mac-cert.tar
|
||||
build/electron-builder.appx.yaml
|
||||
electron-builder.win-store.yaml
|
||||
|
||||
|
|
|
|||
116
.travis.yml
116
.travis.yml
|
|
@ -1,116 +0,0 @@
|
|||
sudo: required
|
||||
language: node_js
|
||||
node_js: '12'
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
osx_image: xcode10
|
||||
addons:
|
||||
chrome: stable
|
||||
before_install:
|
||||
- openssl aes-256-cbc -K $encrypted_527645209bb0_key -iv $encrypted_527645209bb0_iv -in build/mac-cert.tar.enc -out mac-cert.tar -d
|
||||
- tar xvf mac-cert.tar
|
||||
|
||||
- os: linux
|
||||
dist: xenial
|
||||
language: generic
|
||||
services:
|
||||
- docker
|
||||
# before_install:
|
||||
# - sudo snap install snapcraft --classic
|
||||
# - export CHROME_BIN=chromium-browser
|
||||
# - export DISPLAY=:99.0
|
||||
# - sh -e /etc/init.d/xvfb start
|
||||
|
||||
addons:
|
||||
ssh_known_hosts:
|
||||
- the-front-end.de
|
||||
- frs.sourceforge.net
|
||||
apt:
|
||||
packages:
|
||||
- sshpass
|
||||
|
||||
env:
|
||||
global:
|
||||
- ELECTRON_CACHE=$HOME/.cache/electron
|
||||
- ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
- $HOME/.cache/electron
|
||||
- $HOME/.cache/electron-builder
|
||||
- $HOME/.npm/_prebuilds
|
||||
|
||||
script:
|
||||
- |
|
||||
if [ -n "$TRAVIS_TAG" ]; then
|
||||
PUB=always
|
||||
else
|
||||
PUB=never
|
||||
fi
|
||||
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
||||
echo '____RUNNING DOCKER____'
|
||||
bash ${TRAVIS_BUILD_DIR}/build/docker/run-linux-win.sh ${PUB}
|
||||
else
|
||||
yarn install && yarn add 7zip-bin-mac
|
||||
yarn run buildAllElectron:noTests
|
||||
travis_wait 30 yarn dist:mac:dl -p $PUB
|
||||
fi
|
||||
|
||||
# NOTE: disabled until next release of electron builder
|
||||
# if [ -n "$TRAVIS_TAG" ]; then
|
||||
# yarn dist:mac:mas
|
||||
# fi
|
||||
|
||||
|
||||
deploy:
|
||||
# Snap Deployment
|
||||
- on:
|
||||
condition: $TRAVIS_OS_NAME = linux
|
||||
tags: false
|
||||
branch: master
|
||||
provider: snap
|
||||
snap: ./app-builds/*.snap
|
||||
channel: edge
|
||||
skip_cleanup: true
|
||||
# we use edge because of this: https://travis-ci.community/t/snap-deployment-stopped-working-out-of-nowhere/6908/2
|
||||
edge: true
|
||||
- on:
|
||||
condition: $TRAVIS_OS_NAME = linux
|
||||
tags: true
|
||||
branch: master
|
||||
provider: snap
|
||||
snap: ./app-builds/*.snap
|
||||
channel: candidate
|
||||
skip_cleanup: true
|
||||
# we use edge because of this: https://travis-ci.community/t/snap-deployment-stopped-working-out-of-nowhere/6908/2
|
||||
edge: true
|
||||
# Web deployment
|
||||
- on:
|
||||
condition: $TRAVIS_OS_NAME = linux
|
||||
tags: true
|
||||
branch: master
|
||||
provider: script
|
||||
script: sshpass -p "$DEPLOY_PASS" rsync -avz ./dist $DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH
|
||||
skip_cleanup: true
|
||||
# NOTE: disabled until next release of electron builder and until electron works with osx again
|
||||
# - on:
|
||||
# branch: master
|
||||
# condition: $TRAVIS_OS_NAME = osx
|
||||
# tags: true
|
||||
# provider: script
|
||||
# script: xcrun altool --upload-app -f app-builds/mas/superProductivity-*.pkg -u "${APPLEID}" -p "${APPLEIDPASS}"
|
||||
# skip_cleanup: true
|
||||
|
||||
|
||||
# NOTE: this would only work, if we could and wanted to auto publish the github draft
|
||||
# - provider: script
|
||||
# script: brew update && brew install vitorgalvao/tiny-scripts/cask-repair && openssl aes-256-cbc -K $encrypted_c04542ca1075_key -iv $encrypted_c04542ca1075_iv -in build/hub.enc -out ~/.config/hub -d && cask-repair -b -v $TRAVIS_TAG superproductivity
|
||||
# skip_cleanup: true
|
||||
# on:
|
||||
# branch: master
|
||||
# condition: $TRAVIS_OS_NAME = osx
|
||||
# tags: true
|
||||
122
CHANGELOG.md
122
CHANGELOG.md
|
|
@ -1,3 +1,125 @@
|
|||
## [5.9.15](https://github.com/johannesjo/super-productivity/compare/v5.9.14...v5.9.15) (2020-10-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* app not closing on windows for some people [#567](https://github.com/johannesjo/super-productivity/issues/567) ([5e340ad](https://github.com/johannesjo/super-productivity/commit/5e340aded20258533767bc87b54b4405c46ad5d1))
|
||||
* make tests work again ([bc227bc](https://github.com/johannesjo/super-productivity/commit/bc227bcae42cd12d2fb250182a88d8df98028b02))
|
||||
* prevent adding tags via short syntax for child tasks [#568](https://github.com/johannesjo/super-productivity/issues/568) ([94f8147](https://github.com/johannesjo/super-productivity/commit/94f814716174e97c2b28e481a8e90f778c3eb72b))
|
||||
* special case [#568](https://github.com/johannesjo/super-productivity/issues/568) ([c26f62b](https://github.com/johannesjo/super-productivity/commit/c26f62b0ae72c80ca4930073094baebd1c3959e3))
|
||||
* text overlap ([39508dc](https://github.com/johannesjo/super-productivity/commit/39508dc2f26f4228b4721d5fcaa255b702585088))
|
||||
* throw error for inconsistent sub task data [#568](https://github.com/johannesjo/super-productivity/issues/568) ([786235b](https://github.com/johannesjo/super-productivity/commit/786235b9e5ed936adf43aac7f8d9a995fb3cb558))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* write auto repair for wrongly archived sub tasks ([81f076a](https://github.com/johannesjo/super-productivity/commit/81f076aefb543b131cfb87e3e8b7696094b14fd2))
|
||||
* write auto repair for wrongly unarchived archived sub tasks [#568](https://github.com/johannesjo/super-productivity/issues/568) ([609941d](https://github.com/johannesjo/super-productivity/commit/609941ddebf83ac4a2040159d8087d75316f0716))
|
||||
|
||||
|
||||
|
||||
## [5.9.14](https://github.com/johannesjo/super-productivity/compare/v5.9.13...v5.9.14) (2020-10-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* about for mas... ([cdc7687](https://github.com/johannesjo/super-productivity/commit/cdc76876bc4508e9f01e20deb63a2719f1374190))
|
||||
|
||||
|
||||
|
||||
## [5.9.13](https://github.com/johannesjo/super-productivity/compare/v5.9.12...v5.9.13) (2020-10-08)
|
||||
|
||||
|
||||
|
||||
## [5.9.12](https://github.com/johannesjo/super-productivity/compare/v5.9.11...v5.9.12) (2020-10-08)
|
||||
|
||||
|
||||
|
||||
## [5.9.11](https://github.com/johannesjo/super-productivity/compare/v5.9.10...v5.9.11) (2020-10-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* not in project context [#545](https://github.com/johannesjo/super-productivity/issues/545) ([a293f2f](https://github.com/johannesjo/super-productivity/commit/a293f2f736d7a61d87cc792b669864b7c2f5c5e8))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **autoBackupRestore:** add translations [#553](https://github.com/johannesjo/super-productivity/issues/553) ([cfeed8d](https://github.com/johannesjo/super-productivity/commit/cfeed8de1048c26e69b65ec1b7689a9f8eebb720))
|
||||
* **autoBackupRestore:** implement most basic variant – circular dependency [#553](https://github.com/johannesjo/super-productivity/issues/553) ([bdd3cbc](https://github.com/johannesjo/super-productivity/commit/bdd3cbc49649a6e8d6e7dee613932d9fd4dbe688))
|
||||
* **autoBackupRestore:** make it work [#553](https://github.com/johannesjo/super-productivity/issues/553) ([a54711d](https://github.com/johannesjo/super-productivity/commit/a54711d9651d19a0f15b66f0e2f6b4d97f7a3e83))
|
||||
* **autoBackupRestore:** outline [#553](https://github.com/johannesjo/super-productivity/issues/553) ([7d00652](https://github.com/johannesjo/super-productivity/commit/7d00652eb9212a80b4a48c487f91623a41fdd11d))
|
||||
* **i18n:** add norwegian ([a512c94](https://github.com/johannesjo/super-productivity/commit/a512c94584ddaa529d0a0a198fc8d9e7a58fc98d))
|
||||
* **task:** make startable tasks work better ([ada4c97](https://github.com/johannesjo/super-productivity/commit/ada4c97db9fb7075419f43d845b4e33606dbeba2))
|
||||
|
||||
|
||||
|
||||
## [5.9.10](https://github.com/johannesjo/super-productivity/compare/v5.9.2...v5.9.10) (2020-10-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* set first day of the week [#528](https://github.com/johannesjo/super-productivity/issues/528) ([b83bfea](https://github.com/johannesjo/super-productivity/commit/b83bfeafc6fd1c8258da9b7a040815f578d2dbc7))
|
||||
* set first day of week in DateAdapter ([6b9c5e7](https://github.com/johannesjo/super-productivity/commit/6b9c5e72692367cbb50f51e0e2a8fd94572be0d4))
|
||||
|
||||
|
||||
|
||||
## [5.9.9](https://github.com/johannesjo/super-productivity/compare/v5.9.8...v5.9.9) (2020-10-04)
|
||||
|
||||
|
||||
|
||||
## [5.9.8](https://github.com/johannesjo/super-productivity/compare/v5.9.7...v5.9.8) (2020-10-04)
|
||||
|
||||
|
||||
|
||||
## [5.9.7](https://github.com/johannesjo/super-productivity/compare/v5.9.6...v5.9.7) (2020-10-04)
|
||||
|
||||
|
||||
|
||||
## [5.9.6](https://github.com/johannesjo/super-productivity/compare/v5.9.5...v5.9.6) (2020-10-04)
|
||||
|
||||
|
||||
|
||||
## [5.9.5](https://github.com/johannesjo/super-productivity/compare/v5.9.4...v5.9.5) (2020-10-03)
|
||||
|
||||
|
||||
|
||||
## [5.9.4](https://github.com/johannesjo/super-productivity/compare/v5.9.3...v5.9.4) (2020-10-03)
|
||||
|
||||
|
||||
|
||||
## [5.9.3](https://github.com/johannesjo/super-productivity/compare/v0.0.1...v5.9.3) (2020-10-03)
|
||||
|
||||
|
||||
|
||||
## [5.9.2](https://github.com/johannesjo/super-productivity/compare/v5.9.1...v5.9.2) (2020-10-02)
|
||||
|
||||
|
||||
|
||||
## [5.9.1](https://github.com/johannesjo/super-productivity/compare/v5.9.0...v5.9.1) (2020-10-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow to display images from file system [#549](https://github.com/johannesjo/super-productivity/issues/549) ([2c8255b](https://github.com/johannesjo/super-productivity/commit/2c8255b0814e03623048ac52cd960cf7b3710999))
|
||||
* chrome extension link ([58be356](https://github.com/johannesjo/super-productivity/commit/58be3561c4b1a9695f7bc75b01baf747dc54734a))
|
||||
* lint ([b1b8796](https://github.com/johannesjo/super-productivity/commit/b1b87960d7b394784d9bafa92cd84021cec64f7c))
|
||||
* **jira:** wrong issue link for auto-imported issues [#551](https://github.com/johannesjo/super-productivity/issues/551) ([ca7cb4b](https://github.com/johannesjo/super-productivity/commit/ca7cb4bf5c702664ea83feba9c60265d2ad48b4d))
|
||||
* **task:** only start first startable when there is none already running ([c96b846](https://github.com/johannesjo/super-productivity/commit/c96b846377807441500ea99565106190c8a6a8e3))
|
||||
* lint error ([a8d371e](https://github.com/johannesjo/super-productivity/commit/a8d371ed53552c3e354d4bfa9bcc839d15f3856b))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **startTrackingReminder:** auto hide on idle and when starting to track on a task manually ([a7e41d9](https://github.com/johannesjo/super-productivity/commit/a7e41d937655671986d080a62f8f202cedf4a138))
|
||||
* **startTrackingReminder:** hide on mobile per default and make configurable ([b2b210b](https://github.com/johannesjo/super-productivity/commit/b2b210bfe54c04e92b34b47bc25d1816241d7978))
|
||||
* add new productivity tips ([a53878a](https://github.com/johannesjo/super-productivity/commit/a53878ab3176e06617f4665039ec163a0a60d56c))
|
||||
* improve broken data handling [#555](https://github.com/johannesjo/super-productivity/issues/555) ([c9c2e0c](https://github.com/johannesjo/super-productivity/commit/c9c2e0cad56383fd69f3414d266aec7f6c44189d))
|
||||
* improve data repair handling [#552](https://github.com/johannesjo/super-productivity/issues/552) ([1012edb](https://github.com/johannesjo/super-productivity/commit/1012edbd42f8bb99217437843e8a455d7b729dfb))
|
||||
* make AppDataForProjects non optional ([8b1a9cf](https://github.com/johannesjo/super-productivity/commit/8b1a9cf79c01f5e876ec2d972e23ecebdac60c0d))
|
||||
|
||||
|
||||
|
||||
# [5.9.0](https://github.com/johannesjo/super-productivity/compare/v5.8.2...v5.9.0) (2020-09-24)
|
||||
|
||||
|
||||
|
|
|
|||
26
angular.json
26
angular.json
|
|
@ -66,7 +66,7 @@
|
|||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"serviceWorker": true
|
||||
"serviceWorker": false
|
||||
},
|
||||
"productionWeb": {
|
||||
"baseHref": "",
|
||||
|
|
@ -94,6 +94,30 @@
|
|||
"serviceWorker": true
|
||||
},
|
||||
"stage": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "6kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": true,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"serviceWorker": false
|
||||
},
|
||||
"stageWeb": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
FROM electronuserland/builder:wine
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# install google chrome
|
||||
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
|
||||
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \
|
||||
apt-get update -y && apt-get install -y --no-install-recommends xvfb google-chrome-stable libgconf-2-4 && \
|
||||
# clean
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# replace shell with bash so we can source files
|
||||
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
|
||||
|
||||
# add yarn repo
|
||||
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
|
||||
|
||||
# install yarn and clean up
|
||||
RUN apt-get update && apt-get install -y yarn && apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV NVM_DIR /usr/local/nvm
|
||||
ENV NODE_VERSION 12.14.1
|
||||
|
||||
RUN mkdir $NVM_DIR -p
|
||||
|
||||
# install nvm with node and npm
|
||||
RUN curl -sS -o- https://raw.githubusercontent.com/creationix/nvm/v0.35.2/install.sh | bash
|
||||
|
||||
# install node and npm
|
||||
RUN source $NVM_DIR/nvm.sh \
|
||||
&& nvm install $NODE_VERSION \
|
||||
&& nvm alias default $NODE_VERSION \
|
||||
&& nvm use default
|
||||
|
||||
# add node and npm to path so the commands are available
|
||||
ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules
|
||||
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH
|
||||
|
||||
# confirm installation
|
||||
RUN node -v
|
||||
RUN yarn -v
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
PWD2=$PWD
|
||||
# read as arg
|
||||
PUB=$1
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo PUB $PUB
|
||||
google-chrome --version
|
||||
|
||||
docker run $ENVS --rm \
|
||||
$(env | \
|
||||
grep -Eo '^[^\s=]*(_TOKEN|_KEY)[^\s=]*' | \
|
||||
sed '/^$/d;s/^/-e /' | \
|
||||
paste -sd ' ' \
|
||||
) \
|
||||
-v ${PWD2}:/project \
|
||||
-v ~/.cache/electron:/root/.cache/electron \
|
||||
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
|
||||
$(docker image build -q .) \
|
||||
/bin/bash -c "echo '____DOCKER_INNER_START____' && echo $PUB && node -v && npm -v && yarn -v && ls -l && yarn --link-duplicates --pure-lockfile && yarn run dist:linuxAndWin -p ${PUB} && ls -l ./dist"
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
appId: com.super-productivity.app
|
||||
productName: Super Productivity
|
||||
files:
|
||||
- electron/**/*
|
||||
- "!electron/**/*.ts"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
appId: com.super-productivity.app
|
||||
#afterSign: build/scripts/notarize.js
|
||||
afterSign: electron-builder-notarize
|
||||
productName: Super Productivity
|
||||
files:
|
||||
- electron/**/*
|
||||
- "!electron/**/*.ts"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,5 @@
|
|||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,33 +0,0 @@
|
|||
require('dotenv').config();
|
||||
const {notarize} = require('electron-notarize');
|
||||
const fs = require('fs');
|
||||
|
||||
exports.default = async function notarizing(context) {
|
||||
const {electronPlatformName, appOutDir} = context;
|
||||
if (electronPlatformName !== 'darwin') {
|
||||
return;
|
||||
}
|
||||
|
||||
const appName = context.packager.appInfo.productFilename;
|
||||
const appBundleId = context.packager.appInfo.macBundleIdentifier;
|
||||
const appPath = `${appOutDir}/${appName}.app`;
|
||||
if (!fs.existsSync(appPath)) {
|
||||
throw new Error(`Cannot find application at: ${appPath}`);
|
||||
}
|
||||
|
||||
try {
|
||||
let envBefore = process.env.DEBUG;
|
||||
process.env.DEBUG = 'electron-notarize';
|
||||
await notarize({
|
||||
appBundleId,
|
||||
appPath,
|
||||
appleId: process.env.APPLEID,
|
||||
appleIdPassword: process.env.APPLEIDPASS,
|
||||
});
|
||||
process.env.DEBUG = envBefore;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new Error(e);
|
||||
}
|
||||
console.log(`Notarizing DONE`);
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
appId: superProductivity
|
||||
afterSign: build/scripts/notarize.js
|
||||
afterSign: electron-builder-notarize
|
||||
files:
|
||||
- electron/**/*
|
||||
- "!electron/**/*.ts"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,49 @@
|
|||
import { app } from 'electron';
|
||||
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
||||
import { app, ipcMain } from 'electron';
|
||||
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'fs';
|
||||
import { IPC } from './ipc-events.const';
|
||||
import { answerRenderer } from './better-ipc';
|
||||
import { LocalBackupMeta } from '../src/app/imex/local-backup/local-backup.model';
|
||||
import * as path from 'path';
|
||||
|
||||
export const BACKUP_DIR = `${app.getPath('userData')}/backups`;
|
||||
console.log('Saving backups to', BACKUP_DIR);
|
||||
let BACKUP_DIR: string = `${app.getPath('userData')}/backups`;
|
||||
|
||||
export function backupData(ev, data) {
|
||||
export function initBackupAdapter(backupDir: string) {
|
||||
BACKUP_DIR = backupDir;
|
||||
console.log('Saving backups to', BACKUP_DIR);
|
||||
|
||||
// BACKUP
|
||||
ipcMain.on(IPC.BACKUP, backupData);
|
||||
|
||||
// IS_BACKUP_AVAILABLE
|
||||
answerRenderer(IPC.BACKUP_IS_AVAILABLE, (): LocalBackupMeta | false => {
|
||||
if (!existsSync(BACKUP_DIR)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const files = readdirSync(BACKUP_DIR);
|
||||
if (!files.length) {
|
||||
return false;
|
||||
}
|
||||
const filesWithMeta: LocalBackupMeta[] = files.map((fileName: string): LocalBackupMeta => ({
|
||||
name: fileName,
|
||||
path: path.join(BACKUP_DIR, fileName),
|
||||
folder: BACKUP_DIR,
|
||||
created: statSync(path.join(BACKUP_DIR, fileName)).mtime.getTime()
|
||||
}));
|
||||
|
||||
filesWithMeta.sort((a: LocalBackupMeta, b: LocalBackupMeta) => a.created - b.created);
|
||||
console.log('Avilable Backup Files: ', filesWithMeta);
|
||||
return filesWithMeta.reverse()[0];
|
||||
});
|
||||
|
||||
// RESTORE_BACKUP
|
||||
answerRenderer(IPC.BACKUP_LOAD_DATA, (backupPath): string => {
|
||||
console.log('Reading backup file: ', backupPath);
|
||||
return readFileSync(backupPath, {encoding: 'utf8'});
|
||||
});
|
||||
}
|
||||
|
||||
function backupData(ev, data) {
|
||||
if (!existsSync(BACKUP_DIR)) {
|
||||
mkdirSync(BACKUP_DIR);
|
||||
}
|
||||
|
|
|
|||
55
electron/better-ipc.ts
Normal file
55
electron/better-ipc.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { BrowserWindow, ipcMain, IpcMainEvent } from 'electron';
|
||||
|
||||
// TODO make available for both
|
||||
const getSendChannel = channel => `%better-ipc-send-channel-${channel}`;
|
||||
|
||||
// TODO add all typing
|
||||
export const answerRenderer = (browserWindowOrChannel, channelOrCallback, callbackOrNothing?) => {
|
||||
let window;
|
||||
let channel;
|
||||
let callback;
|
||||
|
||||
if (callbackOrNothing === undefined) {
|
||||
channel = browserWindowOrChannel;
|
||||
callback = channelOrCallback;
|
||||
} else {
|
||||
window = browserWindowOrChannel;
|
||||
channel = channelOrCallback;
|
||||
callback = callbackOrNothing;
|
||||
|
||||
if (!window) {
|
||||
throw new Error('Browser window required');
|
||||
}
|
||||
}
|
||||
|
||||
const sendChannel = getSendChannel(channel);
|
||||
|
||||
const listener = async (event: IpcMainEvent, data) => {
|
||||
const browserWindow: BrowserWindow | null = BrowserWindow.fromWebContents(event.sender);
|
||||
|
||||
if (window && window.id !== browserWindow?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const send = (channelI, dataI) => {
|
||||
if (!(browserWindow && browserWindow.isDestroyed())) {
|
||||
event.sender.send(channelI, dataI);
|
||||
}
|
||||
};
|
||||
|
||||
const {dataChannel, errorChannel, userData} = data;
|
||||
|
||||
try {
|
||||
send(dataChannel, await callback(userData, browserWindow));
|
||||
} catch (error) {
|
||||
// send(errorChannel, serializeError(error));
|
||||
send(errorChannel, error);
|
||||
}
|
||||
};
|
||||
|
||||
ipcMain.on(sendChannel, listener);
|
||||
|
||||
return () => {
|
||||
ipcMain.off(sendChannel, listener);
|
||||
};
|
||||
};
|
||||
|
|
@ -35,6 +35,9 @@ export enum IPC {
|
|||
EXEC = 'EXEC',
|
||||
|
||||
BACKUP = 'BACKUP_APP_DATA',
|
||||
BACKUP_IS_AVAILABLE = 'BACKUP_IS_AVAILABLE',
|
||||
BACKUP_LOAD_DATA = 'BACKUP_LOAD_DATA',
|
||||
|
||||
SET_PROGRESS_BAR = 'SET_PROGRESS_BAR',
|
||||
|
||||
NOTIFY_ON_CLOSE = 'NOTIFY_ON_CLOSE',
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ function createMenu(quitApp) {
|
|||
const menuTpl = [{
|
||||
label: 'Application',
|
||||
submenu: [
|
||||
{label: 'About Application', selector: 'orderFrontStandardAboutPanel:'},
|
||||
{label: 'About Super Productivity', selector: 'orderFrontStandardAboutPanel:'},
|
||||
{type: 'separator'},
|
||||
{
|
||||
label: 'Quit', click: quitApp
|
||||
|
|
@ -207,7 +207,7 @@ const appCloseHandler = (
|
|||
}
|
||||
});
|
||||
|
||||
mainWin.on('close', (event) => {
|
||||
app.on('window-all-closed', (event) => {
|
||||
// NOTE: this might not work if we run a second instance of the app
|
||||
console.log('close, isQuiting:', (app as any).isQuiting);
|
||||
if (!(app as any).isQuiting) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
'use strict';
|
||||
import { App, app, BrowserWindow, globalShortcut, ipcMain, powerMonitor } from 'electron';
|
||||
import { App, app, BrowserWindow, globalShortcut, ipcMain, powerMonitor, protocol } from 'electron';
|
||||
import * as electronDl from 'electron-dl';
|
||||
|
||||
import { info } from 'electron-log';
|
||||
|
|
@ -14,7 +14,7 @@ import { initGoogleAuth } from './google-auth';
|
|||
import { errorHandler } from './error-handler';
|
||||
import { initDebug } from './debug';
|
||||
import { IPC } from './ipc-events.const';
|
||||
import { backupData } from './backup';
|
||||
import { initBackupAdapter } from './backup';
|
||||
import { JiraCfg } from '../src/app/features/issue/providers/jira/jira.model';
|
||||
import { KeyboardConfig } from '../src/app/features/config/global-config.model';
|
||||
import lockscreen from './lockscreen';
|
||||
|
|
@ -51,6 +51,7 @@ process.argv.forEach((val) => {
|
|||
isShowDevTools = true;
|
||||
}
|
||||
});
|
||||
const BACKUP_DIR = `${app.getPath('userData')}/backups`;
|
||||
|
||||
interface MyApp extends App {
|
||||
isQuiting?: boolean;
|
||||
|
|
@ -100,6 +101,7 @@ appIN.on('certificate-error', (event, webContents, url, error, certificate, call
|
|||
// -------------------
|
||||
appIN.on('ready', createMainWin);
|
||||
appIN.on('ready', createIndicator);
|
||||
appIN.on('ready', () => initBackupAdapter(BACKUP_DIR));
|
||||
|
||||
appIN.on('activate', () => {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
|
|
@ -156,6 +158,11 @@ appIN.on('ready', () => {
|
|||
sendIdleMsgIfOverMin(Date.now() - suspendStart);
|
||||
mainWin.webContents.send(IPC.RESUME);
|
||||
});
|
||||
|
||||
protocol.registerFileProtocol('file', (request, callback) => {
|
||||
const pathname = decodeURI(request.url.replace('file:///', ''));
|
||||
callback(pathname);
|
||||
});
|
||||
});
|
||||
|
||||
appIN.on('will-quit', () => {
|
||||
|
|
@ -190,8 +197,6 @@ ipcMain.on(IPC.SHUTDOWN_NOW, quitAppNow);
|
|||
|
||||
ipcMain.on(IPC.EXEC, exec);
|
||||
|
||||
ipcMain.on(IPC.BACKUP, backupData);
|
||||
|
||||
ipcMain.on(IPC.LOCK_SCREEN, () => {
|
||||
if (isLocked) {
|
||||
return;
|
||||
|
|
|
|||
25
package.json
25
package.json
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"name": "superProductivity",
|
||||
"version": "5.9.0",
|
||||
"version": "5.9.15",
|
||||
"description": "Personal Task Management App to help you with your daily struggle with JIRA etc.",
|
||||
"main": "./electron/main.js",
|
||||
"author": "johannesjo <contact@super-productivity.com> (http://super-productivity.com)",
|
||||
"author": "Johannes Millan <contact@super-productivity.com> (http://super-productivity.com)",
|
||||
"license": "MIT",
|
||||
"homepage": "http://super-productivity.com",
|
||||
"repository": {
|
||||
|
|
@ -23,12 +23,14 @@
|
|||
"startFrontend": "ng serve",
|
||||
"serveProd": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng serve --prod",
|
||||
"buildFrontend:prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --aot --prod",
|
||||
"buildFrontend:prodWeb": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --aot --prod --configuration productionWeb",
|
||||
"buildFrontend:stage": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --aot --prod --configuration stage",
|
||||
"buildFrontend:stageWeb": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --aot --prod --configuration stageWeb",
|
||||
"buildFrontend:prod:watch": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --aot --prod --watch",
|
||||
"buildAllElectron:prod": "yarn preCheck && yarn buildFrontend:prod && yarn electron:build",
|
||||
"buildAllElectron:stage": "yarn preCheck && yarn buildFrontend:stage && yarn electron:build",
|
||||
"buildAllElectron:noTests": "yarn lint && yarn buildFrontend:prod && yarn electron:build",
|
||||
"buildApp": "yarn preCheck && yarn buildAllElectron:prod && yarn electron-builder",
|
||||
"buildAllElectron:noTests:prod": "yarn lint && yarn buildFrontend:prod && yarn electron:build",
|
||||
"build": "yarn buildAllElectron:noTests:prod",
|
||||
"test": "ng test --watch=false",
|
||||
"test:watch": "ng test --browsers ChromeHeadless",
|
||||
"lint": "ng lint",
|
||||
|
|
@ -40,21 +42,23 @@
|
|||
"electron:build": "tsc -p electron/tsconfig.electron.json",
|
||||
"electron:watch": "tsc -p electron/tsconfig.electron.json --watch",
|
||||
"electronBuilderOnly": "electron-builder",
|
||||
"empty": "echo 'EMPTY YEAH'",
|
||||
"pack": "electron-builder --dir",
|
||||
"localInstall": "sudo echo 'Starting local install' && rm -Rf ./dist/ && rm -Rf ./app-builds/ && yarn buildAllElectron:stage && electron-builder --linux deb && sudo dpkg -i app-builds/superProductivity*.deb",
|
||||
"localInstall:prod": "sudo echo 'Starting local install' && rm -Rf ./dist/ && rm -Rf ./app-builds/ && yarn buildAllElectron:prod && electron-builder --linux deb && sudo dpkg -i app-builds/superProductivity*.deb",
|
||||
"localInstall:quick": "sudo echo 'Starting local install' && rm -Rf ./dist/ && rm -Rf ./app-builds/ && yarn buildFrontend:stage && yarn electron:build && electron-builder --linux deb && sudo dpkg -i app-builds/superProductivity*.deb",
|
||||
"localInstall:mac": "sudo echo 'Starting local install. Don`t forget APPLEID & APPLEIDPASS !!' && yarn buildAllElectron:prod && sudo echo '' && electron-builder && sudo cp -rf app-builds/mac/superProductivity.app/ /Applications/superProductivity.app",
|
||||
"localInstall:mac": "sudo echo 'Starting local install. Don`t forget APPLEID & APPLEIDPASS !!' && yarn buildAllElectron:noTests:prod && sudo echo '' && electron-builder && sudo cp -rf app-builds/mac/Super\\ Productivity.app/ /Applications/superProductivity.app",
|
||||
"dist": "yarn buildAllElectron:prod && electron-builder",
|
||||
"dist:only": "electron-builder",
|
||||
"dist:linuxAndWin": "yarn buildAllElectron:prod && electron-builder --linux --win",
|
||||
"dist:win": "yarn buildAllElectron:noTests && electron-builder --win",
|
||||
"dist:win": "yarn buildAllElectron:noTests:prod && electron-builder --win",
|
||||
"dist:win:only": "electron-builder --win",
|
||||
"dist:win:appx": "yarn buildAllElectron:prod && electron-builder --win --config=build/electron-builder.appx.yaml",
|
||||
"dist:win:store": "git stash && git pull && yarn && git stash pop && yarn dist:win",
|
||||
"dist:mac:dl": "cp dl.provisionprofile embedded.provisionprofile && electron-builder --mac",
|
||||
"dist:mac:mas": "cp mas.provisionprofile embedded.provisionprofile; electron-builder --mac mas --config=build/electron-builder.mas.yaml",
|
||||
"dist:mac:mas:dev": "cp mas-dev.provisionprofile embedded.provisionprofile; electron-builder --mac mas-dev --config=build/electron-builder.mas-dev.yaml",
|
||||
"dist:win:store": "git pull && yarn && copy electron-builder.win-store.yaml electron-builder.yaml && yarn dist:win && git checkout electron-builder.yaml || git checkout electron-builder.yaml",
|
||||
"dist:mac:dl": "cp tools/mac-profiles/dl.provisionprofile embedded.provisionprofile && electron-builder --mac",
|
||||
"dist:mac:mas": "cp tools/mac-profiles/mas.provisionprofile embedded.provisionprofile; electron-builder --mac mas --config=build/electron-builder.mas.yaml",
|
||||
"dist:mac:mas:buildOnly": "electron-builder --mac mas --config=build/electron-builder.mas.yaml",
|
||||
"dist:mac:mas:dev": "cp tools/mac-profiles/mas-dev.provisionprofile embedded.provisionprofile; electron-builder --mac mas-dev --config=build/electron-builder.mas-dev.yaml",
|
||||
"release": "yarn release.changelog && yarn dist",
|
||||
"release.changelog": "conventional-changelog -i CHANGELOG.md -s -p angular",
|
||||
"version": "yarn release.changelog && git add -A",
|
||||
|
|
@ -133,6 +137,7 @@
|
|||
"cross-env": "^7.0.2",
|
||||
"electron": "^10.1.2",
|
||||
"electron-builder": "^22.7.0",
|
||||
"electron-builder-notarize": "^1.2.0",
|
||||
"electron-notarize": "^1.0.0",
|
||||
"electron-reload": "^1.2.5",
|
||||
"file-saver": "^2.0.2",
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import { environment } from '../environments/environment';
|
|||
import { RouterOutlet } from '@angular/router';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { TrackingReminderService } from './features/time-tracking/tracking-reminder/tracking-reminder.service';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
const w = window as any;
|
||||
const productivityTip: string[] = w.productivityTips && w.productivityTips[w.randomIndex];
|
||||
|
|
@ -160,8 +161,11 @@ export class AppComponent implements OnDestroy {
|
|||
ev.preventDefault();
|
||||
}
|
||||
|
||||
@HostListener('document:paste', ['$event']) onPaste(ev: ClipboardEvent) {
|
||||
this._bookmarkService.createFromPaste(ev);
|
||||
@HostListener('document:paste', ['$event'])
|
||||
async onPaste(ev: ClipboardEvent) {
|
||||
if (await this.workContextService.isActiveWorkContextProject$.pipe(first()).toPromise()) {
|
||||
this._bookmarkService.createFromPaste(ev);
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:beforeinstallprompt', ['$event']) onBeforeInstallPrompt(e: any) {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ export enum LanguageCode {
|
|||
it = 'it',
|
||||
pt = 'pt',
|
||||
nl = 'nl',
|
||||
nb = 'nb',
|
||||
}
|
||||
|
||||
export enum LanguageCodeMomentMap {
|
||||
|
|
@ -68,6 +69,7 @@ export enum LanguageCodeMomentMap {
|
|||
it = 'it',
|
||||
pt = 'pt',
|
||||
nl = 'nl',
|
||||
nb = 'nb',
|
||||
zh = 'zh-cn',
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export class DataInitService {
|
|||
if (isValid) {
|
||||
this._store$.dispatch(loadAllData({appDataComplete, isOmitTokens}));
|
||||
} else {
|
||||
if (this._dataRepairService.isRepairConfirmed()) {
|
||||
if (this._dataRepairService.isRepairPossibleAndConfirmed(appDataComplete)) {
|
||||
const fixedData = this._dataRepairService.repairData(appDataComplete);
|
||||
this._store$.dispatch(loadAllData({
|
||||
appDataComplete: fixedData,
|
||||
|
|
@ -63,4 +63,5 @@ export class DataInitService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { AppDataComplete } from '../../imex/sync/sync.model';
|
|||
import { T } from '../../t.const';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { dataRepair } from './data-repair.util';
|
||||
import { isDataRepairPossible } from './is-data-repair-possible.util';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
@ -18,7 +19,11 @@ export class DataRepairService {
|
|||
return dataRepair(dataIn);
|
||||
}
|
||||
|
||||
isRepairConfirmed(): boolean {
|
||||
isRepairPossibleAndConfirmed(dataIn: AppDataComplete): boolean {
|
||||
if (!isDataRepairPossible(dataIn)) {
|
||||
alert('Data damaged, repair not possible.');
|
||||
return false;
|
||||
}
|
||||
return confirm(this._translateService.instant(T.CONFIRM.AUTO_FIX));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ describe('dataRepair()', () => {
|
|||
id: 'TEST',
|
||||
title: 'TEST',
|
||||
}]),
|
||||
})).toEqual({
|
||||
} as any)).toEqual({
|
||||
...mock,
|
||||
task: taskState,
|
||||
taskArchive: {
|
||||
|
|
@ -404,4 +404,125 @@ describe('dataRepair()', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should move archived sub tasks back to their unarchived parents', () => {
|
||||
const taskStateBefore = {
|
||||
...mock.task,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskUnarchived',
|
||||
title: 'subTaskUnarchived',
|
||||
parentId: 'parent',
|
||||
}, {
|
||||
...DEFAULT_TASK,
|
||||
id: 'parent',
|
||||
title: 'parent',
|
||||
parentId: null,
|
||||
subTaskIds: ['subTaskUnarchived']
|
||||
}])
|
||||
} as any;
|
||||
|
||||
const taskArchiveStateBefore = {
|
||||
...mock.taskArchive,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskArchived',
|
||||
title: 'subTaskArchived',
|
||||
parentId: 'parent',
|
||||
}])
|
||||
} as any;
|
||||
|
||||
expect(dataRepair({
|
||||
...mock,
|
||||
task: taskStateBefore,
|
||||
taskArchive: taskArchiveStateBefore,
|
||||
})).toEqual({
|
||||
...mock,
|
||||
task: {
|
||||
...mock.task,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskUnarchived',
|
||||
title: 'subTaskUnarchived',
|
||||
parentId: 'parent',
|
||||
}, {
|
||||
...DEFAULT_TASK,
|
||||
id: 'parent',
|
||||
title: 'parent',
|
||||
parentId: null,
|
||||
subTaskIds: ['subTaskUnarchived', 'subTaskArchived'],
|
||||
}, {
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskArchived',
|
||||
title: 'subTaskArchived',
|
||||
parentId: 'parent',
|
||||
}])
|
||||
} as any,
|
||||
taskArchive: {
|
||||
...mock.taskArchive,
|
||||
...fakeEntityStateFromArray<Task>([])
|
||||
} as any,
|
||||
});
|
||||
});
|
||||
|
||||
it('should move unarchived sub tasks to their archived parents', () => {
|
||||
const taskStateBefore = {
|
||||
...mock.task,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskUnarchived',
|
||||
title: 'subTaskUnarchived',
|
||||
parentId: 'parent',
|
||||
}])
|
||||
} as any;
|
||||
|
||||
const taskArchiveStateBefore = {
|
||||
...mock.taskArchive,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskArchived',
|
||||
title: 'subTaskArchived',
|
||||
parentId: 'parent',
|
||||
}, {
|
||||
...DEFAULT_TASK,
|
||||
id: 'parent',
|
||||
title: 'parent',
|
||||
parentId: null,
|
||||
subTaskIds: ['subTaskArchived']
|
||||
}])
|
||||
} as any;
|
||||
|
||||
expect(dataRepair({
|
||||
...mock,
|
||||
task: taskStateBefore,
|
||||
taskArchive: taskArchiveStateBefore,
|
||||
})).toEqual({
|
||||
...mock,
|
||||
task: {
|
||||
...mock.task,
|
||||
...fakeEntityStateFromArray<Task>([])
|
||||
} as any,
|
||||
taskArchive: {
|
||||
...mock.taskArchive,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskArchived',
|
||||
title: 'subTaskArchived',
|
||||
parentId: 'parent',
|
||||
}, {
|
||||
...DEFAULT_TASK,
|
||||
id: 'parent',
|
||||
title: 'parent',
|
||||
parentId: null,
|
||||
subTaskIds: ['subTaskArchived', 'subTaskUnarchived']
|
||||
}, {
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskUnarchived',
|
||||
title: 'subTaskUnarchived',
|
||||
parentId: 'parent',
|
||||
}])
|
||||
} as any,
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,17 +1,27 @@
|
|||
import { AppBaseDataEntityLikeStates, AppDataComplete } from '../../imex/sync/sync.model';
|
||||
import { TagCopy } from '../../features/tag/tag.model';
|
||||
import { ProjectCopy } from '../../features/project/project.model';
|
||||
import { isDataRepairPossible } from './is-data-repair-possible.util';
|
||||
import { TaskArchive, TaskCopy, TaskState } from '../../features/tasks/task.model';
|
||||
import { unique } from '../../util/unique';
|
||||
|
||||
const ENTITY_STATE_KEYS: (keyof AppDataComplete)[] = ['task', 'taskArchive', 'taskRepeatCfg', 'tag', 'project', 'simpleCounter'];
|
||||
|
||||
export const dataRepair = (data: AppDataComplete): AppDataComplete => {
|
||||
if (!isDataRepairPossible(data)) {
|
||||
throw new Error('Data repair attempted but not possible');
|
||||
}
|
||||
|
||||
// console.time('dataRepair');
|
||||
let dataOut: AppDataComplete = data;
|
||||
// let dataOut: AppDataComplete = dirtyDeepCopy(data);
|
||||
dataOut = _fixEntityStates(dataOut);
|
||||
dataOut = _removeMissingTasksFromListsOrRestoreFromArchive(dataOut);
|
||||
dataOut = _removeDuplicatesFromArchive(dataOut);
|
||||
dataOut = _addOrphanedTasksToProjectLists(dataOut);
|
||||
dataOut = _moveArchivedSubTasksToUnarchivedParents(dataOut);
|
||||
dataOut = _moveUnArchivedSubTasksToArchivedParents(dataOut);
|
||||
dataOut = _removeDuplicatesFromArchive(dataOut);
|
||||
|
||||
// console.timeEnd('dataRepair');
|
||||
return dataOut;
|
||||
};
|
||||
|
|
@ -43,6 +53,89 @@ const _removeDuplicatesFromArchive = (data: AppDataComplete): AppDataComplete =>
|
|||
return data;
|
||||
};
|
||||
|
||||
const _moveArchivedSubTasksToUnarchivedParents = (data: AppDataComplete): AppDataComplete => {
|
||||
// to avoid ambiguity
|
||||
const taskState: TaskState = data.task;
|
||||
const taskArchiveState: TaskArchive = data.taskArchive;
|
||||
const orhphanedArchivedSubTasks: TaskCopy[] = taskArchiveState.ids
|
||||
.map((id: string) => taskArchiveState.entities[id] as TaskCopy)
|
||||
.filter((t: TaskCopy) => t.parentId && !taskArchiveState.ids.includes(t.parentId));
|
||||
|
||||
console.log('orhphanedArchivedSubTasks', orhphanedArchivedSubTasks);
|
||||
orhphanedArchivedSubTasks.forEach((t: TaskCopy) => {
|
||||
// delete archived if duplicate
|
||||
if (taskState.ids.includes(t.id as string)) {
|
||||
taskArchiveState.ids = taskArchiveState.ids.filter(id => t.id !== id);
|
||||
delete taskArchiveState.entities[t.id];
|
||||
// if entity is empty for some reason
|
||||
if (!taskState.entities[t.id]) {
|
||||
taskState.entities[t.id] = t;
|
||||
}
|
||||
}
|
||||
// copy to today if parent exists
|
||||
else if (taskState.ids.includes(t.parentId as string)) {
|
||||
taskState.ids.push((t.id));
|
||||
taskState.entities[t.id] = t;
|
||||
const par: TaskCopy = taskState.entities[t.parentId as string] as TaskCopy;
|
||||
|
||||
par.subTaskIds = unique([...par.subTaskIds, t.id]);
|
||||
|
||||
// and delete from archive
|
||||
taskArchiveState.ids = taskArchiveState.ids.filter(id => t.id !== id);
|
||||
|
||||
delete taskArchiveState.entities[t.id];
|
||||
}
|
||||
// make main if it doesn't
|
||||
else {
|
||||
// @ts-ignore
|
||||
t.parentId = null;
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const _moveUnArchivedSubTasksToArchivedParents = (data: AppDataComplete): AppDataComplete => {
|
||||
// to avoid ambiguity
|
||||
const taskState: TaskState = data.task;
|
||||
const taskArchiveState: TaskArchive = data.taskArchive;
|
||||
const orhphanedUnArchivedSubTasks: TaskCopy[] = taskState.ids
|
||||
.map((id: string) => taskState.entities[id] as TaskCopy)
|
||||
.filter((t: TaskCopy) => t.parentId && !taskState.ids.includes(t.parentId));
|
||||
|
||||
console.log('orhphanedUnArchivedSubTasks', orhphanedUnArchivedSubTasks);
|
||||
orhphanedUnArchivedSubTasks.forEach((t: TaskCopy) => {
|
||||
// delete un-archived if duplicate
|
||||
if (taskArchiveState.ids.includes(t.id as string)) {
|
||||
taskState.ids = taskState.ids.filter(id => t.id !== id);
|
||||
delete taskState.entities[t.id];
|
||||
// if entity is empty for some reason
|
||||
if (!taskArchiveState.entities[t.id]) {
|
||||
taskArchiveState.entities[t.id] = t;
|
||||
}
|
||||
}
|
||||
// copy to archive if parent exists
|
||||
else if (taskArchiveState.ids.includes(t.parentId as string)) {
|
||||
taskArchiveState.ids.push((t.id));
|
||||
taskArchiveState.entities[t.id] = t;
|
||||
|
||||
const par: TaskCopy = taskArchiveState.entities[t.parentId as string] as TaskCopy;
|
||||
par.subTaskIds = unique([...par.subTaskIds, t.id]);
|
||||
|
||||
// and delete from today
|
||||
taskState.ids = taskState.ids.filter(id => t.id !== id);
|
||||
delete taskState.entities[t.id];
|
||||
}
|
||||
// make main if it doesn't
|
||||
else {
|
||||
// @ts-ignore
|
||||
t.parentId = null;
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const _removeMissingTasksFromListsOrRestoreFromArchive = (data: AppDataComplete): AppDataComplete => {
|
||||
const {task, project, tag, taskArchive} = data;
|
||||
const taskIds: string[] = task.ids;
|
||||
|
|
|
|||
8
src/app/core/data-repair/is-data-repair-possible.util.ts
Normal file
8
src/app/core/data-repair/is-data-repair-possible.util.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { AppDataComplete } from '../../imex/sync/sync.model';
|
||||
|
||||
export const isDataRepairPossible = (data: AppDataComplete): boolean => {
|
||||
const d: any = data as any;
|
||||
return typeof d === 'object' && d !== null
|
||||
&& typeof d.task === 'object' && d.task !== null
|
||||
&& typeof d.project === 'object' && d.project !== null;
|
||||
};
|
||||
|
|
@ -6,6 +6,20 @@ import { IS_ELECTRON } from '../../app.constants';
|
|||
import { getElectron } from '../../util/get-electron';
|
||||
import * as ElectronRenderer from 'electron/renderer';
|
||||
|
||||
// TODO make available for both
|
||||
export const getSendChannel = (channel: string) => `%better-ipc-send-channel-${channel}`;
|
||||
const getUniqueId = () => `${Date.now()}-${Math.random()}`;
|
||||
|
||||
// const getRendererSendChannel = (windowId, channel) => `%better-ipc-send-channel-${windowId}-${channel}`;
|
||||
const getResponseChannels = (channel: string) => {
|
||||
const id = getUniqueId();
|
||||
return {
|
||||
sendChannel: getSendChannel(channel),
|
||||
dataChannel: `%better-ipc-response-data-channel-${channel}-${id}`,
|
||||
errorChannel: `%better-ipc-response-error-channel-${channel}-${id}`
|
||||
};
|
||||
};
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class ElectronService {
|
||||
ipcRenderer?: typeof ipcRenderer;
|
||||
|
|
@ -57,4 +71,37 @@ export class ElectronService {
|
|||
public get process(): any {
|
||||
return this.remote ? this.remote.process : null;
|
||||
}
|
||||
|
||||
public callMain(channel: string, data: unknown) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const {sendChannel, dataChannel, errorChannel} = getResponseChannels(channel);
|
||||
|
||||
const cleanup = () => {
|
||||
(this.ipcRenderer as typeof ipcRenderer).off(dataChannel, onData);
|
||||
(this.ipcRenderer as typeof ipcRenderer).off(errorChannel, onError);
|
||||
};
|
||||
|
||||
const onData = (event: unknown, result: unknown) => {
|
||||
cleanup();
|
||||
resolve(result);
|
||||
};
|
||||
|
||||
const onError = (event: unknown, error: unknown) => {
|
||||
cleanup();
|
||||
// reject(deserializeError(error));
|
||||
reject(error);
|
||||
};
|
||||
|
||||
(this.ipcRenderer as typeof ipcRenderer).once(dataChannel, onData);
|
||||
(this.ipcRenderer as typeof ipcRenderer).once(errorChannel, onError);
|
||||
|
||||
const completeData = {
|
||||
dataChannel,
|
||||
errorChannel,
|
||||
userData: data
|
||||
};
|
||||
|
||||
(this.ipcRenderer as typeof ipcRenderer).send(sendChannel, completeData);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import { DateAdapter } from '@angular/material/core';
|
|||
import * as moment from 'moment';
|
||||
import { AUTO_SWITCH_LNGS, LanguageCode, LanguageCodeMomentMap, RTL_LANGUAGES } from '../../app.constants';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { GlobalConfigService } from 'src/app/features/config/global-config.service';
|
||||
import { map, startWith } from 'rxjs/operators';
|
||||
import { DEFAULT_GLOBAL_CONFIG } from 'src/app/features/config/default-global-config.const';
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class LanguageService {
|
||||
|
|
@ -19,6 +22,7 @@ export class LanguageService {
|
|||
private _translateService: TranslateService,
|
||||
private _dateTimeAdapter: DateTimeAdapter<unknown>,
|
||||
private _dateAdapter: DateAdapter<unknown>,
|
||||
private _globalConfigService: GlobalConfigService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -32,6 +36,15 @@ export class LanguageService {
|
|||
|
||||
setDefault(lng: LanguageCode) {
|
||||
this._translateService.setDefaultLang(lng);
|
||||
|
||||
let firstDayOfWeek = DEFAULT_GLOBAL_CONFIG.misc.firstDayOfWeek;
|
||||
this._globalConfigService.misc$.pipe(
|
||||
map(cfg => cfg.firstDayOfWeek),
|
||||
startWith(0),
|
||||
).subscribe((_firstDayOfWeek: number) => {
|
||||
firstDayOfWeek = _firstDayOfWeek;
|
||||
});
|
||||
this._dateAdapter.getFirstDayOfWeek = () => firstDayOfWeek;
|
||||
}
|
||||
|
||||
setFromBrowserLngIfAutoSwitchLng() {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ export const DEFAULT_GLOBAL_CONFIG: GlobalConfigState = {
|
|||
isTurnOffMarkdown: false,
|
||||
isAutoAddWorkedOnToToday: false,
|
||||
isDisableInitialDialog: false,
|
||||
defaultProjectId: null
|
||||
defaultProjectId: null,
|
||||
firstDayOfWeek: 0,
|
||||
},
|
||||
evaluation: {
|
||||
isHideEvaluationSheet: false,
|
||||
|
|
@ -115,6 +116,7 @@ export const DEFAULT_GLOBAL_CONFIG: GlobalConfigState = {
|
|||
},
|
||||
trackingReminder: {
|
||||
isEnabled: true,
|
||||
isShowOnMobile: false,
|
||||
minTime: minute * 2,
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export const LANGUAGE_SELECTION_FORM_FORM: ConfigFormSection<LanguageConfig> = {
|
|||
{label: T.GCF.LANG.IT, value: LanguageCode.it},
|
||||
{label: T.GCF.LANG.PT, value: LanguageCode.pt},
|
||||
{label: T.GCF.LANG.NL, value: LanguageCode.nl},
|
||||
{label: T.GCF.LANG.NB, value: LanguageCode.nb},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -70,5 +70,21 @@ export const MISC_SETTINGS_FORM_CFG: ConfigFormSection<MiscConfig> = {
|
|||
label: T.GCF.MISC.DEFAULT_PROJECT,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'firstDayOfWeek',
|
||||
type: 'select',
|
||||
templateOptions: {
|
||||
label: T.GCF.MISC.FIRST_DAY_OF_WEEK,
|
||||
options: [
|
||||
{label: T.F.TASK_REPEAT.F.SUNDAY, value: 0},
|
||||
{label: T.F.TASK_REPEAT.F.MONDAY, value: 1},
|
||||
{label: T.F.TASK_REPEAT.F.TUESDAY, value: 2},
|
||||
{label: T.F.TASK_REPEAT.F.WEDNESDAY, value: 3},
|
||||
{label: T.F.TASK_REPEAT.F.THURSDAY, value: 4},
|
||||
{label: T.F.TASK_REPEAT.F.FRIDAY, value: 5},
|
||||
{label: T.F.TASK_REPEAT.F.SATURDAY, value: 6},
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@ export const TRACKING_REMINDER_FORM_CFG: ConfigFormSection<TrackingReminderConfi
|
|||
label: T.GCF.TRACKING_REMINDER.L_IS_ENABLED,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'isShowOnMobile',
|
||||
type: 'checkbox',
|
||||
templateOptions: {
|
||||
label: T.GCF.TRACKING_REMINDER.L_IS_SHOW_ON_MOBILE,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'minTime',
|
||||
type: 'duration',
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ export type MiscConfig = Readonly<{
|
|||
isAutoAddWorkedOnToToday: boolean;
|
||||
isDisableInitialDialog: boolean;
|
||||
defaultProjectId: string | null;
|
||||
firstDayOfWeek: number;
|
||||
}>;
|
||||
|
||||
export type EvaluationConfig = Readonly<{
|
||||
|
|
@ -127,6 +128,7 @@ export type SoundConfig = Readonly<{
|
|||
|
||||
export type TrackingReminderConfig = Readonly<{
|
||||
isEnabled: boolean;
|
||||
isShowOnMobile: boolean;
|
||||
minTime: number;
|
||||
}>;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
[id]="id"
|
||||
[readonly]="to.readonly"
|
||||
matNativeControl>
|
||||
<option [ngValue]="null">{{T.G.NONE|translate}}</option>
|
||||
<option [ngValue]="T.G.NONE || ''">{{T.G.NONE | translate}}</option>
|
||||
<ng-container *ngFor="let opt of projectService.list$|async; trackBy: trackById">
|
||||
<option [ngValue]="opt.id">{{ opt.title }}</option>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export const mapToSearchResults = (res: any): SearchResultItem[] => {
|
|||
issueData: {
|
||||
...issue,
|
||||
summary: issue.summaryText,
|
||||
// NOTE THIS
|
||||
// NOTE: we always use the key, because it allows us to create the right link
|
||||
id: issue.key,
|
||||
},
|
||||
};
|
||||
|
|
@ -47,7 +47,8 @@ export const mapIssue = (issue: JiraIssueOriginal, cfg: JiraCfg): JiraIssue => {
|
|||
|
||||
return {
|
||||
key: issueCopy.key,
|
||||
id: issueCopy.id,
|
||||
// NOTE: we always use the key, because it allows us to create the right link
|
||||
id: issueCopy.key,
|
||||
components: fields.components,
|
||||
timeestimate: fields.timeestimate,
|
||||
timespent: fields.timespent,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { NoteModule } from '../note/note.module';
|
|||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { IS_ELECTRON } from '../../app.constants';
|
||||
import { TasksModule } from '../tasks/tasks.module';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { concatMap, filter, first } from 'rxjs/operators';
|
||||
import { Reminder } from './reminder.model';
|
||||
import { UiHelperService } from '../ui-helper/ui-helper.service';
|
||||
import { NotifyService } from '../../core/notify/notify.service';
|
||||
|
|
@ -13,6 +13,10 @@ import { DialogViewNoteReminderComponent } from '../note/dialog-view-note-remind
|
|||
import { DialogViewTaskRemindersComponent } from '../tasks/dialog-view-task-reminders/dialog-view-task-reminders.component';
|
||||
import { DataInitService } from '../../core/data-init/data-init.service';
|
||||
import { throttle } from 'helpful-decorators';
|
||||
import { merge, timer } from 'rxjs';
|
||||
import { SyncService } from '../../imex/sync/sync.service';
|
||||
|
||||
const MAX_WAIT_FOR_INITIAL_SYNC = 25000;
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
|
|
@ -29,10 +33,22 @@ export class ReminderModule {
|
|||
private readonly _uiHelperService: UiHelperService,
|
||||
private readonly _notifyService: NotifyService,
|
||||
private readonly _dataInitService: DataInitService,
|
||||
private readonly _syncService: SyncService,
|
||||
) {
|
||||
this._dataInitService.isAllDataLoadedInitially$.subscribe(() => {
|
||||
_reminderService.init();
|
||||
});
|
||||
|
||||
this._dataInitService.isAllDataLoadedInitially$.pipe(concatMap(() =>
|
||||
|
||||
// we do this to wait for syncing and the like
|
||||
merge(
|
||||
this._syncService.afterInitialSyncDoneAndDataLoadedInitially$,
|
||||
timer(MAX_WAIT_FOR_INITIAL_SYNC),
|
||||
).pipe(
|
||||
first(),
|
||||
)))
|
||||
.subscribe(async () => {
|
||||
_reminderService.init();
|
||||
});
|
||||
|
||||
this._reminderService.onRemindersActive$.pipe(
|
||||
// NOTE: we simply filter for open dialogs, as reminders are re-queried quite often
|
||||
filter((reminder) => this._matDialog.openDialogs.length === 0 && !!reminder && reminder.length > 0),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { PersistenceService } from '../../core/persistence/persistence.service';
|
|||
import { RecurringConfig, Reminder, ReminderCopy, ReminderType } from './reminder.model';
|
||||
import { SnackService } from '../../core/snack/snack.service';
|
||||
import * as shortid from 'shortid';
|
||||
import { BehaviorSubject, merge, Observable, ReplaySubject, Subject, timer } from 'rxjs';
|
||||
import { BehaviorSubject, Observable, ReplaySubject, Subject } from 'rxjs';
|
||||
import { dirtyDeepCopy } from '../../util/dirtyDeepCopy';
|
||||
import { ImexMetaService } from '../../imex/imex-meta/imex-meta.service';
|
||||
import { TaskService } from '../tasks/task.service';
|
||||
|
|
@ -11,14 +11,12 @@ import { Note } from '../note/note.model';
|
|||
import { Task } from '../tasks/task.model';
|
||||
import { NoteService } from '../note/note.service';
|
||||
import { T } from '../../t.const';
|
||||
import { SyncService } from '../../imex/sync/sync.service';
|
||||
import { filter, first, map, skipUntil } from 'rxjs/operators';
|
||||
import { filter, map, skipUntil } from 'rxjs/operators';
|
||||
import { migrateReminders } from './migrate-reminder.util';
|
||||
import { WorkContextService } from '../work-context/work-context.service';
|
||||
import { devError } from '../../util/dev-error';
|
||||
import { WorkContextType } from '../work-context/work-context.model';
|
||||
|
||||
const MAX_WAIT_FOR_INITIAL_SYNC = 25000;
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
|
@ -45,7 +43,6 @@ export class ReminderService {
|
|||
|
||||
constructor(
|
||||
private readonly _workContextService: WorkContextService,
|
||||
private readonly _syncService: SyncService,
|
||||
private readonly _persistenceService: PersistenceService,
|
||||
private readonly _snackService: SnackService,
|
||||
private readonly _taskService: TaskService,
|
||||
|
|
@ -67,19 +64,11 @@ export class ReminderService {
|
|||
});
|
||||
}
|
||||
|
||||
init() {
|
||||
// we do this to wait for syncing and the like
|
||||
merge(
|
||||
this._syncService.afterInitialSyncDoneAndDataLoadedInitially$,
|
||||
timer(MAX_WAIT_FOR_INITIAL_SYNC),
|
||||
).pipe(
|
||||
first(),
|
||||
).subscribe(async () => {
|
||||
this._w.addEventListener('message', this._onReminderActivated.bind(this));
|
||||
this._w.addEventListener('error', this._handleError.bind(this));
|
||||
await this.reloadFromDatabase();
|
||||
this._isRemindersLoaded$.next(true);
|
||||
});
|
||||
async init() {
|
||||
this._w.addEventListener('message', this._onReminderActivated.bind(this));
|
||||
this._w.addEventListener('error', this._handleError.bind(this));
|
||||
await this.reloadFromDatabase();
|
||||
this._isRemindersLoaded$.next(true);
|
||||
}
|
||||
|
||||
async reloadFromDatabase() {
|
||||
|
|
|
|||
|
|
@ -184,6 +184,18 @@ describe('shortSyntax', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should not add tags for sub tasks', () => {
|
||||
const t = {
|
||||
...TASK,
|
||||
parentId: 'SOMEPARENT',
|
||||
title: 'Fun title #blu #idontexist',
|
||||
tagIds: []
|
||||
};
|
||||
const r = shortSyntax(t, ALL_TAGS);
|
||||
|
||||
expect(r).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('should work with all combined', () => {
|
||||
|
|
|
|||
|
|
@ -112,6 +112,10 @@ const parseProjectChanges = (task: Partial<TaskCopy>, allProjects?: Project[]):
|
|||
const parseTagChanges = (task: Partial<TaskCopy>, allTags?: Tag[]): { taskChanges: Partial<TaskCopy>, newTagTitlesToCreate: string[] } => {
|
||||
const taskChanges: Partial<TaskCopy> = {};
|
||||
|
||||
if (task.parentId) {
|
||||
return {taskChanges, newTagTitlesToCreate: []};
|
||||
}
|
||||
|
||||
const newTagTitlesToCreate: string[] = [];
|
||||
// only exec if previous ones are also passed
|
||||
if (Array.isArray(task.tagIds) && Array.isArray(allTags)) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export interface TimeSpentOnDayCopy {
|
|||
}
|
||||
|
||||
export interface TaskArchive extends EntityState<ArchiveTask> {
|
||||
ids: string[];
|
||||
// additional entities state properties
|
||||
[MODEL_VERSION_KEY]?: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ export class TaskService {
|
|||
|
||||
startFirstStartable() {
|
||||
this._workContextService.startableTasks$.pipe(take(1)).subscribe(tasks => {
|
||||
if (tasks[0]) {
|
||||
if (tasks[0] && !this.currentTaskId) {
|
||||
this.setCurrentId(tasks[0].id);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { getWorklogStr } from '../../../util/get-work-log-str';
|
|||
import { T } from '../../../t.const';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { TrackingReminderConfig } from '../../config/global-config.model';
|
||||
import { IS_TOUCH_ONLY } from '../../../util/is-touch';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
@ -27,14 +28,19 @@ export class TrackingReminderService {
|
|||
_manualReset$: Subject<void> = new Subject();
|
||||
|
||||
_resetableCounter$: Observable<number> = merge(
|
||||
of(true),
|
||||
of('INITIAL'),
|
||||
this._manualReset$,
|
||||
).pipe(
|
||||
switchMap(() => this._counter$),
|
||||
);
|
||||
|
||||
_hideTrigger$: Observable<any> = merge(
|
||||
this._taskService.currentTaskId$.pipe(filter(currentId => !!currentId)),
|
||||
this._idleService.isIdle$.pipe(filter(isIdle => isIdle)),
|
||||
);
|
||||
|
||||
remindCounter$: Observable<number> = this._cfg$.pipe(
|
||||
switchMap((cfg) => !cfg.isEnabled
|
||||
switchMap((cfg) => !cfg.isEnabled || (!cfg.isShowOnMobile && IS_TOUCH_ONLY)
|
||||
? EMPTY
|
||||
: combineLatest([
|
||||
this._taskService.currentTaskId$,
|
||||
|
|
@ -66,6 +72,14 @@ export class TrackingReminderService {
|
|||
this.remindCounter$.subscribe((count) => {
|
||||
this._triggerBanner(count, {});
|
||||
});
|
||||
|
||||
this._hideTrigger$.subscribe((v) => {
|
||||
this._hideBanner();
|
||||
});
|
||||
}
|
||||
|
||||
private _hideBanner() {
|
||||
this._bannerService.dismiss(BannerId.StartTrackingReminder);
|
||||
}
|
||||
|
||||
private _triggerBanner(duration: number, cfg: any) {
|
||||
|
|
|
|||
|
|
@ -226,28 +226,26 @@ export class WorkContextService {
|
|||
map(([today, backlog]) => [...today, ...backlog])
|
||||
);
|
||||
|
||||
// TODO make it more efficient
|
||||
startableTasks$: Observable<Task[]> = combineLatest([
|
||||
this.activeWorkContext$,
|
||||
this._store$.pipe(
|
||||
select(selectTaskEntities),
|
||||
)
|
||||
]).pipe(
|
||||
switchMap(([activeContext, entities]) => {
|
||||
const taskIds = activeContext.taskIds;
|
||||
return of(
|
||||
(Object.keys(entities)
|
||||
.filter((id) => {
|
||||
const t = entities[id] as Task;
|
||||
return !t.isDone && (
|
||||
(t.parentId)
|
||||
? (taskIds.includes(t.parentId))
|
||||
: (taskIds.includes(id) && (!t.subTaskIds || t.subTaskIds.length === 0))
|
||||
);
|
||||
})
|
||||
.map(key => entities[key]) as Task[])
|
||||
);
|
||||
})
|
||||
map(([activeContext, entities]) => {
|
||||
let startableTasks: Task[] = [];
|
||||
activeContext.taskIds.forEach(id => {
|
||||
const task: Task | undefined = entities[id];
|
||||
if (!task) throw new Error('Task not found');
|
||||
|
||||
if (task.subTaskIds && task.subTaskIds.length) {
|
||||
startableTasks = startableTasks.concat(task.subTaskIds.map(sid => entities[sid] as Task));
|
||||
} else {
|
||||
startableTasks.push(task);
|
||||
}
|
||||
});
|
||||
return startableTasks.filter(task => !task.isDone);
|
||||
}),
|
||||
);
|
||||
|
||||
workingToday$: Observable<any> = this.getTimeWorkedForDay$(getWorklogStr());
|
||||
|
|
|
|||
25
src/app/imex/local-backup/local-backup.effects.spec.ts
Normal file
25
src/app/imex/local-backup/local-backup.effects.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// import { TestBed } from '@angular/core/testing';
|
||||
// import { provideMockActions } from '@ngrx/effects/testing';
|
||||
// import { Observable } from 'rxjs';
|
||||
//
|
||||
// import { LocalBackupEffects } from './local-backup.effects';
|
||||
//
|
||||
// describe('LocalBackupEffects', () => {
|
||||
// let actions$: Observable<any>;
|
||||
// let effects: LocalBackupEffects;
|
||||
//
|
||||
// beforeEach(() => {
|
||||
// TestBed.configureTestingModule({
|
||||
// providers: [
|
||||
// LocalBackupEffects,
|
||||
// provideMockActions(() => actions$)
|
||||
// ]
|
||||
// });
|
||||
//
|
||||
// effects = TestBed.inject(LocalBackupEffects);
|
||||
// });
|
||||
//
|
||||
// it('should be created', () => {
|
||||
// expect(effects).toBeTruthy();
|
||||
// });
|
||||
// });
|
||||
58
src/app/imex/local-backup/local-backup.effects.ts
Normal file
58
src/app/imex/local-backup/local-backup.effects.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import { take, tap } from 'rxjs/operators';
|
||||
import { loadAllData } from '../../root-store/meta/load-all-data.action';
|
||||
import { AppDataComplete } from '../sync/sync.model';
|
||||
import { IS_ELECTRON } from '../../app.constants';
|
||||
import { LocalBackupService } from './local-backup.service';
|
||||
import { DataImportService } from '../sync/data-import.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { T } from '../../t.const';
|
||||
import * as moment from 'moment';
|
||||
|
||||
@Injectable()
|
||||
export class LocalBackupEffects {
|
||||
|
||||
checkForBackupIfNoTasks$: any = createEffect(() => this._actions$.pipe(
|
||||
ofType(
|
||||
loadAllData
|
||||
),
|
||||
take(1),
|
||||
tap(({appDataComplete}) => {
|
||||
console.log(appDataComplete);
|
||||
this._checkForBackupIfEmpty(appDataComplete);
|
||||
})
|
||||
), {dispatch: false});
|
||||
|
||||
constructor(
|
||||
private _actions$: Actions,
|
||||
private _localBackupService: LocalBackupService,
|
||||
private _dataImportService: DataImportService,
|
||||
private _translateService: TranslateService,
|
||||
) {
|
||||
}
|
||||
|
||||
private async _checkForBackupIfEmpty(appDataComplete: AppDataComplete) {
|
||||
console.log(IS_ELECTRON, appDataComplete);
|
||||
if (IS_ELECTRON) {
|
||||
if (appDataComplete.task.ids.length === 0 && appDataComplete.taskArchive.ids.length === 0) {
|
||||
const backupMeta = await this._localBackupService.isBackupAvailable();
|
||||
if (backupMeta) {
|
||||
console.log('backupMeta', backupMeta);
|
||||
if (confirm(this._translateService.instant(T.CONFIRM.RESTORE_FILE_BACKUP, {
|
||||
dir: backupMeta.folder,
|
||||
from: this._formatDate(backupMeta.created),
|
||||
}))) {
|
||||
const backupData = await this._localBackupService.loadBackup(backupMeta.path);
|
||||
console.log('backupData', backupData);
|
||||
await this._dataImportService.importCompleteSyncData(JSON.parse(backupData));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _formatDate(date: Date | string | number) {
|
||||
return moment(date).format('DD-MM-YYYY, hh:mm:ss');
|
||||
}
|
||||
}
|
||||
6
src/app/imex/local-backup/local-backup.model.ts
Normal file
6
src/app/imex/local-backup/local-backup.model.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export interface LocalBackupMeta {
|
||||
folder: string;
|
||||
path: string;
|
||||
name: string;
|
||||
created: number;
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { LocalBackupService } from './local-backup.service';
|
||||
import { IS_ELECTRON } from '../../app.constants';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { LocalBackupEffects } from './local-backup.effects';
|
||||
|
||||
@NgModule({
|
||||
providers: [LocalBackupService],
|
||||
imports: [EffectsModule.forFeature([LocalBackupEffects])],
|
||||
})
|
||||
export class LocalBackupModule {
|
||||
constructor(private _localBackupService: LocalBackupService) {
|
||||
|
|
@ -12,4 +15,6 @@ export class LocalBackupModule {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ import { GlobalConfigService } from '../../features/config/global-config.service
|
|||
import { interval, Observable } from 'rxjs';
|
||||
import { LocalBackupConfig } from '../../features/config/global-config.model';
|
||||
import { filter, map, switchMap, tap } from 'rxjs/operators';
|
||||
import { DataImportService } from '../sync/data-import.service';
|
||||
import { IPC } from '../../../../electron/ipc-events.const';
|
||||
import { ElectronService } from '../../core/electron/electron.service';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { PersistenceService } from '../../core/persistence/persistence.service';
|
||||
import { LocalBackupMeta } from './local-backup.model';
|
||||
|
||||
const DEFAULT_BACKUP_INTERVAL = 2 * 60 * 1000;
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ export class LocalBackupService {
|
|||
|
||||
constructor(
|
||||
private _configService: GlobalConfigService,
|
||||
private _dataImportService: DataImportService,
|
||||
private _persistenceService: PersistenceService,
|
||||
private _electronService: ElectronService,
|
||||
) {
|
||||
}
|
||||
|
|
@ -32,8 +33,16 @@ export class LocalBackupService {
|
|||
this._triggerBackups.subscribe();
|
||||
}
|
||||
|
||||
isBackupAvailable(): Promise<false | LocalBackupMeta> {
|
||||
return this._electronService.callMain(IPC.BACKUP_IS_AVAILABLE, null) as Promise<false | LocalBackupMeta>;
|
||||
}
|
||||
|
||||
loadBackup(backupPath: string): Promise<string> {
|
||||
return this._electronService.callMain(IPC.BACKUP_LOAD_DATA, backupPath) as Promise<string>;
|
||||
}
|
||||
|
||||
private async _backup() {
|
||||
const data = await this._dataImportService.getCompleteSyncData();
|
||||
const data = await this._persistenceService.loadComplete();
|
||||
(this._electronService.ipcRenderer as typeof ipcRenderer).send(IPC.BACKUP, data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export class DataImportService {
|
|||
await this._importBackup();
|
||||
this._imexMetaService.setDataImportInProgress(false);
|
||||
}
|
||||
} else if (this._dataRepairService.isRepairConfirmed()) {
|
||||
} else if (this._dataRepairService.isRepairPossibleAndConfirmed(data)) {
|
||||
const fixedData = this._dataRepairService.repairData(data);
|
||||
await this.importCompleteSyncData(fixedData, isBackupReload, true);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,76 @@ describe('isValidAppData()', () => {
|
|||
})).toThrowError(`Inconsistent Task State: Missing task id goneTag for Project/Tag TEST_TAG`);
|
||||
});
|
||||
|
||||
it('orphaned archived sub tasks', () => {
|
||||
const taskState = {
|
||||
...mock.task,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskUnarchived',
|
||||
title: 'subTaskUnarchived',
|
||||
parentId: 'parent',
|
||||
}, {
|
||||
...DEFAULT_TASK,
|
||||
id: 'parent',
|
||||
title: 'parent',
|
||||
parentId: null,
|
||||
subTaskIds: ['subTaskUnarchived']
|
||||
}])
|
||||
} as any;
|
||||
|
||||
const taskArchiveState = {
|
||||
...mock.taskArchive,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskArchived',
|
||||
title: 'subTaskArchived',
|
||||
parentId: 'parent',
|
||||
}])
|
||||
} as any;
|
||||
|
||||
expect(() => isValidAppData({
|
||||
...mock,
|
||||
// NOTE: it's empty
|
||||
task: taskState,
|
||||
taskArchive: taskArchiveState,
|
||||
})).toThrowError(`Inconsistent Task State: Lonely Sub Task in Archive`);
|
||||
});
|
||||
|
||||
it('orphaned today sub tasks', () => {
|
||||
const taskState = {
|
||||
...mock.task,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskUnarchived',
|
||||
title: 'subTaskUnarchived',
|
||||
parentId: 'parent',
|
||||
}])
|
||||
} as any;
|
||||
|
||||
const taskArchiveState = {
|
||||
...mock.taskArchive,
|
||||
...fakeEntityStateFromArray<Task>([{
|
||||
...DEFAULT_TASK,
|
||||
id: 'subTaskArchived',
|
||||
title: 'subTaskArchived',
|
||||
parentId: 'parent',
|
||||
}, {
|
||||
...DEFAULT_TASK,
|
||||
id: 'parent',
|
||||
title: 'parent',
|
||||
parentId: null,
|
||||
subTaskIds: ['subTaskArchived']
|
||||
}])
|
||||
} as any;
|
||||
|
||||
expect(() => isValidAppData({
|
||||
...mock,
|
||||
// NOTE: it's empty
|
||||
task: taskState,
|
||||
taskArchive: taskArchiveState,
|
||||
})).toThrowError(`Inconsistent Task State: Lonely Sub Task in Today`);
|
||||
});
|
||||
|
||||
xit('missing tag for task', () => {
|
||||
expect(() => isValidAppData({
|
||||
...mock,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { isEntityStateConsistent } from '../../util/check-fix-entity-state-consi
|
|||
import { devError } from '../../util/dev-error';
|
||||
import { Tag } from '../../features/tag/tag.model';
|
||||
import { Project } from '../../features/project/project.model';
|
||||
import { Task } from '../../features/tasks/task.model';
|
||||
|
||||
export const isValidAppData = (d: AppDataComplete, isSkipInconsistentTaskStateError = false): boolean => {
|
||||
const dAny: any = d;
|
||||
|
|
@ -31,7 +32,10 @@ export const isValidAppData = (d: AppDataComplete, isSkipInconsistentTaskStateEr
|
|||
&& typeof dAny.project === 'object' && dAny.project !== null
|
||||
&& Array.isArray(d.reminders)
|
||||
&& _isEntityStatesConsistent(d)
|
||||
&& (isSkipInconsistentTaskStateError || _isAllTasksAvailable(d))
|
||||
&& (isSkipInconsistentTaskStateError ||
|
||||
_isAllTasksAvailable(d)
|
||||
&& _isNoLonelySubTasks(d)
|
||||
)
|
||||
|
||||
: typeof dAny === 'object'
|
||||
;
|
||||
|
|
@ -103,7 +107,7 @@ const _isEntityStatesConsistent = (data: AppDataComplete): boolean => {
|
|||
||
|
||||
projectStateKeys.find(projectModelKey => {
|
||||
const dataForProjects = data[projectModelKey];
|
||||
if (typeof dataForProjects !== 'object') {
|
||||
if (typeof (dataForProjects as any) !== 'object') {
|
||||
throw new Error('No dataForProjects');
|
||||
}
|
||||
return Object.keys(dataForProjects).find(projectId =>
|
||||
|
|
@ -116,3 +120,26 @@ const _isEntityStatesConsistent = (data: AppDataComplete): boolean => {
|
|||
|
||||
return !brokenItem;
|
||||
};
|
||||
|
||||
const _isNoLonelySubTasks = (data: AppDataComplete): boolean => {
|
||||
let isValid: boolean = true;
|
||||
data.task.ids.forEach((id: string) => {
|
||||
const t: Task = data.task.entities[id] as Task;
|
||||
if (t.parentId && !data.task.ids.includes(t.parentId)) {
|
||||
console.log(t);
|
||||
devError(`Inconsistent Task State: Lonely Sub Task in Today`);
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
data.taskArchive.ids.forEach((id: string) => {
|
||||
const t: Task = data.taskArchive.entities[id] as Task;
|
||||
if (t.parentId && !data.taskArchive.ids.includes(t.parentId)) {
|
||||
console.log(t);
|
||||
devError(`Inconsistent Task State: Lonely Sub Task in Archive`);
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
return isValid;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ export const T = {
|
|||
'CONFIRM': {
|
||||
'AUTO_FIX': 'CONFIRM.AUTO_FIX',
|
||||
'DELETE_STRAY_BACKUP': 'CONFIRM.DELETE_STRAY_BACKUP',
|
||||
'RESTORE_STRAY_BACKUP': 'CONFIRM.RESTORE_STRAY_BACKUP'
|
||||
'RESTORE_STRAY_BACKUP': 'CONFIRM.RESTORE_STRAY_BACKUP',
|
||||
'RESTORE_FILE_BACKUP': 'CONFIRM.RESTORE_FILE_BACKUP'
|
||||
},
|
||||
'DATETIME_INPUT': {
|
||||
'IN': 'DATETIME_INPUT.IN',
|
||||
|
|
@ -938,6 +939,7 @@ export const T = {
|
|||
'JA': 'GCF.LANG.JA',
|
||||
'KO': 'GCF.LANG.KO',
|
||||
'LABEL': 'GCF.LANG.LABEL',
|
||||
'NB': 'GCF.LANG.NB',
|
||||
'NL': 'GCF.LANG.NL',
|
||||
'PT': 'GCF.LANG.PT',
|
||||
'RU': 'GCF.LANG.RU',
|
||||
|
|
@ -957,7 +959,8 @@ export const T = {
|
|||
'IS_HIDE_NAV': 'GCF.MISC.IS_HIDE_NAV',
|
||||
'IS_NOTIFY_WHEN_TIME_ESTIMATE_EXCEEDED': 'GCF.MISC.IS_NOTIFY_WHEN_TIME_ESTIMATE_EXCEEDED',
|
||||
'IS_TURN_OFF_MARKDOWN': 'GCF.MISC.IS_TURN_OFF_MARKDOWN',
|
||||
'TITLE': 'GCF.MISC.TITLE'
|
||||
'TITLE': 'GCF.MISC.TITLE',
|
||||
'FIRST_DAY_OF_WEEK': 'GCF.MISC.FIRST_DAY_OF_WEEK'
|
||||
},
|
||||
'POMODORO': {
|
||||
'BREAK_DURATION': 'GCF.POMODORO.BREAK_DURATION',
|
||||
|
|
@ -994,6 +997,7 @@ export const T = {
|
|||
'HELP': 'GCF.TRACKING_REMINDER.HELP',
|
||||
'TITLE': 'GCF.TRACKING_REMINDER.TITLE',
|
||||
'L_IS_ENABLED': 'GCF.TRACKING_REMINDER.L_IS_ENABLED',
|
||||
'L_IS_SHOW_ON_MOBILE': 'GCF.TRACKING_REMINDER.L_IS_SHOW_ON_MOBILE',
|
||||
'L_MIN_TIME': 'GCF.TRACKING_REMINDER.L_MIN_TIME'
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@
|
|||
[sPlaceholder]="T.DATETIME_SCHEDULE.PLACEHOLDER|translate"
|
||||
[sPressEnterToSubmit]="T.DATETIME_SCHEDULE.PRESS_ENTER_AGAIN|translate"
|
||||
[sTomorrow]="T.DATETIME_SCHEDULE.TOMORROW|translate"
|
||||
[firstDayOfWeek]="(firstDayOfWeek$|async)"
|
||||
name="owlDate"
|
||||
ngDefaultControl></owl-date-time-inline>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, startWith } from 'rxjs/operators';
|
||||
import { GlobalConfigService } from 'src/app/features/config/global-config.service';
|
||||
import { T } from 'src/app/t.const';
|
||||
|
||||
@Component({
|
||||
|
|
@ -31,7 +34,12 @@ export class OwlWrapperComponent {
|
|||
'23:30',
|
||||
];
|
||||
|
||||
constructor() {
|
||||
firstDayOfWeek$: Observable<number> = this._globalConfigService.misc$.pipe(
|
||||
map(cfg => cfg.firstDayOfWeek),
|
||||
startWith(0),
|
||||
);
|
||||
|
||||
constructor(private _globalConfigService: GlobalConfigService) {
|
||||
}
|
||||
|
||||
@Input('dateTime')
|
||||
|
|
|
|||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "اليابانية",
|
||||
"KO": "الكورية",
|
||||
"LABEL": "يرجى تحديد لغة",
|
||||
"NB": "النرويجية بوكمال",
|
||||
"NL": "هولندي",
|
||||
"PT": "البرتغالية",
|
||||
"RU": "الروسية",
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "Verwerfen",
|
||||
"DO_IT": "TU es!",
|
||||
"EDIT": "Bearbeiten",
|
||||
"EXTENSION_INFO": "Bitte <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> laden Sie die Chrome-Erweiterung</a> herunter, um die Kommunikation mit dem Jira Api und Idle Time Handling zu ermöglichen. Beachten Sie, dass dies für Handys nicht funktioniert.",
|
||||
"EXTENSION_INFO": "Bitte <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> laden Sie die Chrome-Erweiterung</a> herunter, um die Kommunikation mit dem Jira Api und Idle Time Handling zu ermöglichen. Beachten Sie, dass dies für Handys nicht funktioniert.",
|
||||
"LOGIN": "Anmeldung",
|
||||
"LOGOUT": "Ausloggen",
|
||||
"MINUTES": "{{m}} Minuten",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "Japanisch",
|
||||
"KO": "Koreanisch",
|
||||
"LABEL": "Bitte wähle eine Sprache",
|
||||
"NB": "Norwegischer Bokmål",
|
||||
"NL": "Niederländisch",
|
||||
"PT": "Portugiesisch",
|
||||
"RU": "Russisch",
|
||||
|
|
@ -941,7 +942,8 @@
|
|||
"IS_HIDE_NAV": "Navigation verbergen, bis die Hauptüberschrift angezeigt wird (nur Desktop)",
|
||||
"IS_NOTIFY_WHEN_TIME_ESTIMATE_EXCEEDED": "Benachrichtigen, wenn die geschätzte Zeit überschritten wurde",
|
||||
"IS_TURN_OFF_MARKDOWN": "Deaktivieren Sie das Markdown-Parsing für Notizen",
|
||||
"TITLE": "Verschiedene Einstellungen"
|
||||
"TITLE": "Verschiedene Einstellungen",
|
||||
"FIRST_DAY_OF_WEEK": "Erster Tag der Woche"
|
||||
},
|
||||
"POMODORO": {
|
||||
"BREAK_DURATION": "Dauer der kurzen Pausen",
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
"CONFIRM": {
|
||||
"AUTO_FIX": "Your data seems to be damaged. Do you want to try to automatically fix it? This might result in partial data loss.",
|
||||
"DELETE_STRAY_BACKUP": "Do you want to delete the back to avoid seeing this dialog?",
|
||||
"RESTORE_STRAY_BACKUP": "During last sync there might have been some error. Do you want to restore the last backup?"
|
||||
"RESTORE_STRAY_BACKUP": "During last sync there might have been some error. Do you want to restore the last backup?",
|
||||
"RESTORE_FILE_BACKUP": "There seems to be NO DATA, but there are backups available at \"{{dir}}\". Do you want to restore the latest backup from {{from}}?"
|
||||
},
|
||||
"DATETIME_INPUT": {
|
||||
"IN": "in {{time}}",
|
||||
|
|
@ -842,7 +843,7 @@
|
|||
"DISMISS": "Dismiss",
|
||||
"DO_IT": "Do it!",
|
||||
"EDIT": "Edit",
|
||||
"EXTENSION_INFO": "Please <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> download the chrome extension</a> in order to allow communication with the Jira Api and Idle Time Handling. Note that this doesn't work for mobile.",
|
||||
"EXTENSION_INFO": "Please <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> download the chrome extension</a> in order to allow communication with the Jira Api and Idle Time Handling. Note that this doesn't work for mobile.",
|
||||
"LOGIN": "Login",
|
||||
"LOGOUT": "Logout",
|
||||
"MINUTES": "{{m}} minutes",
|
||||
|
|
@ -938,6 +939,7 @@
|
|||
"JA": "Japanese",
|
||||
"KO": "Korean",
|
||||
"LABEL": "Please select a language",
|
||||
"NB": "Norwegian Bokmål",
|
||||
"NL": "Dutch",
|
||||
"PT": "Portuguese",
|
||||
"RU": "Russian",
|
||||
|
|
@ -957,7 +959,8 @@
|
|||
"IS_HIDE_NAV": "Hide navigation until main header is hovered (desktop only)",
|
||||
"IS_NOTIFY_WHEN_TIME_ESTIMATE_EXCEEDED": "Notify when time estimate was exceeded",
|
||||
"IS_TURN_OFF_MARKDOWN": "Turn off markdown parsing for notes",
|
||||
"TITLE": "Misc Settings"
|
||||
"TITLE": "Misc Settings",
|
||||
"FIRST_DAY_OF_WEEK": "First day of the week"
|
||||
},
|
||||
"POMODORO": {
|
||||
"BREAK_DURATION": "Duration of short breaks",
|
||||
|
|
@ -994,6 +997,7 @@
|
|||
"HELP": "Configure a banner to show up in case you forgot to start time tracking.",
|
||||
"TITLE": "Time Tracking Reminder",
|
||||
"L_IS_ENABLED": "Enabled",
|
||||
"L_IS_SHOW_ON_MOBILE": "Show on mobile app",
|
||||
"L_MIN_TIME": "Time to wait before showing Banner"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
"APP": {
|
||||
"B_INSTALL": {
|
||||
"IGNORE": "Ignorar",
|
||||
"INSTALL": "instalar",
|
||||
"MSG": "¿Desea instalar Super Productividad como PWA?"
|
||||
"INSTALL": "Instalar",
|
||||
"MSG": "¿Deseas instalar Super Productivity como una PWA?"
|
||||
},
|
||||
"B_OFFLINE": "Estás desconectado de internet. Sincronizar y solicitar datos del proveedor de problemas no funcionará.",
|
||||
"B_OFFLINE": "Estás desconectado de internet. La sincronización y solicitud de datos del proveedor no funcionarán.",
|
||||
"D_INITIAL": {
|
||||
"TITLE": "Bienvenido a v{{nr}}"
|
||||
},
|
||||
"UPDATE_MAIN_MODEL": "¡Super Productivity ha recibido una actualización importante! Se requieren algunas migraciones para sus datos. Tenga en cuenta que esto hace que sus datos sean incompatibles con versiones anteriores de la aplicación.",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "No se eligió ninguna actualización del modelo. Tenga en cuenta que, si no desea realizar la actualización del modelo, debe bajar a la última versión.",
|
||||
"UPDATE_MAIN_MODEL": "¡Super Productivity ha recibido una actualización importante! Se requieren algunas migraciones de tus datos. Ten en cuenta que esto hace que tus datos sean incompatibles con versiones anteriores de la aplicación.",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "No se eligió ninguna actualización del modelo. Ten en cuenta que, si no deseas realizar la actualización del modelo, debes descargar la última versión.",
|
||||
"UPDATE_WEB_APP": "Nueva versión disponible. ¿Cargar nueva versión?"
|
||||
},
|
||||
"BL": {
|
||||
|
|
@ -23,21 +23,21 @@
|
|||
"DATETIME_SCHEDULE": {
|
||||
"LATER_TODAY": "Mas tarde, hoy",
|
||||
"NEXT_WEEK": "La próxima semana",
|
||||
"PLACEHOLDER": "Por favor seleccione una fecha",
|
||||
"PRESS_ENTER_AGAIN": "Presione enter nuevamente para guardar",
|
||||
"PLACEHOLDER": "Selecciona una fecha",
|
||||
"PRESS_ENTER_AGAIN": "Presiona enter nuevamente para guardar",
|
||||
"TOMORROW": "mañana"
|
||||
},
|
||||
"F": {
|
||||
"ATTACHMENT": {
|
||||
"DIALOG_EDIT": {
|
||||
"ADD_ATTACHMENT": "Añadir un adjunto",
|
||||
"ADD_ATTACHMENT": "Agregar un adjunto",
|
||||
"EDIT_ATTACHMENT": "Editar adjunto",
|
||||
"LABELS": {
|
||||
"FILE": "Ruta de archivo",
|
||||
"IMG": "Imagen",
|
||||
"LINK": "Url"
|
||||
},
|
||||
"SELECT_TYPE": "Seleccione un tipo",
|
||||
"SELECT_TYPE": "Selecciona un tipo",
|
||||
"TYPES": {
|
||||
"FILE": "Archivo (abierto por la aplicación predeterminada del sistema)",
|
||||
"IMG": "Imagen (mostrada como miniatura)",
|
||||
|
|
@ -47,13 +47,13 @@
|
|||
},
|
||||
"BOOKMARK": {
|
||||
"BAR": {
|
||||
"ADD": "Añadir marcador",
|
||||
"ADD": "Agregar marcador",
|
||||
"DROP": "Suelta aquí para agregar un marcador",
|
||||
"EDIT": "Editar marcadores",
|
||||
"NO_BOOKMARKS": "No tienes marcadores de proyectos. Agregue una a través de arrastrar y soltar o haciendo clic en el ícono ''."
|
||||
},
|
||||
"DIALOG_EDIT": {
|
||||
"ADD_BOOKMARK": "Añadir marcador",
|
||||
"ADD_BOOKMARK": "Agregar marcador",
|
||||
"EDIT_BOOKMARK": "Editar marcador",
|
||||
"LABELS": {
|
||||
"COMMAND": "Comando",
|
||||
|
|
@ -61,8 +61,8 @@
|
|||
"IMG": "Imagen",
|
||||
"LINK": "Url"
|
||||
},
|
||||
"SELECT_ICON": "Seleccione un ícono",
|
||||
"SELECT_TYPE": "Seleccione un tipo",
|
||||
"SELECT_ICON": "Selecciona un ícono",
|
||||
"SELECT_TYPE": "Selecciona un tipo",
|
||||
"TYPES": {
|
||||
"COMMAND": "Comando (comando shell personalizado)",
|
||||
"FILE": "Archivo (abierto por la aplicación predeterminada del sistema)",
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
},
|
||||
"FORM": {
|
||||
"B_GENERATE_TOKEN": "Generar token",
|
||||
"FOLLOW_LINK": "Abra el siguiente enlace y copie el código de autenticación proporcionado allí en el campo de entrada.",
|
||||
"FOLLOW_LINK": "Abre el siguiente enlace y copia el código de autenticación proporcionado allí en el campo de entrada.",
|
||||
"L_ACCESS_TOKEN": "Token de acceso (generado a partir del código de autenticación)",
|
||||
"L_AUTH_CODE": "código de autenticación",
|
||||
"L_ENABLE_SYNCING": "Habilitar sincronización de Dropbox",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
"ERROR": "Google Drive - Error:",
|
||||
"ERROR_INITIAL_IMPORT": "Google Drive: error al intentar importar datos inicialmente",
|
||||
"LOCAL_UP_TO_DATE": "Google Drive: datos locales ya actualizados",
|
||||
"MULTIPLE_SYNC_FILES_WITH_SAME_NAME": "Se encontraron varios archivos con el nombre \"{{newFileName}}\". Por favor, elimine todos menos uno o elija un nombre diferente.",
|
||||
"MULTIPLE_SYNC_FILES_WITH_SAME_NAME": "Se encontraron varios archivos con el nombre \"{{newFileName}}\". Elimine todos menos uno o elija un nombre diferente.",
|
||||
"NO_UPDATE_REQUIRED": "Google Drive: No se requiere actualización",
|
||||
"REMOTE_UP_TO_DATE": "Google Drive: datos remotos ya actualizados",
|
||||
"SUCCESS": "Google Drive: Copia de seguridad guardada con éxito",
|
||||
|
|
@ -260,7 +260,7 @@
|
|||
},
|
||||
"JIRA": {
|
||||
"BANNER": {
|
||||
"BLOCK_ACCESS_MSG": "Jira: Para evitar el cierre de api, Super Productividad ha bloqueado el acceso. ¡Probablemente deberías revisar tu configuración de jira!",
|
||||
"BLOCK_ACCESS_MSG": "Jira: Para evitar el cierre de api, Super Productivity ha bloqueado el acceso. ¡Probablemente deberías revisar tu configuración de jira!",
|
||||
"BLOCK_ACCESS_UNBLOCK": "Desbloquear"
|
||||
},
|
||||
"CFG_CMP": {
|
||||
|
|
@ -285,7 +285,7 @@
|
|||
"TITLE": "Configurar Jira para Proyecto"
|
||||
},
|
||||
"DIALOG_TRANSITION": {
|
||||
"CHOOSE_STATUS": "Elija estado para asignar",
|
||||
"CHOOSE_STATUS": "Elija estado a asignar",
|
||||
"CURRENT_ASSIGNEE": "Asignado actual:",
|
||||
"CURRENT_STATUS": "Estado actual:",
|
||||
"TITLE": "Jira: Estado de actualización",
|
||||
|
|
@ -293,7 +293,7 @@
|
|||
},
|
||||
"DIALOG_WORKLOG": {
|
||||
"CURRENTLY_LOGGED": "Tiempo registrado actualmente:",
|
||||
"INVALID_DATE": "El valor introducido no es una fecha!",
|
||||
"INVALID_DATE": "¡El valor introducido no es una fecha!",
|
||||
"SAVE_WORKLOG": "Guardar registro de trabajo",
|
||||
"STARTED": "Empezado",
|
||||
"SUBMIT_WORKLOG_FOR": "Enviar un registro de trabajo a Jira para",
|
||||
|
|
@ -304,12 +304,12 @@
|
|||
"IS_AUTO_ADD_TO_BACKLOG": "Agregar automáticamente problemas sin resolver desde Github al registro de trabajo",
|
||||
"IS_AUTO_POLL": "Comprobar automáticamente los problemas de git importados por cambios",
|
||||
"IS_SEARCH_ISSUES_FROM_GITHUB": "Mostrar problemas de git como sugerencias al agregar nuevas tareas",
|
||||
"REPO": "\"username / repositoryName\" para el repositorio de git que desee seguir"
|
||||
"REPO": "\"username/repositoryName\" para el repositorio de git que desee seguir"
|
||||
},
|
||||
"FORM_ADV": {
|
||||
"AUTO_ADD_BACKLOG_JQL_QUERY": "JQL usado para agregar tareas automáticamente al registro de trabajo",
|
||||
"IS_ADD_WORKLOG_ON_SUB_TASK_DONE": "Abrir el cuadro de diálogo para enviar el registro de trabajo a jira cuando se realiza la subtarea",
|
||||
"IS_AUTO_ADD_TO_BACKLOG": "Añadir automáticamente problemas al registro de trabajo de Jira",
|
||||
"IS_AUTO_ADD_TO_BACKLOG": "Agregar automáticamente problemas al registro de trabajo de Jira",
|
||||
"IS_AUTO_POLL_TICKETS": "Verifica automáticamente los problemas importados por cambios y notifica",
|
||||
"IS_CHECK_TO_RE_ASSIGN_TICKET_ON_TASK_START": "Compruebe si el problema actualmente trabajado está asignado al usuario actual",
|
||||
"IS_WORKLOG_ENABLED": "Abrir el cuadro de diálogo para enviar el registro de trabajo a jira cuando se realiza la tarea",
|
||||
|
|
@ -358,7 +358,7 @@
|
|||
},
|
||||
"S": {
|
||||
"ADDED_WORKLOG_FOR": "Jira: Registro de trabajo agregado para {{issueKey}}",
|
||||
"EXTENSION_NOT_LOADED": "Extensión de Super Productividad no cargada. Recargar la página podría ayudar",
|
||||
"EXTENSION_NOT_LOADED": "Extensión de Super Productivity no cargada. Recargar la página podría ayudar",
|
||||
"IMPORTED_MULTIPLE_ISSUES": "Jira: Importó {{issuesLength}} problemas nuevos de jira al registro de trabajo",
|
||||
"IMPORTED_SINGLE_ISSUE": "Jira: problema importado \"{{issueText}}\" de jira al registro de trabajo",
|
||||
"INSUFFICIENT_SETTINGS": "Ajustes insuficientes proporcionados para Jira",
|
||||
|
|
@ -373,14 +373,14 @@
|
|||
"TRANSITION": "Jira: establece el problema \"{{issueKey}}\" en \"{{name}}\"",
|
||||
"TRANSITIONS_LOADED": "Jira: Transiciones cargadas. Usa las selecciones de abajo para asignarlas.",
|
||||
"TRANSITION_SUCCESS": "Jira: establece el problema {{issueKey}} a <strong>{{chosenTransition}}</strong>",
|
||||
"UNABLE_TO_REASSIGN": "Jira: No se puede reasignar el ticket a ti mismo, porque no especificaste un nombre de usuario. Por favor, visite los ajustes."
|
||||
"UNABLE_TO_REASSIGN": "Jira: No se puede reasignar el ticket a ti mismo, porque no especificaste un nombre de usuario. Visite los ajustes."
|
||||
},
|
||||
"STEPPER": {
|
||||
"CREDENTIALS": "Credenciales",
|
||||
"DONE": "Ya has terminado.",
|
||||
"LOGIN_SUCCESS": "¡Inicio de sesión exitoso!",
|
||||
"TEST_CREDENTIALS": "Credenciales de prueba",
|
||||
"WELCOME_USER": "Bienvenido {{user}}!"
|
||||
"WELCOME_USER": "¡Bienvenido {{user}}!"
|
||||
}
|
||||
},
|
||||
"METRIC": {
|
||||
|
|
@ -399,12 +399,12 @@
|
|||
"MOOD_PRODUCTIVITY_OVER_TIME": "Estado de ánimo y productividad a lo largo del tiempo.",
|
||||
"NO_ADDITIONAL_DATA_YET": "No se han recopilado datos adicionales todavía. Use el formulario en el resumen diario \"Evaluación\" del panel para hacerlo.",
|
||||
"OBSTRUCTION_SELECTION_COUNT": "Número de veces que se seleccionó un factor de obstrucción",
|
||||
"TASKS_DONE_CREATED": "Tareas (realizada / creada)",
|
||||
"TASKS_DONE_CREATED": "Tareas (realizada/creada)",
|
||||
"TIME_ESTIMATED": "Tiempo estimado",
|
||||
"TIME_SPENT": "Tiempo empleado"
|
||||
},
|
||||
"EVAL_FORM": {
|
||||
"ADD_NOTE_FOR_TOMORROW": "Añadir nota para mañana",
|
||||
"ADD_NOTE_FOR_TOMORROW": "Agregar nota para mañana",
|
||||
"DISABLE_REPEAT_EVERY_DAY": "Desactivar repetir todos los días",
|
||||
"ENABLE_REPEAT_EVERY_DAY": "Repite todos los dias",
|
||||
"HELP_H1": "¿Por qué debería importarme?",
|
||||
|
|
@ -442,7 +442,7 @@
|
|||
"EDIT_FULLSCREEN": "Editar en pantalla completa",
|
||||
"EDIT_REMINDER": "Editar recordatorio",
|
||||
"NOTES_CMP": {
|
||||
"ADD_BTN": "Añadir nueva nota",
|
||||
"ADD_BTN": "Agregar nueva nota",
|
||||
"DROP_TO_ADD": "Suelta aquí para agregar una nueva nota"
|
||||
},
|
||||
"NOTE_CMP": {
|
||||
|
|
@ -459,7 +459,7 @@
|
|||
},
|
||||
"POMODORO": {
|
||||
"BACK_TO_WORK": "¡Volver al trabajo!",
|
||||
"BREAK_IS_DONE": "Tu descanso ha terminado!",
|
||||
"BREAK_IS_DONE": "!Tu descanso ha terminado!",
|
||||
"ENJOY_YOURSELF": "Diviértete, muévete, vuelve en:",
|
||||
"FINISH_SESSION_X": "¡Has completado exitosamente la sesión <strong>{{nr}}</strong>!",
|
||||
"NOTIFICATION": {
|
||||
|
|
@ -492,7 +492,7 @@
|
|||
"TITLE": "Curiosidad"
|
||||
},
|
||||
"H1": "¡Relájate un poco!",
|
||||
"P1": "Primero que nada, a relajarse! Todo el mundo lo hace de vez en cuando. Y si no estás haciendo lo que debes, ¡al menos deberías disfrutarlo! Entonces revisa las secciones de abajo para algo útil.",
|
||||
"P1": "!Primero que nada, a relajarse! Todo el mundo lo hace de vez en cuando. Y si no estás haciendo lo que debes, ¡al menos deberías disfrutarlo! Entonces revisa las secciones de abajo para algo útil.",
|
||||
"P2": "Si desea saber más sobre la ciencia detrás de todo esto, puedo recomendar <a target=\"_blank\" href=\"https://www.nytimes.com/2019/03/25/smarter-living/why-you-procrastinate-it-has-nothing-to-do-with-self-control.html\" target=\"_blank\">este artículo</a> , en el cual se encuentran algunos de los ejercicios.",
|
||||
"P3": "Recuerde: la procrastinación es un problema de regulación emocional, no un problema de gestión del tiempo.",
|
||||
"REFRAME": {
|
||||
|
|
@ -560,7 +560,7 @@
|
|||
"TITLE": "Editar contador simple"
|
||||
},
|
||||
"FORM": {
|
||||
"ADD_NEW": "Añadir contador simple",
|
||||
"ADD_NEW": "Agregar contador simple",
|
||||
"HELP": "Aquí puede configurar botones simples que aparecerán en la esquina superior derecha. Pueden ser temporizadores o simplemente un contador simple, que se cuenta, haciendo clic en él.",
|
||||
"L_AUTO_COUNT_UP": "El gatillo automático cuenta para",
|
||||
"L_AUTO_SWITCH_OFF": "Disparador automático apagado para",
|
||||
|
|
@ -600,8 +600,8 @@
|
|||
},
|
||||
"TASK": {
|
||||
"ADDITIONAL_INFO": {
|
||||
"ADD_ATTACHMENT": "Añadir un adjunto",
|
||||
"ADD_SUB_TASK": "Añadir sub tarea",
|
||||
"ADD_ATTACHMENT": "Agregar un adjunto",
|
||||
"ADD_SUB_TASK": "Agregar subtarea",
|
||||
"ATTACHMENTS": "Adjuntos {{nr}}",
|
||||
"FROM_PARENT": "(del padre)",
|
||||
"LOCAL_ATTACHMENTS": "Adjuntos locales",
|
||||
|
|
@ -619,15 +619,15 @@
|
|||
"ADD_TASK": "Agregar tarea",
|
||||
"ADD_TASK_TO_BACKLOG": "Agregar tarea al registro de trabajo",
|
||||
"CREATE_TASK": "Crear nueva tarea",
|
||||
"EXAMPLE": "Ejemplo: \"Un título de tarea + nombre de proyecto # alguna etiqueta # alguna otra etiqueta 10m / 3h\"",
|
||||
"EXAMPLE": "Ejemplo: \"Título de tarea + nombre de proyecto #una etiqueta #otra etiqueta 10m/3h\"",
|
||||
"START": "Presiona entrar una vez más para comenzar"
|
||||
},
|
||||
"B": {
|
||||
"ADD_HALF_HOUR": "Añadir 1/2 hora",
|
||||
"ADD_HALF_HOUR": "Agregar 1/2 hora",
|
||||
"ESTIMATE_EXCEEDED": "Tiempo estimado superado para \"{{title}}\""
|
||||
},
|
||||
"CMP": {
|
||||
"ADD_SUB_TASK": "Añadir subtarea",
|
||||
"ADD_SUB_TASK": "Agregar subtarea",
|
||||
"ADD_TO_MY_DAY": "Agregar a mi día",
|
||||
"ADD_TO_PROJECT": "Agregar a un proyecto",
|
||||
"CONVERT_TO_PARENT_TASK": "Convertir a tarea principal",
|
||||
|
|
@ -647,8 +647,8 @@
|
|||
"REPEAT_EDIT": "Editar Repetir Tarea Config.",
|
||||
"SCHEDULE": "Programar tarea",
|
||||
"SHOW_UPDATES": "Mostrar actualizaciones",
|
||||
"TOGGLE_ADDITIONAL": "Mostrar / Ocultar información adicional",
|
||||
"TOGGLE_ATTACHMENTS": "Mostrar / Ocultar archivos adjuntos",
|
||||
"TOGGLE_ADDITIONAL": "Mostrar/Ocultar información adicional",
|
||||
"TOGGLE_ATTACHMENTS": "Mostrar/Ocultar archivos adjuntos",
|
||||
"TOGGLE_DONE": "Marcar como realizada / no realizada",
|
||||
"TOGGLE_SUB_TASK_VISIBILITY": "Alternar visibilidad de subtareas",
|
||||
"TRACK_TIME": "Comenzar el tiempo de seguimiento",
|
||||
|
|
@ -663,8 +663,8 @@
|
|||
"UNSCHEDULE": "Desprogramar"
|
||||
},
|
||||
"D_REMINDER_VIEW": {
|
||||
"ADD_ALL_TO_TODAY": "Agrega todo a hoy",
|
||||
"ADD_TO_TODAY": "Añadir a hoy",
|
||||
"ADD_ALL_TO_TODAY": "Agregar todo a hoy",
|
||||
"ADD_TO_TODAY": "Agregar a hoy",
|
||||
"DISMISS": "Descartar recordatorio",
|
||||
"DISMISS_ALL": "Descartar todo",
|
||||
"DUE_TASK": "Tarea debida",
|
||||
|
|
@ -680,7 +680,7 @@
|
|||
"SWITCH_CONTEXT_START": "Cambiar contexto e inicio"
|
||||
},
|
||||
"D_TIME": {
|
||||
"ADD_FOR_OTHER_DAY": "Añadir tiempo empleado para otro día",
|
||||
"ADD_FOR_OTHER_DAY": "Agregar tiempo empleado para otro día",
|
||||
"DELETE_FOR": "Borrar entrada por dia",
|
||||
"ESTIMATE": "Estimado",
|
||||
"TIME_SPENT": "Tiempo empleado",
|
||||
|
|
@ -688,14 +688,14 @@
|
|||
"TITLE": "Tiempo empleado / Estimaciones"
|
||||
},
|
||||
"D_TIME_FOR_DAY": {
|
||||
"ADD_ENTRY_FOR": "Añadir nueva entrada para {{date}}",
|
||||
"ADD_ENTRY_FOR": "Agregar nueva entrada para {{date}}",
|
||||
"DATE": "Fecha para la nueva entrada",
|
||||
"HELP": "Ejemplos:<br> 30m => 30 minutos<br> 2h => 2 horas<br> 2h 30m => 2 horas y 30 minutos",
|
||||
"TINE_SPENT": "Tiempo empleado",
|
||||
"TITLE": "Añadir para el día"
|
||||
"TITLE": "Agregar para el día"
|
||||
},
|
||||
"N": {
|
||||
"ESTIMATE_EXCEEDED": "Tiempo estimado superado!",
|
||||
"ESTIMATE_EXCEEDED": "!Tiempo estimado superado!",
|
||||
"ESTIMATE_EXCEEDED_BODY": "Has excedido tu tiempo estimado para \"{{title}}\"."
|
||||
},
|
||||
"S": {
|
||||
|
|
@ -724,7 +724,7 @@
|
|||
"OK": "Quitar completamente"
|
||||
},
|
||||
"D_EDIT": {
|
||||
"ADD": "Añadir Repetir configuración de tarea",
|
||||
"ADD": "Agregar Repetir configuración de tarea",
|
||||
"EDIT": "Editar Repetir Tarea Config.",
|
||||
"HELP1": "Las tareas repetitivas están destinadas a las tareas diarias, por ejemplo, \"Organización\", \"Reunión diaria\", \"Revisión de código\", \"Comprobación de correos electrónicos\" o tareas similares que pueden ocurrir una y otra vez.",
|
||||
"HELP2": "Una vez configurada, se volverá a crear una tarea repetitiva en cada día seleccionado a continuación tan pronto como abra su proyecto y se marcará automáticamente como finalizada al final del día. Serán manejados como diferentes instancias. Así que puedes agregar libremente subtareas, etc.",
|
||||
|
|
@ -774,7 +774,7 @@
|
|||
"D_EXPORT_TITLE": "Exportar registro de trabajo {{start}}-{{end}}",
|
||||
"D_EXPORT_TITLE_SINGLE": "Exportar registro de trabajo {{day}}",
|
||||
"EXPORT": {
|
||||
"ADD_COL": "Añadir columna",
|
||||
"ADD_COL": "Agregar columna",
|
||||
"COPY_TO_CLIPBOARD": "Copiar al portapapeles",
|
||||
"DONT_ROUND": "no redondear",
|
||||
"EDIT_COL": "Editar columna",
|
||||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "Descartar",
|
||||
"DO_IT": "¡Hazlo!",
|
||||
"EDIT": "Editar",
|
||||
"EXTENSION_INFO": "Por favor descargue <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> la extensión de Chrome</a> para permitir la comunicación con Jira Api y Idle Time Handling. Tenga en cuenta que esto no funciona para móviles.",
|
||||
"EXTENSION_INFO": "Por favor descargue <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> la extensión de Chrome</a> para permitir la comunicación con Jira Api y Idle Time Handling. Tenga en cuenta que esto no funciona para móviles.",
|
||||
"LOGIN": "Iniciar sesión",
|
||||
"LOGOUT": "Cerrar sesión",
|
||||
"MINUTES": "{{m}} minutos",
|
||||
|
|
@ -871,42 +871,42 @@
|
|||
"TITLE": "Importación y exportación"
|
||||
},
|
||||
"KEYBOARD": {
|
||||
"ADD_NEW_NOTE": "Añadir nueva nota",
|
||||
"ADD_NEW_NOTE": "Agregar nueva nota",
|
||||
"ADD_NEW_TASK": "Agregar nueva tarea",
|
||||
"APP_WIDE_SHORTCUTS": "Accesos directos globales (en toda la aplicación)",
|
||||
"APP_WIDE_SHORTCUTS": "Atajos globales (en toda la aplicación)",
|
||||
"COLLAPSE_SUB_TASKS": "Contraer subtareas",
|
||||
"EXPAND_SUB_TASKS": "Expandir subtareas",
|
||||
"GLOBAL_ADD_NOTE": "Añadir nueva nota",
|
||||
"GLOBAL_ADD_NOTE": "Agregar nueva nota",
|
||||
"GLOBAL_ADD_TASK": "Agregar nueva tarea",
|
||||
"GLOBAL_SHOW_HIDE": "Mostrar / Ocultar Super Productividad",
|
||||
"GLOBAL_SHOW_HIDE": "Mostrar/Ocultar Super Productivity",
|
||||
"GLOBAL_TOGGLE_TASK_START": "Alternar el seguimiento de tiempo para la última tarea activa",
|
||||
"GO_TO_DAILY_AGENDA": "Ir a Agenda",
|
||||
"GO_TO_FOCUS_MODE": "Ir al Modo de Enfoque",
|
||||
"GO_TO_SETTINGS": "Ir a Ajustes",
|
||||
"GO_TO_WORK_VIEW": "Ir a la Vista de Trabajo",
|
||||
"HELP": "<p>Aquí puedes configurar todos los atajos del teclado.</p> <p>Haga clic en la entrada de texto e ingrese la combinación de teclas deseada. Pulsa Enter para guardar y Escape para abortar.</p> <p>Hay tres tipos de accesos directos:</p> <ul> <li> <strong>Atajos globales:</strong> Cuando la aplicación se está ejecutando, se activará la acción desde cualquier otra aplicación. </li> <li> <strong>Atajos de nivel de aplicación:</strong> Se activará desde todas las pantallas de la aplicación, pero no si está editando un campo de texto. </li> <li> <strong>Atajos de nivel de tarea:</strong> Solo se activarán si ha seleccionado una tarea mediante el mouse o el teclado y, por lo general, activará una acción relacionada específicamente con esa tarea. </li> </ul>",
|
||||
"HELP": "<p>Aquí puedes configurar todos los atajos del teclado.</p> <p>Haga clic en la entrada de texto e ingrese la combinación de teclas deseada. Pulsa Enter para guardar y Escape para abortar.</p> <p>Hay tres tipos de atajos:</p> <ul> <li> <strong>Atajos globales:</strong> Cuando la aplicación se está ejecutando, se activará la acción desde cualquier otra aplicación. </li> <li> <strong>Atajos de nivel de aplicación:</strong> Se activará desde todas las pantallas de la aplicación, pero no si está editando un campo de texto. </li> <li> <strong>Atajos de nivel de tarea:</strong> Solo se activarán si ha seleccionado una tarea mediante el mouse o el teclado y, por lo general, activará una acción relacionada específicamente con esa tarea. </li> </ul>",
|
||||
"MOVE_TASK_DOWN": "Mueve la tarea hacia abajo en la lista",
|
||||
"MOVE_TASK_UP": "Mover la tarea hacia arriba en la lista",
|
||||
"MOVE_TO_BACKLOG": "Mover la tarea al registro de trabajo",
|
||||
"MOVE_TO_TODAYS_TASKS": "Mueve la tarea a la lista de tareas de hoy",
|
||||
"OPEN_PROJECT_NOTES": "Mostrar / Ocultar Notas del Proyecto",
|
||||
"OPEN_PROJECT_NOTES": "Mostrar/Ocultar Notas del Proyecto",
|
||||
"SELECT_NEXT_TASK": "Seleccionar tarea siguiente",
|
||||
"SELECT_PREVIOUS_TASK": "Seleccionar tarea previa",
|
||||
"SYSTEM_SHORTCUTS": "Atajos globales (en todo el sistema)",
|
||||
"TASK_ADD_SUB_TASK": "Añadir subtarea",
|
||||
"TASK_ADD_SUB_TASK": "Agregar subtarea",
|
||||
"TASK_DELETE": "Eliminar tarea",
|
||||
"TASK_EDIT_TITLE": "Editar Título",
|
||||
"TASK_MOVE_TO_PROJECT": "Abrir mover tarea al menú del proyecto",
|
||||
"TASK_OPEN_ESTIMATION_DIALOG": "Editar estimación / tiempo empleado",
|
||||
"TASK_SCHEDULE": "Programar tarea",
|
||||
"TASK_SHORTCUTS": "Tareas",
|
||||
"TASK_SHORTCUTS_INFO": "Los siguientes atajos se aplican a la tarea seleccionada actualmente (seleccionada mediante una pestaña o un mouse).",
|
||||
"TASK_TOGGLE_ADDITIONAL_INFO_OPEN": "Mostrar / Ocultar información adicional de la tarea",
|
||||
"TASK_SHORTCUTS_INFO": "Los siguientes atajos se aplican a la tarea seleccionada actual (seleccionada a través de una pestaña o con el ratón).",
|
||||
"TASK_TOGGLE_ADDITIONAL_INFO_OPEN": "Mostrar/Ocultar información adicional de la tarea",
|
||||
"TASK_TOGGLE_DONE": "Altenado realizado",
|
||||
"TITLE": "Atajos de teclado",
|
||||
"TOGGLE_BACKLOG": "Mostrar / Ocultar registro de la tarea",
|
||||
"TOGGLE_BOOKMARKS": "Mostrar / Ocultar barra de marcadores",
|
||||
"TOGGLE_PLAY": "Iniciar / detener tarea",
|
||||
"TOGGLE_BACKLOG": "Mostrar/Ocultar registro de la tarea",
|
||||
"TOGGLE_BOOKMARKS": "Mostrar/Ocultar barra de marcadores",
|
||||
"TOGGLE_PLAY": "Iniciar/Detener tarea",
|
||||
"ZOOM_DEFAULT": "Valor predeterminado de zoom (solo para escritorio)",
|
||||
"ZOOM_IN": "Acercar (solo para escritorio)",
|
||||
"ZOOM_OUT": "Alejar (solo para escritorio)"
|
||||
|
|
@ -918,30 +918,31 @@
|
|||
"ES": "Español",
|
||||
"FA": "Farsi",
|
||||
"FR": "Francés",
|
||||
"IT": "italiano",
|
||||
"IT": "Italiano",
|
||||
"JA": "Japonés",
|
||||
"KO": "Coreano",
|
||||
"LABEL": "Por favor, seleccione un idioma",
|
||||
"LABEL": "Selecciona un idioma",
|
||||
"NB": "Noruego bokmål",
|
||||
"NL": "Holandés",
|
||||
"PT": "portugués",
|
||||
"PT": "Portugués",
|
||||
"RU": "Ruso",
|
||||
"TITLE": "Idioma",
|
||||
"TR": "Turco",
|
||||
"ZH": "Chino"
|
||||
},
|
||||
"MISC": {
|
||||
"DEFAULT_PROJECT": "Proyecto predeterminado para usar para tareas si no se especifica ninguno",
|
||||
"HELP": "<p><strong>¿No ve las notificaciones de escritorio?</strong> Para Windows, es posible que desee revisar Sistema> Notificaciones y acciones y verificar si se han habilitado las notificaciones requeridas.</p>",
|
||||
"IS_AUTO_ADD_WORKED_ON_TO_TODAY": "Agregue automáticamente la etiqueta de hoy a las tareas trabajadas",
|
||||
"IS_AUTO_MARK_PARENT_AS_DONE": "Marque la tarea principal como realizada, cuando todas las subtareas estén listas",
|
||||
"IS_AUTO_START_NEXT_TASK": "Comience a rastrear la siguiente tarea cuando marque actual como hecha",
|
||||
"DEFAULT_PROJECT": "Proyecto predeterminado a usar para las tareas si no se especifica ninguno",
|
||||
"HELP": "<p><strong>¿No se ven las notificaciones de escritorio?</strong> En Windows, puedes revisar en Sistema> Notificaciones y acciones, y verificar si se han habilitado las notificaciones requeridas.</p>",
|
||||
"IS_AUTO_ADD_WORKED_ON_TO_TODAY": "Agregar automáticamente la etiqueta de hoy a las tareas completadas",
|
||||
"IS_AUTO_MARK_PARENT_AS_DONE": "Marcar la tarea principal como realizada, cuando se completen todas las subtareas",
|
||||
"IS_AUTO_START_NEXT_TASK": "Comenzar a rastrear la siguiente tarea cuando se marque la tarea actual como completa",
|
||||
"IS_CONFIRM_BEFORE_EXIT": "Confirmar antes de salir de la aplicación",
|
||||
"IS_DARK_MODE": "Modo oscuro",
|
||||
"IS_DISABLE_INITIAL_DIALOG": "Deshabilite el diálogo de información inicial (¡podría perderse actualizaciones importantes!)",
|
||||
"IS_DARK_MODE": "Modo Oscuro",
|
||||
"IS_DISABLE_INITIAL_DIALOG": "Deshabilitar el diálogo de información inicial (¡podrías perderte actualizaciones importantes!)",
|
||||
"IS_HIDE_NAV": "Ocultar la navegación hasta que se desplace sobre el encabezado principal (solo para escritorio)",
|
||||
"IS_NOTIFY_WHEN_TIME_ESTIMATE_EXCEEDED": "Notificar cuando se excedió el tiempo estimado",
|
||||
"IS_TURN_OFF_MARKDOWN": "Desactiva el análisis de descuento para notas",
|
||||
"TITLE": "Ajustes varios"
|
||||
"IS_NOTIFY_WHEN_TIME_ESTIMATE_EXCEEDED": "Notificar cuando se excede el tiempo estimado",
|
||||
"IS_TURN_OFF_MARKDOWN": "Desactivar la sintaxis markdown para las notas",
|
||||
"TITLE": "Ajustes Variados"
|
||||
},
|
||||
"POMODORO": {
|
||||
"BREAK_DURATION": "Duración de las pausas breves",
|
||||
|
|
@ -952,16 +953,16 @@
|
|||
"IS_MANUAL_CONTINUE": "Confirmar manualmente el inicio de la siguiente sesión de pomodoro",
|
||||
"IS_PLAY_SOUND": "Reproducir sonido cuando la sesión haya terminado",
|
||||
"IS_PLAY_SOUND_AFTER_BREAK": "Reproducir sonido cuando el descanso haya terminado",
|
||||
"IS_PLAY_TICK": "Reproduce el sonido de tick cada segundo",
|
||||
"IS_PLAY_TICK": "Reproducir el sonido de tick cada segundo",
|
||||
"IS_STOP_TRACKING_ON_BREAK": "Detener el tiempo de seguimiento para la tarea en descanso",
|
||||
"LONGER_BREAK_DURATION": "Duración de los descansos más largos",
|
||||
"TITLE": "Pomodoro Timer"
|
||||
"TITLE": "Temporizador Pomodoro"
|
||||
},
|
||||
"SOUND": {
|
||||
"DONE_SOUND": "Sonido de tarea realizada",
|
||||
"IS_INCREASE_DONE_PITCH": "Aumente el tono para cada tarea realizada",
|
||||
"IS_PLAY_DONE_SOUND": "Reproducir sonido cuando la tarea esté marcada como terminada",
|
||||
"TITLE": "Sonar",
|
||||
"TITLE": "Sonido",
|
||||
"VOLUME": "Volumen"
|
||||
},
|
||||
"TAKE_A_BREAK": {
|
||||
|
|
@ -973,6 +974,12 @@
|
|||
"MIN_WORKING_TIME": "Mostrar una notificación de descanso después de X tiempo trabajando sin una",
|
||||
"MOTIVATIONAL_IMG": "Imagen motivacional (url web)",
|
||||
"TITLE": "Recordatorio de descanso"
|
||||
},
|
||||
"TRACKING_REMINDER": {
|
||||
"HELP": "Establecer un recordatorio para que aparezca en caso de que haya olvidado iniciar el seguimiento del tiempo.",
|
||||
"TITLE": "Recordatorio de Seguimiento de Tiempo",
|
||||
"L_IS_ENABLED": "Activado",
|
||||
"L_MIN_TIME": "Tiempo a esperar antes de que se mueste el recordatorio"
|
||||
}
|
||||
},
|
||||
"GLOBAL_SNACK": {
|
||||
|
|
@ -980,8 +987,8 @@
|
|||
"ERR_COMPRESSION": "Error para la interfaz de compresión",
|
||||
"PERSISTENCE_DISALLOWED": "Los datos no se conservarán de forma permanente. ¡Tenga en cuenta que esto puede conducir a la pérdida de datos!",
|
||||
"RUNNING_X": "Ejecutando \"{{str}}\".",
|
||||
"SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG": "{{keyCombo}} presionado, pero el acceso directo a marcadores abiertos solo está disponible en el contexto del proyecto.",
|
||||
"SHORTCUT_WARN_OPEN_NOTES_FROM_TAG": "{{keyCombo}} presionado, pero el acceso directo de notas abiertas solo está disponible en el contexto del proyecto."
|
||||
"SHORTCUT_WARN_OPEN_BOOKMARKS_FROM_TAG": "{{keyCombo}} presionado, pero el atajo a marcadores abiertos solo está disponible en el contexto del proyecto.",
|
||||
"SHORTCUT_WARN_OPEN_NOTES_FROM_TAG": "{{keyCombo}} presionado, pero el atajo de notas abiertas solo está disponible en el contexto del proyecto."
|
||||
},
|
||||
"GPB": {
|
||||
"ASSETS": "Cargando activos ...",
|
||||
|
|
@ -1012,14 +1019,14 @@
|
|||
"TAGS": "Etiquetas",
|
||||
"TASKS": "Tareas",
|
||||
"TASK_LIST": "Lista de tareas",
|
||||
"TOGGLE_SHOW_BOOKMARKS": "Mostrar / Ocultar Marcadores",
|
||||
"TOGGLE_SHOW_NOTES": "Mostrar / Ocultar Notas del Proyecto",
|
||||
"TOGGLE_SHOW_BOOKMARKS": "Mostrar/Ocultar Marcadores",
|
||||
"TOGGLE_SHOW_NOTES": "Mostrar/Ocultar Notas del Proyecto",
|
||||
"TOGGLE_TRACK_TIME": "Iniciar / Detener el tiempo de seguimiento",
|
||||
"WORKLOG": "Registro de trabajo"
|
||||
},
|
||||
"PDS": {
|
||||
"BACK": "Espera me olvidé de algo!",
|
||||
"BREAK_LABEL": "Descansos (nr / tiempo)",
|
||||
"BACK": "!Espera me olvidé de algo!",
|
||||
"BREAK_LABEL": "Descansos (nr/tiempo)",
|
||||
"CELEBRATE": "¡Tómate un momento para celebrar <i>!</i>",
|
||||
"CLEAR_ALL_CONTINUE": "Borrar todo listo y continuar",
|
||||
"D_CONFIRM_APP_CLOSE": {
|
||||
|
|
@ -1063,11 +1070,11 @@
|
|||
"OK": "Archivar"
|
||||
},
|
||||
"D_CONFIRM_DELETE": {
|
||||
"MSG": "¿Estás seguro de que quieres eliminar este proyecto? Se recomienda hacer una copia de seguridad de sus datos antes de hacer esto.",
|
||||
"MSG": "¿Seguro que quieres eliminar este proyecto? Se recomienda hacer una copia de seguridad de sus datos antes de hacer esto.",
|
||||
"OK": "Borrar"
|
||||
},
|
||||
"D_CONFIRM_UNARCHIVE": {
|
||||
"MSG": "¿Estás seguro de que quieres desarchivar este proyecto?",
|
||||
"MSG": "¿Seguro que quieres desarchivar este proyecto?",
|
||||
"OK": "Desarchivar"
|
||||
},
|
||||
"EDIT_PROJECT": "Editar proyecto",
|
||||
|
|
@ -1084,11 +1091,11 @@
|
|||
"GLOBAL_SETTINGS": "Ajustes globales",
|
||||
"ISSUE_INTEGRATION": "Integración de problemas",
|
||||
"PRIVATE_POLICY": "Política privada",
|
||||
"PRODUCTIVITY_HELPER": "Ayudante de productividad",
|
||||
"PRODUCTIVITY_HELPER": "Ayudante de Productividad",
|
||||
"PROJECT_SETTINGS": "Ajustes Específicos del Proyecto",
|
||||
"SYNC_EXPORT": "Sincronizar y Exportar",
|
||||
"TAG_SETTINGS": "Configuraciones específicas de etiqueta",
|
||||
"TOGGLE_DARK_MODE": "Cambiar modo oscuro"
|
||||
"TOGGLE_DARK_MODE": "Cambiar a modo oscuro"
|
||||
},
|
||||
"S": {
|
||||
"SYNC": {
|
||||
|
|
@ -1103,7 +1110,7 @@
|
|||
"START_TASK": "Inicie la tarea ahora y elimine el recordatorio"
|
||||
},
|
||||
"THEMES": {
|
||||
"SELECT_THEME": "Seleccione el tema",
|
||||
"SELECT_THEME": "Selecciona el tema",
|
||||
"amber": "Ámbar",
|
||||
"blue": "Azul",
|
||||
"blue-grey": "Gris azulado",
|
||||
|
|
@ -1121,7 +1128,7 @@
|
|||
"yellow": "Amarillo"
|
||||
},
|
||||
"V": {
|
||||
"E_1TO10": "Por favor, introduzca un valor entre 1 y 10",
|
||||
"E_1TO10": "Ingresa un valor entre 1 y 10",
|
||||
"E_DATETIME": "El valor ingresado no es una fecha y hora!",
|
||||
"E_MAX": "No debe ser más grande que {{val}}",
|
||||
"E_MAX_LENGTH": "Debe tener una longitud máxima de {{val}} caracteres",
|
||||
|
|
@ -1131,12 +1138,12 @@
|
|||
"E_REQUIRED": "Este campo es requerido"
|
||||
},
|
||||
"WW": {
|
||||
"ADD_MORE": "Añadir más",
|
||||
"ADD_MORE": "Agregar más",
|
||||
"ADD_SOME_TASKS": "¡Agrega algunas tareas para planificar tu día!",
|
||||
"COMPLETED_TASKS": "Tareas completadas",
|
||||
"ESTIMATE_REMAINING": "Estimación restante:",
|
||||
"FINISH_DAY": "Fin de dia",
|
||||
"HELP_PROCRASTINATION": "Ayuda, estoy procrastinando!",
|
||||
"HELP_PROCRASTINATION": "Ayuda, !estoy procrastinando!",
|
||||
"NO_COMPLETED_TASKS": "Actualmente no hay tareas completadas.",
|
||||
"NO_PLANNED_TASKS": "No hay tareas planificadas",
|
||||
"READY_TO_WORK": "¡Listo para trabajar!",
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "رد کردن",
|
||||
"DO_IT": "انجام بدهید!",
|
||||
"EDIT": "ویرایش",
|
||||
"EXTENSION_INFO": "لطفا برای ارتباط با جیرا و مدیریت زمان <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> افزونه گوگل کروم</a> را دانلود کنید. توجه این افزونه برای نسخه موبایل کروم کار نمی کند.",
|
||||
"EXTENSION_INFO": "لطفا برای ارتباط با جیرا و مدیریت زمان <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> افزونه گوگل کروم</a> را دانلود کنید. توجه این افزونه برای نسخه موبایل کروم کار نمی کند.",
|
||||
"LOGIN": "وارد شدن",
|
||||
"LOGOUT": "خارج شدن",
|
||||
"MINUTES": "{{m}} دقیقه",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "ژاپنی",
|
||||
"KO": "کره ای",
|
||||
"LABEL": "لطفا یک زبان انتخاب کنید",
|
||||
"NB": "نروژی",
|
||||
"NL": "هلندی",
|
||||
"PT": "پرتغالی",
|
||||
"RU": "روسی",
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "Rejeter",
|
||||
"DO_IT": "Fais le !",
|
||||
"EDIT": "modifier",
|
||||
"EXTENSION_INFO": "Veuillez <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> télécharger l'extension chrome</a> afin de permettre la communication avec l'Api Jira et la gestion du temps d'inactivité. Notez que cela ne fonctionne pas sur mobile.",
|
||||
"EXTENSION_INFO": "Veuillez <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> télécharger l'extension chrome</a> afin de permettre la communication avec l'Api Jira et la gestion du temps d'inactivité. Notez que cela ne fonctionne pas sur mobile.",
|
||||
"LOGIN": "S'identifier",
|
||||
"LOGOUT": "Se déconnecter",
|
||||
"MINUTES": "{{m}} minutes",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "japonais",
|
||||
"KO": "coréen",
|
||||
"LABEL": "Veuillez sélectionner une langue",
|
||||
"NB": "Norvégien bokmål",
|
||||
"NL": "Néerlandais",
|
||||
"PT": "Portugais",
|
||||
"RU": "russe",
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "Rimuovi",
|
||||
"DO_IT": "Fallo!",
|
||||
"EDIT": "Modifica",
|
||||
"EXTENSION_INFO": "Per favore <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> scarica l'estensione di chrome</a> per permettere la comunicazione con le api di Jira e la gestione del tempo inattivo. Nota che non funziona su dispositivi mobile.",
|
||||
"EXTENSION_INFO": "Per favore <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> scarica l'estensione di chrome</a> per permettere la comunicazione con le api di Jira e la gestione del tempo inattivo. Nota che non funziona su dispositivi mobile.",
|
||||
"LOGIN": "Login",
|
||||
"LOGOUT": "Logout",
|
||||
"MINUTES": "{{m}} minuti",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "Giapponese",
|
||||
"KO": "Coreano",
|
||||
"LABEL": "Seleziona la lingua",
|
||||
"NB": "Norvegese Bokmål",
|
||||
"NL": "Olandese",
|
||||
"PT": "Portoguese",
|
||||
"RU": "Russo",
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "やめる",
|
||||
"DO_IT": "やれ!",
|
||||
"EDIT": "編集",
|
||||
"EXTENSION_INFO": "Jira ApiおよびIdle Time Handlingとの通信を可能にするために、クロム拡張</a> をダウンロード <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> してください。これはモバイルでは機能しないことに注意してください。",
|
||||
"EXTENSION_INFO": "Jira ApiおよびIdle Time Handlingとの通信を可能にするために、クロム拡張</a> をダウンロード <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> してください。これはモバイルでは機能しないことに注意してください。",
|
||||
"LOGIN": "ログイン",
|
||||
"LOGOUT": "ログアウト",
|
||||
"MINUTES": "{{m}} 分",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "日本人",
|
||||
"KO": "韓国語",
|
||||
"LABEL": "言語を選択してください",
|
||||
"NB": "ノルウェーのブークモール",
|
||||
"NL": "蘭語",
|
||||
"PT": "ポルトガル",
|
||||
"RU": "ロシア",
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "버리다",
|
||||
"DO_IT": "해!",
|
||||
"EDIT": "편집하다",
|
||||
"EXTENSION_INFO": "Jira Api 및 Idle Time Handling과의 통신을 허용하려면 <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> 크롬 확장</a> 을 다운로드하십시오. 이 기능은 모바일에서 작동하지 않습니다.",
|
||||
"EXTENSION_INFO": "Jira Api 및 Idle Time Handling과의 통신을 허용하려면 <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> 크롬 확장</a> 을 다운로드하십시오. 이 기능은 모바일에서 작동하지 않습니다.",
|
||||
"LOGIN": "로그인",
|
||||
"LOGOUT": "로그 아웃",
|
||||
"MINUTES": "{{m}} 분",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "일본어",
|
||||
"KO": "한국어",
|
||||
"LABEL": "언어를 선택하십시오.",
|
||||
"NB": "노르웨이 보크 몰",
|
||||
"NL": "네덜란드 사람",
|
||||
"PT": "포르투갈 인",
|
||||
"RU": "러시아인",
|
||||
|
|
|
|||
1174
src/assets/i18n/nb.json
Normal file
1174
src/assets/i18n/nb.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "Afwijzen",
|
||||
"DO_IT": "Doe het!",
|
||||
"EDIT": "Bewerk",
|
||||
"EXTENSION_INFO": "<a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> Download de Chrome-extensie</a> om communicatie met de Jira Api en Idle Time Handling mogelijk te maken. Merk op dat dit niet werkt voor mobiel.",
|
||||
"EXTENSION_INFO": "<a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> Download de Chrome-extensie</a> om communicatie met de Jira Api en Idle Time Handling mogelijk te maken. Merk op dat dit niet werkt voor mobiel.",
|
||||
"LOGIN": "Log in",
|
||||
"LOGOUT": "Uitloggen",
|
||||
"MINUTES": "{{m}} minuten",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "Japans",
|
||||
"KO": "Koreaans",
|
||||
"LABEL": "Selecteer een taal",
|
||||
"NB": "Noors Bokmål",
|
||||
"NL": "Nederlands",
|
||||
"PT": "Portugees",
|
||||
"RU": "Russisch",
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
"INSTALL": "Instalar",
|
||||
"MSG": "Deseja instalar Super Productivity como PWA?"
|
||||
},
|
||||
"B_OFFLINE": "Você está desconectado da internet. Sincronizar e solicitar dados do provedor de problemas não funcionará.",
|
||||
"B_OFFLINE": "Você está desconectado da internet. A sincronização e solicitação de dados do provedor de problemas não funcionará.",
|
||||
"D_INITIAL": {
|
||||
"TITLE": "Bem-vindo à v{{nr}}"
|
||||
},
|
||||
"UPDATE_MAIN_MODEL": "Super Produtividade recebeu uma grande atualização! Algumas migrações para seus dados são necessárias. Observe que isso torna seus dados incompatíveis com versões mais antigas do aplicativo.",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "Nenhuma atualização de modelo escolhida. Observe que você deve fazer o downgrade para a última versão, se não desejar executar a atualização do modelo.",
|
||||
"UPDATE_MAIN_MODEL": "Super Productivity recebeu uma grande atualização! Algumas migrações para seus dados são necessárias. Observe que isso torna seus dados incompatíveis com versões mais antigas do aplicativo.",
|
||||
"UPDATE_MAIN_MODEL_NO_UPDATE": "Nenhuma atualização de modelo escolhida. Note que você deve fazer o downgrade para a última versão, se não desejar executar a atualização do modelo.",
|
||||
"UPDATE_WEB_APP": "Nova versão disponível. Carregar nova versão?"
|
||||
},
|
||||
"BL": {
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
"IMG": "Imagem",
|
||||
"LINK": "Url"
|
||||
},
|
||||
"SELECT_ICON": "Selecione um icone",
|
||||
"SELECT_ICON": "Selecione um ícone",
|
||||
"SELECT_TYPE": "Selecione um tipo",
|
||||
"TYPES": {
|
||||
"COMMAND": "Comando (Comando shell personalizado)",
|
||||
|
|
@ -86,14 +86,14 @@
|
|||
},
|
||||
"D_CONFLICT": {
|
||||
"LAST_CHANGE": "última mudança:",
|
||||
"LAST_SYNC": "última sincronização:",
|
||||
"LAST_SYNC": "Última sincronização:",
|
||||
"LOCAL": "Local",
|
||||
"LOCAL_REMOTE": "local -> remoto",
|
||||
"REMOTE": "Controlo remoto",
|
||||
"REMOTE": "remoto",
|
||||
"TEXT": "<p>Atualização do Dropbox. Os dados locais e remotos parecem ter sido modificados.</p>",
|
||||
"TITLE": "Dropbox: dados conflitantes",
|
||||
"USE_LOCAL": "Use local",
|
||||
"USE_REMOTE": "Usar controle remoto"
|
||||
"USE_LOCAL": "Usar local",
|
||||
"USE_REMOTE": "Usar remoto"
|
||||
},
|
||||
"FORM": {
|
||||
"B_GENERATE_TOKEN": "Gerar token",
|
||||
|
|
@ -119,8 +119,8 @@
|
|||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Nome de usuário (ex.: para filtrar as alterações sozinho)",
|
||||
"IS_AUTO_ADD_TO_BACKLOG": "Adicionar automáticamente problemas não resolvidos do Github para o backlog",
|
||||
"IS_AUTO_POLL": "Obter automáticamente issues do Github para alterações",
|
||||
"IS_AUTO_ADD_TO_BACKLOG": "Adicionar automaticamente problemas não resolvidos do Github para o backlog",
|
||||
"IS_AUTO_POLL": "Obter automaticamente issues do Github para alterações",
|
||||
"IS_SEARCH_ISSUES_FROM_GITHUB": "Mostrar issues do Github como sugestões qando adicionar novas tarefas",
|
||||
"REPO": "\"username/repositoryName\" para o repositório git que você deseja rastrear",
|
||||
"TOKEN": "Token de acesso"
|
||||
|
|
@ -131,12 +131,12 @@
|
|||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Responsável",
|
||||
"AT": "at",
|
||||
"AT": "em",
|
||||
"DESCRIPTION": "Descrição",
|
||||
"LABELS": "Etiquetas",
|
||||
"MARK_AS_CHECKED": "Marcar atualizações como checadas",
|
||||
"STATUS": "Status",
|
||||
"SUMMARY": "Indíce",
|
||||
"SUMMARY": "Índice",
|
||||
"WRITE_A_COMMENT": "Comentar"
|
||||
},
|
||||
"S": {
|
||||
|
|
@ -161,8 +161,8 @@
|
|||
},
|
||||
"FORM": {
|
||||
"FILTER_USER": "Nome de usuário (ex.: para filtrar as alterações sozinho)",
|
||||
"IS_AUTO_ADD_TO_BACKLOG": "Adicionar automáticamente problemas não resolvidos do Gitlab para o backlog",
|
||||
"IS_AUTO_POLL": "Obter automáticamente issues do Gitlab para alterações",
|
||||
"IS_AUTO_ADD_TO_BACKLOG": "Adicionar automaticamente problemas não resolvidos do Gitlab para o backlog",
|
||||
"IS_AUTO_POLL": "Obter automaticamente issues do Gitlab para alterações",
|
||||
"IS_SEARCH_ISSUES_FROM_GITLAB": "Mostrar issues do Gitlab como sugestões qando adicionar novas tarefas",
|
||||
"PROJECT": "Caminho completo ou nome de usuário / projeto",
|
||||
"TOKEN": "Token de acesso"
|
||||
|
|
@ -173,7 +173,7 @@
|
|||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Responsável",
|
||||
"AT": "at",
|
||||
"AT": "em",
|
||||
"DESCRIPTION": "Descrição",
|
||||
"LABELS": "Etiquetas",
|
||||
"MARK_AS_CHECKED": "Marcar atualizações como checadas",
|
||||
|
|
@ -212,7 +212,7 @@
|
|||
"LOCAL_REMOTE": "local <=> remoto",
|
||||
"OVERWRITE_LOCAL": "Substituir local",
|
||||
"OVERWRITE_REMOTE": "Substituir remoto",
|
||||
"REMOTE": "romoto",
|
||||
"REMOTE": "remoto",
|
||||
"TEXT": "<p>Atualização do Google Drive Backup. Os dados locais e remotos parecem ter sido modificados. Deseja sobrescrever alterações locais não salvas? <strong>Todos os dados serão perdidos para sempre</strong>.</p>",
|
||||
"TITLE": "Sobrescrever dados locais com a Atualização GDrive?"
|
||||
},
|
||||
|
|
@ -260,7 +260,7 @@
|
|||
},
|
||||
"JIRA": {
|
||||
"BANNER": {
|
||||
"BLOCK_ACCESS_MSG": "Jira: A fim de impedir o desligamento da API, o acesso foi bloqueado pela Super Produtividade. Você provavelmente deve verificar suas configurações do jira!",
|
||||
"BLOCK_ACCESS_MSG": "Jira: A fim de impedir o desligamento da API, o acesso foi bloqueado pelo Super Productivity. Você provavelmente deve verificar suas configurações do jira!",
|
||||
"BLOCK_ACCESS_UNBLOCK": "Desbloquear"
|
||||
},
|
||||
"CFG_CMP": {
|
||||
|
|
@ -301,7 +301,7 @@
|
|||
"TITLE": "Jira: Enviar log de trabalho"
|
||||
},
|
||||
"FORM": {
|
||||
"IS_AUTO_ADD_TO_BACKLOG": "Adicionar automáticamente problemas não resolvidos do Github para o backlog",
|
||||
"IS_AUTO_ADD_TO_BACKLOG": "Adicionar automaticamente problemas não resolvidos do Github para o backlog",
|
||||
"IS_AUTO_POLL": "Pesquisar automaticamente problemas importados do git em busca de alterações",
|
||||
"IS_SEARCH_ISSUES_FROM_GITHUB": "Mostrar issues do Github como sugestões qando adicionar novas tarefas",
|
||||
"REPO": "\"username/repositoryName\" para o repositório git que você deseja rastrear"
|
||||
|
|
@ -341,7 +341,7 @@
|
|||
},
|
||||
"ISSUE_CONTENT": {
|
||||
"ASSIGNEE": "Resposável",
|
||||
"AT": "at",
|
||||
"AT": "em",
|
||||
"ATTACHMENTS": "Anexos",
|
||||
"CHANGED": "Alterado",
|
||||
"COMMENTS": "Comentarios",
|
||||
|
|
@ -349,7 +349,7 @@
|
|||
"DESCRIPTION": "Descrição",
|
||||
"LIST_OF_CHANGES": "Lista de mudanças",
|
||||
"MARK_AS_CHECKED": "Marcar atualizações como checadas",
|
||||
"ON": "on",
|
||||
"ON": "em",
|
||||
"STATUS": "Status",
|
||||
"STORY_POINTS": "Story Points",
|
||||
"SUMMARY": "Indíce",
|
||||
|
|
@ -463,7 +463,7 @@
|
|||
"ENJOY_YOURSELF": "Divirta-se, mexa-se, volte em:",
|
||||
"FINISH_SESSION_X": "Você terminou a sessão com sucesso <strong>{{nr}}</strong>!",
|
||||
"NOTIFICATION": {
|
||||
"BREAK_X_START": "Pomodoro: Pausa {{nr}} iniciado!",
|
||||
"BREAK_X_START": "Pomodoro: Pausa {{nr}} iniciada!",
|
||||
"SESSION_X_START": "Pomodoro: Sessão {{nr}} iniciada!"
|
||||
},
|
||||
"S": {
|
||||
|
|
@ -567,7 +567,7 @@
|
|||
"L_AUTO_SWITCH_ON": "O gatilho automático é ativado por",
|
||||
"L_ICON": "Ícone",
|
||||
"L_ICON_ON": "Ícone quando alternado",
|
||||
"L_IS_ENABLED": "ativado",
|
||||
"L_IS_ENABLED": "Ativado",
|
||||
"L_TITLE": "Título",
|
||||
"L_TYPE": "Tipo",
|
||||
"TITLE": "Contadores simples",
|
||||
|
|
@ -611,7 +611,7 @@
|
|||
"REPEAT": "Repetir",
|
||||
"SCHEDULE_TASK": "Agendar Tarefa",
|
||||
"SUB_TASKS": "Subtarefas ({{nr}})",
|
||||
"TIME": "tempo"
|
||||
"TIME": "Tempo"
|
||||
},
|
||||
"ADD_TASK_BAR": {
|
||||
"ADD_EXISTING_TASK": "Adicionar tarefa existente \"{{taskTitle}}\"",
|
||||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "Dispensar",
|
||||
"DO_IT": "Fazer isto!",
|
||||
"EDIT": "Editar",
|
||||
"EXTENSION_INFO": "Por favor <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> faça o download da extensão chrome</a> para permitir a comunicação com o Jira Api e o Idle Time Handling. Observe que isso não funciona para dispositivos móveis.",
|
||||
"EXTENSION_INFO": "Por favor <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> faça o download da extensão chrome</a> para permitir a comunicação com o Jira Api e o Idle Time Handling. Observe que isso não funciona para dispositivos móveis.",
|
||||
"LOGIN": "Login",
|
||||
"LOGOUT": "Sair",
|
||||
"MINUTES": "{{m}} minutos",
|
||||
|
|
@ -912,22 +912,23 @@
|
|||
"ZOOM_OUT": "Diminuir o zoom (somente para computador)"
|
||||
},
|
||||
"LANG": {
|
||||
"AR": "Arabic",
|
||||
"DE": "German",
|
||||
"EN": "English",
|
||||
"ES": "Spanish",
|
||||
"AR": "Árabe",
|
||||
"DE": "Alemão",
|
||||
"EN": "Inglês",
|
||||
"ES": "Espanhol",
|
||||
"FA": "Persa",
|
||||
"FR": "French",
|
||||
"IT": "italiano",
|
||||
"JA": "Japanese",
|
||||
"KO": "Korean",
|
||||
"LABEL": "Please select a language",
|
||||
"FR": "Francês",
|
||||
"IT": "Italiano",
|
||||
"JA": "Japonês",
|
||||
"KO": "Coreano",
|
||||
"LABEL": "Por favor escolha um idioma",
|
||||
"NB": "Bokmål norueguês",
|
||||
"NL": "Holandês",
|
||||
"PT": "português",
|
||||
"RU": "Russian",
|
||||
"TITLE": "Language",
|
||||
"TR": "Turkish",
|
||||
"ZH": "Chinese"
|
||||
"PT": "Português",
|
||||
"RU": "Russo",
|
||||
"TITLE": "Idioma",
|
||||
"TR": "Turco",
|
||||
"ZH": "Chinês"
|
||||
},
|
||||
"MISC": {
|
||||
"DEFAULT_PROJECT": "Projeto padrão a ser usado para tarefas se nenhum for especificado",
|
||||
|
|
@ -1114,10 +1115,10 @@
|
|||
"indigo": "índigo",
|
||||
"light-blue": "azul claro",
|
||||
"light-green": "verde claro",
|
||||
"lime": "Lima",
|
||||
"pink": "Rosa",
|
||||
"lime": "lima",
|
||||
"pink": "rosa",
|
||||
"purple": "roxa",
|
||||
"teal": "teal",
|
||||
"teal": "azul petróleo",
|
||||
"yellow": "amarelo"
|
||||
},
|
||||
"V": {
|
||||
|
|
@ -1140,7 +1141,7 @@
|
|||
"NO_COMPLETED_TASKS": "No momento, não há tarefas concluídas",
|
||||
"NO_PLANNED_TASKS": "Nenhuma tarefa planejada",
|
||||
"READY_TO_WORK": "Pronto para trabalhar!",
|
||||
"RESET_BREAK_TIMER": "Reset without break timer",
|
||||
"RESET_BREAK_TIMER": "Reiniciar sem temporizador de pause",
|
||||
"TIME_ESTIMATED": "Tempo estimado:",
|
||||
"WITHOUT_BREAK": "Sem pausa:",
|
||||
"WORKING_TODAY": "Trabalhando hoje:"
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "Отклонить",
|
||||
"DO_IT": "Сделай это!",
|
||||
"EDIT": "Редактировать",
|
||||
"EXTENSION_INFO": "Пожалуйста, <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> загрузите расширение Chrome</a> , чтобы обеспечить связь с Jira Api и Idle Time Handling. Обратите внимание, что это не работает для мобильных устройств.",
|
||||
"EXTENSION_INFO": "Пожалуйста, <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> загрузите расширение Chrome</a> , чтобы обеспечить связь с Jira Api и Idle Time Handling. Обратите внимание, что это не работает для мобильных устройств.",
|
||||
"LOGIN": "Авторизоваться",
|
||||
"LOGOUT": "Выйти",
|
||||
"MINUTES": "{{m}} минут",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "Японский",
|
||||
"KO": "Корейский",
|
||||
"LABEL": "Пожалуйста, выберите язык",
|
||||
"NB": "Норвежский букмол",
|
||||
"NL": "голландский",
|
||||
"PT": "португальский",
|
||||
"RU": "Русский",
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "Reddet",
|
||||
"DO_IT": "Yap!",
|
||||
"EDIT": "Düzenle",
|
||||
"EXTENSION_INFO": "Jira Api ve Idle Time Handling ile iletişime izin vermek için lütfen <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> krom uzantısını</a> indirin. Bunun mobil cihazlar için işe yaramadığını unutmayın.",
|
||||
"EXTENSION_INFO": "Jira Api ve Idle Time Handling ile iletişime izin vermek için lütfen <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> krom uzantısını</a> indirin. Bunun mobil cihazlar için işe yaramadığını unutmayın.",
|
||||
"LOGIN": "Oturum aç",
|
||||
"LOGOUT": "Çıkış Yap",
|
||||
"MINUTES": "{{m}} dakika",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "Japonca",
|
||||
"KO": "Koreli",
|
||||
"LABEL": "Lütfen bir dil seçin",
|
||||
"NB": "Norveççe Bokmål",
|
||||
"NL": "Flemenkçe",
|
||||
"PT": "Portekizce",
|
||||
"RU": "Rusça",
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@
|
|||
"DISMISS": "取消",
|
||||
"DO_IT": "开始吧!",
|
||||
"EDIT": "编辑",
|
||||
"EXTENSION_INFO": "请 <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb'}\"> 下载Chrome扩展程序</a> ,以便与Jira Api和空闲时间处理进行通信。请注意,这不适用于移动设备。",
|
||||
"EXTENSION_INFO": "请 <a target=\"_blank\" href=\"https://chrome.google.com/webstore/detail/super-productivity/ljkbjodfmekklcoibdnhahlaalhihmlb\"> 下载Chrome扩展程序</a> ,以便与Jira Api和空闲时间处理进行通信。请注意,这不适用于移动设备。",
|
||||
"LOGIN": "登录",
|
||||
"LOGOUT": "登出",
|
||||
"MINUTES": "{{m}} 分钟",
|
||||
|
|
@ -922,6 +922,7 @@
|
|||
"JA": "日本语",
|
||||
"KO": "朝鲜语",
|
||||
"LABEL": "请选择一种语言",
|
||||
"NB": "挪威语 Bokmål",
|
||||
"NL": "荷兰语",
|
||||
"PT": "葡萄牙语",
|
||||
"RU": "俄语",
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ TODO configure more restrictive Content-Security-Policy
|
|||
<meta content="default-src *;
|
||||
frame-src * data:;
|
||||
font-src * data:;
|
||||
img-src * data:;
|
||||
img-src * data: filesystem: file:;
|
||||
style-src * 'unsafe-inline' ;
|
||||
script-src * 'self' 'unsafe-inline' 'unsafe-eval'"
|
||||
http-equiv="Content-Security-Policy">
|
||||
|
|
@ -190,7 +190,13 @@ TODO configure more restrictive Content-Security-Policy
|
|||
['Mess creates stress', 'Clean up your desk!'],
|
||||
['Focus on a single task', 'Multi-tasking is the worst.'],
|
||||
['Set your goals', 'Having a goal to aim for (or even some smaller ones) increases motivation and focus. Remind yourself why you are doing something.'],
|
||||
['Try to get it right the first time', 'This can help you to avoid dragging a task on forever.']
|
||||
['Try to get it right the first time', 'This can help you to avoid dragging a task on forever.'],
|
||||
['We are what we repeatedly do.', 'Excellence, then, is not an act, but a habit. - Aristotle'],
|
||||
['You don’t learn to walk by following rules.', 'You learn by doing, and by falling over. - Richard Branson'],
|
||||
['A problem well-put is half-solved', '- John Dewey'],
|
||||
['Wisdom is learning what to overlook', '- William James'],
|
||||
['It is not that I’m so smart', 'But I stay with the questions much longer - Albert Einstein'],
|
||||
['No problem can withstand the assault of sustained thinking', '- Voltaire'],
|
||||
];
|
||||
var randomIndex = Math.floor(Math.random() * productivityTips.length);
|
||||
document.getElementById('heading').innerText = productivityTips[randomIndex][0];
|
||||
|
|
|
|||
|
|
@ -16,9 +16,15 @@ platformBrowserDynamic().bootstrapModule(AppModule).then(() => {
|
|||
if ('serviceWorker' in navigator && (environment.production || environment.stage) && !IS_ELECTRON) {
|
||||
console.log('Registering Service worker');
|
||||
return navigator.serviceWorker.register('ngsw-worker.js');
|
||||
} else if ('serviceWorker' in navigator && IS_ELECTRON) {
|
||||
navigator.serviceWorker.getRegistrations().then((registrations) => {
|
||||
for (const registration of registrations) {
|
||||
registration.unregister();
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}).catch(err => {
|
||||
}).catch((err: any) => {
|
||||
console.log('Service Worker Registration Error');
|
||||
console.log(err);
|
||||
});
|
||||
|
|
|
|||
19
yarn.lock
19
yarn.lock
|
|
@ -4468,6 +4468,15 @@ ejs@^3.1.3:
|
|||
dependencies:
|
||||
jake "^10.6.1"
|
||||
|
||||
electron-builder-notarize@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-builder-notarize/-/electron-builder-notarize-1.2.0.tgz#6db86173601513bcb667074f80322f8622e24ff9"
|
||||
integrity sha512-mSU5CSjydNlO5oFSOimJvzKQ4m/whUUBoE3i2xSAOF7+T2ZIzSfsGCT1SJvqsiHYf2xvTb2RpFoHWE6Oc9Cvgg==
|
||||
dependencies:
|
||||
electron-notarize "^0.2.0"
|
||||
js-yaml "^3.14.0"
|
||||
read-pkg-up "^7.0.0"
|
||||
|
||||
electron-builder@^22.7.0:
|
||||
version "22.8.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-22.8.1.tgz#84295190dae17b3892df7aa39ac334983aeaea06"
|
||||
|
|
@ -4517,6 +4526,14 @@ electron-log@^4.2.2:
|
|||
resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-4.2.4.tgz#a13e42a9fc42ca2cc7d2603c3746352efa82112e"
|
||||
integrity sha512-CXbDU+Iwi+TjKzugKZmTRIORIPe3uQRqgChUl19fkW/reFUn5WP7dt+cNGT3bkLV8xfPilpkPFv33HgtmLLewQ==
|
||||
|
||||
electron-notarize@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-notarize/-/electron-notarize-0.2.1.tgz#759e8006decae19134f82996ed910db26d9192cc"
|
||||
integrity sha512-oZ6/NhKeXmEKNROiFmRNfytqu3cxqC95sjooG7kBXQVEUSQkZnbiAhxVh5jXngL881G197pbwpeVPJyM7Ikmxw==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
fs-extra "^8.1.0"
|
||||
|
||||
electron-notarize@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-notarize/-/electron-notarize-1.0.0.tgz#bc925b1ccc3f79e58e029e8c4706572b01a9fd8f"
|
||||
|
|
@ -10016,7 +10033,7 @@ read-pkg-up@^3.0.0:
|
|||
find-up "^2.0.0"
|
||||
read-pkg "^3.0.0"
|
||||
|
||||
read-pkg-up@^7.0.1:
|
||||
read-pkg-up@^7.0.0, read-pkg-up@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
|
||||
integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue