Merge pull request #331 from jat255/add_elevation_chart_preference

Add elevation chart preference
This commit is contained in:
Sam 2023-04-08 11:12:00 +02:00 committed by GitHub
commit 337a882506
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 111 additions and 15 deletions

View File

@ -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:

View File

@ -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>

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

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

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

View File

@ -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 ###

View File

@ -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'

View File

@ -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()

View File

@ -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,
}, },

View File

@ -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')">

View File

@ -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
} }

View File

@ -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)
) )

View File

@ -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",

View File

@ -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",

View File

@ -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