Merge pull request #331 from jat255/add_elevation_chart_preference
Add elevation chart preference
This commit is contained in:
commit
337a882506
3
Makefile
3
Makefile
@ -55,6 +55,9 @@ docker-build-client:
|
|||||||
|
|
||||||
docker-check-all: docker-bandit docker-lint-all docker-type-check docker-test-client docker-test-python
|
docker-check-all: docker-bandit docker-lint-all docker-type-check docker-test-client docker-test-python
|
||||||
|
|
||||||
|
docker-downgrade-db:
|
||||||
|
docker-compose -f docker-compose-dev.yml exec fittrackee $(DOCKER_FLASK) db downgrade --directory $(DOCKER_MIGRATIONS)
|
||||||
|
|
||||||
docker-init: docker-run docker-init-db docker-restart docker-run-workers
|
docker-init: docker-run docker-init-db docker-restart docker-run-workers
|
||||||
|
|
||||||
docker-init-db:
|
docker-init-db:
|
||||||
|
2
fittrackee/dist/index.html
vendored
2
fittrackee/dist/index.html
vendored
@ -1 +1 @@
|
|||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.01cb48d3.js"></script><script defer="defer" src="/static/js/app.9225ef92.js"></script><link href="/static/css/app.38b148d9.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.01cb48d3.js"></script><script defer="defer" src="/static/js/app.fbd9f0c5.js"></script><link href="/static/css/app.5f8309dc.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
2
fittrackee/dist/service-worker.js
vendored
2
fittrackee/dist/service-worker.js
vendored
File diff suppressed because one or more lines are too long
2
fittrackee/dist/service-worker.js.map
vendored
2
fittrackee/dist/service-worker.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
fittrackee/dist/static/js/app.9225ef92.js
vendored
2
fittrackee/dist/static/js/app.9225ef92.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
fittrackee/dist/static/js/app.fbd9f0c5.js
vendored
Normal file
2
fittrackee/dist/static/js/app.fbd9f0c5.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
fittrackee/dist/static/js/app.fbd9f0c5.js.map
vendored
Normal file
1
fittrackee/dist/static/js/app.fbd9f0c5.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
fittrackee/dist/static/js/workouts.fd4ab6ab.js.map
vendored
Normal file
1
fittrackee/dist/static/js/workouts.fd4ab6ab.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,35 @@
|
|||||||
|
"""add user preference to start elevation plots at zero
|
||||||
|
|
||||||
|
Revision ID: db58d195c5bf
|
||||||
|
Revises: 374a670efe23
|
||||||
|
Create Date: 2023-03-14 04:14:23.781672
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'db58d195c5bf'
|
||||||
|
down_revision = '374a670efe23'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('users', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('start_elevation_at_zero', sa.Boolean(), nullable=True))
|
||||||
|
op.execute("UPDATE users SET start_elevation_at_zero = true")
|
||||||
|
op.alter_column('users', 'start_elevation_at_zero', nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('users', schema=None) as batch_op:
|
||||||
|
batch_op.drop_column('start_elevation_at_zero')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
@ -1482,6 +1482,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin):
|
|||||||
language=input_language,
|
language=input_language,
|
||||||
imperial_units=True,
|
imperial_units=True,
|
||||||
display_ascent=False,
|
display_ascent=False,
|
||||||
|
start_elevation_at_zero=False,
|
||||||
date_format='yyyy-MM-dd',
|
date_format='yyyy-MM-dd',
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
@ -1493,6 +1494,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin):
|
|||||||
assert data['status'] == 'success'
|
assert data['status'] == 'success'
|
||||||
assert data['message'] == 'user preferences updated'
|
assert data['message'] == 'user preferences updated'
|
||||||
assert data['data']['display_ascent'] is False
|
assert data['data']['display_ascent'] is False
|
||||||
|
assert data['data']['start_elevation_at_zero'] is False
|
||||||
assert data['data']['imperial_units'] is True
|
assert data['data']['imperial_units'] is True
|
||||||
assert data['data']['language'] == expected_language
|
assert data['data']['language'] == expected_language
|
||||||
assert data['data']['timezone'] == 'America/New_York'
|
assert data['data']['timezone'] == 'America/New_York'
|
||||||
|
@ -869,6 +869,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
4,
|
4,
|
||||||
6
|
6
|
||||||
],
|
],
|
||||||
|
"start_elevation_at_zero": true,
|
||||||
"timezone": "Europe/Paris",
|
"timezone": "Europe/Paris",
|
||||||
"total_distance": 67.895,
|
"total_distance": 67.895,
|
||||||
"total_duration": "6:50:27",
|
"total_duration": "6:50:27",
|
||||||
@ -883,9 +884,9 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
:<json boolean display_ascent: display highest ascent records and total
|
:<json boolean display_ascent: display highest ascent records and total
|
||||||
:<json boolean imperial_units: display distance in imperial units
|
:<json boolean imperial_units: display distance in imperial units
|
||||||
:<json string language: language preferences
|
:<json string language: language preferences
|
||||||
|
:<json boolean start_elevation_at_zero: do elevation plots start at zero?
|
||||||
:<json string timezone: user time zone
|
:<json string timezone: user time zone
|
||||||
:<json boolean weekm: does week start on Monday?
|
:<json boolean weekm: does week start on Monday?
|
||||||
:<json boolean weekm: does week start on Monday?
|
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
|
|
||||||
@ -906,6 +907,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
'display_ascent',
|
'display_ascent',
|
||||||
'imperial_units',
|
'imperial_units',
|
||||||
'language',
|
'language',
|
||||||
|
'start_elevation_at_zero',
|
||||||
'timezone',
|
'timezone',
|
||||||
'weekm',
|
'weekm',
|
||||||
}
|
}
|
||||||
@ -916,6 +918,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
display_ascent = post_data.get('display_ascent')
|
display_ascent = post_data.get('display_ascent')
|
||||||
imperial_units = post_data.get('imperial_units')
|
imperial_units = post_data.get('imperial_units')
|
||||||
language = get_language(post_data.get('language'))
|
language = get_language(post_data.get('language'))
|
||||||
|
start_elevation_at_zero = post_data.get('start_elevation_at_zero')
|
||||||
timezone = post_data.get('timezone')
|
timezone = post_data.get('timezone')
|
||||||
weekm = post_data.get('weekm')
|
weekm = post_data.get('weekm')
|
||||||
|
|
||||||
@ -924,6 +927,7 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
|
|||||||
auth_user.display_ascent = display_ascent
|
auth_user.display_ascent = display_ascent
|
||||||
auth_user.imperial_units = imperial_units
|
auth_user.imperial_units = imperial_units
|
||||||
auth_user.language = language
|
auth_user.language = language
|
||||||
|
auth_user.start_elevation_at_zero = start_elevation_at_zero
|
||||||
auth_user.timezone = timezone
|
auth_user.timezone = timezone
|
||||||
auth_user.weekm = weekm
|
auth_user.weekm = weekm
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -59,6 +59,9 @@ class User(BaseModel):
|
|||||||
confirmation_token = db.Column(db.String(255), nullable=True)
|
confirmation_token = db.Column(db.String(255), nullable=True)
|
||||||
display_ascent = db.Column(db.Boolean, default=True, nullable=False)
|
display_ascent = db.Column(db.Boolean, default=True, nullable=False)
|
||||||
accepted_policy_date = db.Column(db.DateTime, nullable=True)
|
accepted_policy_date = db.Column(db.DateTime, nullable=True)
|
||||||
|
start_elevation_at_zero = db.Column(
|
||||||
|
db.Boolean, default=True, nullable=False
|
||||||
|
)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'<User {self.username!r}>'
|
return f'<User {self.username!r}>'
|
||||||
@ -211,6 +214,7 @@ class User(BaseModel):
|
|||||||
'display_ascent': self.display_ascent,
|
'display_ascent': self.display_ascent,
|
||||||
'imperial_units': self.imperial_units,
|
'imperial_units': self.imperial_units,
|
||||||
'language': self.language,
|
'language': self.language,
|
||||||
|
'start_elevation_at_zero': self.start_elevation_at_zero,
|
||||||
'timezone': self.timezone,
|
'timezone': self.timezone,
|
||||||
'weekm': self.weekm,
|
'weekm': self.weekm,
|
||||||
},
|
},
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
</dd>
|
</dd>
|
||||||
<dt>{{ $t('user.PROFILE.ASCENT_DATA') }}:</dt>
|
<dt>{{ $t('user.PROFILE.ASCENT_DATA') }}:</dt>
|
||||||
<dd>{{ $t(`common.${display_ascent}`) }}</dd>
|
<dd>{{ $t(`common.${display_ascent}`) }}</dd>
|
||||||
|
<dt>{{ $t('user.PROFILE.ELEVATION_CHART_START.LABEL') }}:</dt>
|
||||||
|
<dd>{{ $t(`user.PROFILE.ELEVATION_CHART_START.${user.start_elevation_at_zero ? 'ZERO' : 'MIN_ALT'}`) }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<div class="profile-buttons">
|
<div class="profile-buttons">
|
||||||
<button @click="$router.push('/profile/edit/preferences')">
|
<button @click="$router.push('/profile/edit/preferences')">
|
||||||
|
@ -99,6 +99,26 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-items form-checkboxes">
|
||||||
|
<span class="checkboxes-label">
|
||||||
|
{{ $t('user.PROFILE.ELEVATION_CHART_START.LABEL') }}
|
||||||
|
</span>
|
||||||
|
<div class="checkboxes">
|
||||||
|
<label v-for="status in startElevationAtZeroData" :key="status.label">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
:id="status.label"
|
||||||
|
:name="status.label"
|
||||||
|
:checked="status.value === userForm.start_elevation_at_zero"
|
||||||
|
:disabled="loading"
|
||||||
|
@input="updateStartElevationAtZero(status.value)"
|
||||||
|
/>
|
||||||
|
<span class="checkbox-label">
|
||||||
|
{{ $t(`user.PROFILE.ELEVATION_CHART_START.${status.label}`) }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-buttons">
|
<div class="form-buttons">
|
||||||
<button class="confirm" type="submit">
|
<button class="confirm" type="submit">
|
||||||
{{ $t('buttons.SUBMIT') }}
|
{{ $t('buttons.SUBMIT') }}
|
||||||
@ -170,6 +190,16 @@
|
|||||||
value: false,
|
value: false,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
const startElevationAtZeroData = [
|
||||||
|
{
|
||||||
|
label: 'ZERO',
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'MIN_ALT',
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
]
|
||||||
const loading = computed(
|
const loading = computed(
|
||||||
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
|
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
|
||||||
)
|
)
|
||||||
@ -192,6 +222,7 @@
|
|||||||
|
|
||||||
function updateUserForm(user: IAuthUserProfile) {
|
function updateUserForm(user: IAuthUserProfile) {
|
||||||
userForm.display_ascent = user.display_ascent
|
userForm.display_ascent = user.display_ascent
|
||||||
|
userForm.start_elevation_at_zero = user.start_elevation_at_zero ? user.start_elevation_at_zero : false
|
||||||
userForm.imperial_units = user.imperial_units ? user.imperial_units : false
|
userForm.imperial_units = user.imperial_units ? user.imperial_units : false
|
||||||
userForm.language = user.language ? user.language : 'en'
|
userForm.language = user.language ? user.language : 'en'
|
||||||
userForm.timezone = user.timezone ? user.timezone : 'Europe/Paris'
|
userForm.timezone = user.timezone ? user.timezone : 'Europe/Paris'
|
||||||
@ -204,6 +235,9 @@
|
|||||||
function updateTZ(value: string) {
|
function updateTZ(value: string) {
|
||||||
userForm.timezone = value
|
userForm.timezone = value
|
||||||
}
|
}
|
||||||
|
function updateStartElevationAtZero(value: boolean) {
|
||||||
|
userForm.start_elevation_at_zero = value
|
||||||
|
}
|
||||||
function updateAscentDisplay(value: boolean) {
|
function updateAscentDisplay(value: boolean) {
|
||||||
userForm.display_ascent = value
|
userForm.display_ascent = value
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const displayDistance = ref(true)
|
const displayDistance = ref(true)
|
||||||
const beginElevationAtZero = ref(true)
|
const beginElevationAtZero = ref(props.authUser.start_elevation_at_zero)
|
||||||
const datasets: ComputedRef<IWorkoutChartData> = computed(() =>
|
const datasets: ComputedRef<IWorkoutChartData> = computed(() =>
|
||||||
getDatasets(props.workoutData.chartData, t, props.authUser.imperial_units)
|
getDatasets(props.workoutData.chartData, t, props.authUser.imperial_units)
|
||||||
)
|
)
|
||||||
|
@ -69,6 +69,11 @@
|
|||||||
"EDIT_PREFERENCES": "Edit preferences",
|
"EDIT_PREFERENCES": "Edit preferences",
|
||||||
"EDIT_SPORTS_PREFERENCES": "Edit sports preferences",
|
"EDIT_SPORTS_PREFERENCES": "Edit sports preferences",
|
||||||
"ERRORED_EMAIL_UPDATE": "Please {0} to change your email address again or contact the administrator",
|
"ERRORED_EMAIL_UPDATE": "Please {0} to change your email address again or contact the administrator",
|
||||||
|
"ELEVATION_CHART_START": {
|
||||||
|
"LABEL": "Elevation chart starts at",
|
||||||
|
"ZERO": "Zero",
|
||||||
|
"MIN_ALT": "Minimum altitude"
|
||||||
|
},
|
||||||
"FIRST_DAY_OF_WEEK": "First day of week",
|
"FIRST_DAY_OF_WEEK": "First day of week",
|
||||||
"FIRST_NAME": "First name",
|
"FIRST_NAME": "First name",
|
||||||
"LANGUAGE": "Language",
|
"LANGUAGE": "Language",
|
||||||
|
@ -68,6 +68,11 @@
|
|||||||
"EDIT": "Modifier le profil",
|
"EDIT": "Modifier le profil",
|
||||||
"EDIT_PREFERENCES": "Modifier les préférences",
|
"EDIT_PREFERENCES": "Modifier les préférences",
|
||||||
"EDIT_SPORTS_PREFERENCES": "Modifier les préférences des sports",
|
"EDIT_SPORTS_PREFERENCES": "Modifier les préférences des sports",
|
||||||
|
"ELEVATION_CHART_START": {
|
||||||
|
"LABEL": "Début de l'axe pour le graphe affichant l'altitude",
|
||||||
|
"ZERO": "0",
|
||||||
|
"MIN_ALT": "Altitude minimale"
|
||||||
|
},
|
||||||
"ERRORED_EMAIL_UPDATE": "Veuillez vous {0} pour changer de nouveau votre adresse électronique ou contacter l'administrateur",
|
"ERRORED_EMAIL_UPDATE": "Veuillez vous {0} pour changer de nouveau votre adresse électronique ou contacter l'administrateur",
|
||||||
"FIRST_DAY_OF_WEEK": "Premier jour de la semaine",
|
"FIRST_DAY_OF_WEEK": "Premier jour de la semaine",
|
||||||
"FIRST_NAME": "Prénom",
|
"FIRST_NAME": "Prénom",
|
||||||
|
@ -28,6 +28,7 @@ export interface IAuthUserProfile extends IUserProfile {
|
|||||||
accepted_privacy_policy: boolean
|
accepted_privacy_policy: boolean
|
||||||
display_ascent: boolean
|
display_ascent: boolean
|
||||||
imperial_units: boolean
|
imperial_units: boolean
|
||||||
|
start_elevation_at_zero: boolean
|
||||||
language: string | null
|
language: string | null
|
||||||
timezone: string
|
timezone: string
|
||||||
date_format: string
|
date_format: string
|
||||||
@ -63,6 +64,7 @@ export interface IAdminUserPayload {
|
|||||||
|
|
||||||
export interface IUserPreferencesPayload {
|
export interface IUserPreferencesPayload {
|
||||||
display_ascent: boolean
|
display_ascent: boolean
|
||||||
|
start_elevation_at_zero: boolean
|
||||||
imperial_units: boolean
|
imperial_units: boolean
|
||||||
language: string
|
language: string
|
||||||
timezone: string
|
timezone: string
|
||||||
|
Loading…
Reference in New Issue
Block a user