forked from CIT/Vmeda.Online
		
	Merge pull request #2761 from crazyserver/MOBILE-3320
MOBILE-3320 lang: Use AWS to update lang files
This commit is contained in:
		
						commit
						8c16e648c9
					
				
							
								
								
									
										29
									
								
								.github/workflows/e2e.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								.github/workflows/e2e.yml
									
									
									
									
										vendored
									
									
								
							@ -15,14 +15,21 @@ jobs:
 | 
			
		||||
      uses: actions/setup-node@v1
 | 
			
		||||
      with:
 | 
			
		||||
        node-version: '12.x'
 | 
			
		||||
    - run: npm ci
 | 
			
		||||
    - run: git clone --branch master --depth 1 git://github.com/moodle/moodle $GITHUB_WORKSPACE/moodle
 | 
			
		||||
    - run: git clone --branch ionic5 --depth 1 git://github.com/moodlehq/moodle-local_moodlemobileapp $GITHUB_WORKSPACE/moodle/local/moodlemobileapp
 | 
			
		||||
    - run: git clone --branch MOBILE-3738 --depth 1 git://github.com/NoelDeMartin/moodle-docker $GITHUB_WORKSPACE/moodle-docker
 | 
			
		||||
    - run: cp $GITHUB_WORKSPACE/moodle-docker/config.docker-template.php $GITHUB_WORKSPACE/moodle/config.php
 | 
			
		||||
    - run: MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-compose pull
 | 
			
		||||
    - run: MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-compose up -d
 | 
			
		||||
    - run: MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-wait-for-db
 | 
			
		||||
    - run: MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-wait-for-app
 | 
			
		||||
    - run: MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-compose exec -T webserver sh -c "php admin/tool/behat/cli/init.php"
 | 
			
		||||
    - run: MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-compose exec -T webserver sh -c "php admin/tool/behat/cli/run.php --tags="@app" --auto-rerun"
 | 
			
		||||
    - name: Install npm packages
 | 
			
		||||
      run: npm ci
 | 
			
		||||
    - name: Additional checkouts
 | 
			
		||||
      run: |
 | 
			
		||||
        git clone --branch master --depth 1 git://github.com/moodle/moodle $GITHUB_WORKSPACE/moodle
 | 
			
		||||
        git clone --branch ionic5 --depth 1 git://github.com/moodlehq/moodle-local_moodlemobileapp $GITHUB_WORKSPACE/moodle/local/moodlemobileapp
 | 
			
		||||
        git clone --branch MOBILE-3738 --depth 1 git://github.com/NoelDeMartin/moodle-docker $GITHUB_WORKSPACE/moodle-docker
 | 
			
		||||
    - name: Setup docker machine
 | 
			
		||||
      run: |
 | 
			
		||||
        cp $GITHUB_WORKSPACE/moodle-docker/config.docker-template.php $GITHUB_WORKSPACE/moodle/config.php
 | 
			
		||||
        MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-compose pull
 | 
			
		||||
        MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-compose up -d
 | 
			
		||||
        MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-wait-for-db
 | 
			
		||||
        MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-wait-for-app
 | 
			
		||||
    - name: Init behat
 | 
			
		||||
      run: MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-compose exec -T webserver sh -c "php admin/tool/behat/cli/init.php"
 | 
			
		||||
    - name: Run tests
 | 
			
		||||
      run: MOODLE_DOCKER_WWWROOT=$GITHUB_WORKSPACE/moodle MOODLE_DOCKER_APP_PATH=$GITHUB_WORKSPACE $GITHUB_WORKSPACE/moodle-docker/bin/moodle-docker-compose exec -T webserver sh -c "php admin/tool/behat/cli/run.php --tags="@app" --auto-rerun"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										47
									
								
								.github/workflows/testing.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								.github/workflows/testing.yml
									
									
									
									
										vendored
									
									
								
							@ -13,8 +13,45 @@ jobs:
 | 
			
		||||
      uses: actions/setup-node@v1
 | 
			
		||||
      with:
 | 
			
		||||
        node-version: '12.x'
 | 
			
		||||
    - run: npm ci
 | 
			
		||||
    - run: npm run lint
 | 
			
		||||
    - run: npm run test:ci
 | 
			
		||||
    - run: npm run build:prod
 | 
			
		||||
    - run: result=$(npx check-es-compat www/*.js 2> /dev/null | grep -v -E "Array\.prototype\.includes|Promise\.prototype\.finally|String\.prototype\.(matchAll|trimRight)|globalThis" | grep -Po "(?<=error).*?(?=\s+ecmascript)" | wc -l); test $result -eq 0
 | 
			
		||||
    - name: Install npm packages
 | 
			
		||||
      run: npm ci
 | 
			
		||||
    - name: Check langindex
 | 
			
		||||
      run: |
 | 
			
		||||
        result=$(cat scripts/langindex.json | grep \"TBD\" | wc -l); test $result -eq 0
 | 
			
		||||
        if [ $result -ne 0 ]; then
 | 
			
		||||
          echo "There are lang strings to be decided on langindex.json"
 | 
			
		||||
          exit 1
 | 
			
		||||
        fi
 | 
			
		||||
        gulp
 | 
			
		||||
        langlength=`jq -r '. | length' src/assets/lang/en.json`
 | 
			
		||||
        langindexlength=`jq -r '. | length' scripts/langindex.json`
 | 
			
		||||
        if [ $langlength -ne $langindexlength ]; then
 | 
			
		||||
          echo "Lang file has $langlength while langindex $langindexlength"
 | 
			
		||||
          exit 1
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        langkeys=`jq -r 'keys[]' src/assets/lang/en.json`
 | 
			
		||||
        langindex=`jq -r 'keys[]' scripts/langindex.json`
 | 
			
		||||
        found=0
 | 
			
		||||
        for i in $langkeys; do
 | 
			
		||||
            skip=
 | 
			
		||||
            for j in $langindex; do
 | 
			
		||||
                if [ "$i" == "$j" ]; then
 | 
			
		||||
                  skip=1
 | 
			
		||||
                  break;
 | 
			
		||||
                fi
 | 
			
		||||
            done
 | 
			
		||||
            [[ -n $skip ]] || { echo "$i key not found"; found=$(($found + 1)); }
 | 
			
		||||
        done
 | 
			
		||||
        if [ $found -ne 0 ]; then
 | 
			
		||||
          echo "Found $found missing langkeys"
 | 
			
		||||
          exit 1
 | 
			
		||||
        fi
 | 
			
		||||
    - name: Run Linter
 | 
			
		||||
      run: npm run lint
 | 
			
		||||
    - name: Run tests
 | 
			
		||||
      run: npm run test:ci
 | 
			
		||||
    - name: Production builds
 | 
			
		||||
      run: npm run build:prod
 | 
			
		||||
    - name: JavaScript code compatibility
 | 
			
		||||
      run: result=$(npx check-es-compat www/*.js 2> /dev/null | grep -v -E "Array\.prototype\.includes|Promise\.prototype\.finally|String\.prototype\.(matchAll|trimRight)|globalThis" | grep -Po "(?<=error).*?(?=\s+ecmascript)" | wc -l); test $result -eq 0
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,12 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
#
 | 
			
		||||
# Script to create langindex from available language packs.
 | 
			
		||||
# ./create_langindex.sh [findbetter]
 | 
			
		||||
# If findbetter is set it will try to find a better solution for every key.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
source "functions.sh"
 | 
			
		||||
source "lang_functions.sh"
 | 
			
		||||
 | 
			
		||||
#Saves or updates a key on langindex_old.json
 | 
			
		||||
function save_key {
 | 
			
		||||
@ -48,7 +55,8 @@ function exists_in_mobile {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function do_match {
 | 
			
		||||
    match=$1
 | 
			
		||||
    match=${1/\{\{/\{}
 | 
			
		||||
    match=${match/\}\}/\}}
 | 
			
		||||
    filematch=""
 | 
			
		||||
 | 
			
		||||
    coincidence=`grep "$match" $LANGPACKSFOLDER/en/*.php | wc -l`
 | 
			
		||||
@ -56,7 +64,7 @@ function do_match {
 | 
			
		||||
        filematch=`grep "$match" $LANGPACKSFOLDER/en/*.php | cut -d'/' -f5 | cut -d'.' -f1`
 | 
			
		||||
        exists_in_file $filematch $plainid
 | 
			
		||||
    elif [ $coincidence -gt 0 ] && [ "$#" -gt 1 ]; then
 | 
			
		||||
        print_message $2
 | 
			
		||||
        print_message "$2"
 | 
			
		||||
        tput setaf 6
 | 
			
		||||
        grep "$match" $LANGPACKSFOLDER/en/*.php
 | 
			
		||||
    fi
 | 
			
		||||
@ -67,18 +75,21 @@ function find_matches {
 | 
			
		||||
    do_match "string\[\'$plainid\'\] = \'$value\'" "Found EXACT match for $key in the following paths"
 | 
			
		||||
    if [ $coincidence -gt 0 ]; then
 | 
			
		||||
        case=1
 | 
			
		||||
        save_key $key "TBD"
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    do_match " = \'$value\'" "Found some string VALUES for $key in the following paths"
 | 
			
		||||
    if [ $coincidence -gt 0 ]; then
 | 
			
		||||
        case=2
 | 
			
		||||
        save_key $key "TBD"
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    do_match "string\[\'$plainid\'\]" "Found some string KEYS for $key in the following paths, value $value"
 | 
			
		||||
    if [ $coincidence -gt 0 ]; then
 | 
			
		||||
        case=3
 | 
			
		||||
        save_key $key "TBD"
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
@ -297,17 +308,13 @@ function array_contains {
 | 
			
		||||
    done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
print_title 'Generating language from code...'
 | 
			
		||||
gulp lang
 | 
			
		||||
 | 
			
		||||
print_title 'Getting languages'
 | 
			
		||||
git clone https://git.in.moodle.com/moodle/moodle-langpacks.git $LANGPACKSFOLDER
 | 
			
		||||
pushd $LANGPACKSFOLDER
 | 
			
		||||
BRANCHES=($(git branch -r --format="%(refname:lstrip=3)" --sort="refname" | grep MOODLE_))
 | 
			
		||||
BRANCH=${BRANCHES[${#BRANCHES[@]}-1]}
 | 
			
		||||
git checkout $BRANCH
 | 
			
		||||
git pull
 | 
			
		||||
popd
 | 
			
		||||
 | 
			
		||||
get_language en
 | 
			
		||||
 | 
			
		||||
print_title 'Processing file'
 | 
			
		||||
#Create langindex.json if not exists.
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
LANGPACKSFOLDER='../../moodle-langpacks'
 | 
			
		||||
 | 
			
		||||
function check_success_exit {
 | 
			
		||||
    if [ $? -ne 0 ]; then
 | 
			
		||||
        print_error "$1"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										132
									
								
								scripts/lang_functions.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										132
									
								
								scripts/lang_functions.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,132 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
#
 | 
			
		||||
# Functions to fetch languages.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
LANGPACKSFOLDER='../../moodle-langpacks'
 | 
			
		||||
BUCKET='moodle-lang-prod'
 | 
			
		||||
MOODLEORG_URL='https://download.moodle.org/download.php/direct/langpack'
 | 
			
		||||
DEFAULT_LASTVERSION='4.0'
 | 
			
		||||
 | 
			
		||||
# Checks if AWS is available and configured.
 | 
			
		||||
function check_aws {
 | 
			
		||||
    aws --version &> /dev/null
 | 
			
		||||
    AWS_SERVICE=1
 | 
			
		||||
    if [ $? -ne 0 ]; then
 | 
			
		||||
        AWS_SERVICE=0
 | 
			
		||||
        echo 'AWS not installed. Check https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html for more info.'
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # In order to login to AWS, use credentials file or AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY vars.
 | 
			
		||||
    if [ ! -f ~/.aws/credentials ] && [ [ -z $AWS_ACCESS_KEY_ID ] || [ -z $AWS_SECRET_ACCESS_KEY ] ]; then
 | 
			
		||||
        AWS_SERVICE=0
 | 
			
		||||
        lastversion=$DEFAULT_LASTVERSION
 | 
			
		||||
        echo 'AWS Cannot authenticate. Use aws configure or set the proper env vars.'
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Get last version of Moodle to fetch latest languages.
 | 
			
		||||
function get_last_version {
 | 
			
		||||
    if [ ! -z "${lastversion}" ]; then
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    check_aws
 | 
			
		||||
    if [ $AWS_SERVICE -eq 0 ]; then
 | 
			
		||||
        lastversion=$DEFAULT_LASTVERSION
 | 
			
		||||
        echo "Using default version $lastversion"
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    list=`aws s3 ls s3://$BUCKET/`
 | 
			
		||||
    if [ $? -ne 0 ]; then
 | 
			
		||||
        AWS_SERVICE=0
 | 
			
		||||
        lastversion=$DEFAULT_LASTVERSION
 | 
			
		||||
        echo "AWS Cannot authenticate. Using default version $lastversion"
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    lastversion=''
 | 
			
		||||
    for folder in $list; do
 | 
			
		||||
        if [ $folder != 'PRE' ]; then
 | 
			
		||||
            lastversion=${folder/\//}
 | 
			
		||||
        fi
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    if [ ! -z "${lastversion}" ]; then
 | 
			
		||||
        echo "Last version $lastversion detected"
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    lastversion=$DEFAULT_LASTVERSION
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Get all language list from AWS.
 | 
			
		||||
function get_all_languages_aws {
 | 
			
		||||
    langsfiles=`aws s3 ls s3://$BUCKET/$lastversion/`
 | 
			
		||||
    langs=""
 | 
			
		||||
    for file in $langsfiles; do
 | 
			
		||||
        if [[ "$file" == *.zip ]]; then
 | 
			
		||||
            file=${file/\.zip/}
 | 
			
		||||
            langs+="$file "
 | 
			
		||||
        fi
 | 
			
		||||
    done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Get language list from the installed ones (will not discover new translations).
 | 
			
		||||
function get_installed_languages {
 | 
			
		||||
    langs=`jq -r '.languages | keys[]' ../moodle.config.json`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Entry function to get a language file.
 | 
			
		||||
function get_language {
 | 
			
		||||
    lang=$1
 | 
			
		||||
    lang=${lang/-/_}
 | 
			
		||||
 | 
			
		||||
    get_last_version
 | 
			
		||||
 | 
			
		||||
    echo "Getting $lang language"
 | 
			
		||||
 | 
			
		||||
    pushd $LANGPACKSFOLDER > /dev/null
 | 
			
		||||
 | 
			
		||||
    curl -s $MOODLEORG_URL/$lastversion/$lang.zip --output $lang.zip > /dev/null
 | 
			
		||||
    rm -R $lang
 | 
			
		||||
    unzip -o -u $lang.zip > /dev/null
 | 
			
		||||
 | 
			
		||||
    # This is the AWS version to get the language but right now it's slower.
 | 
			
		||||
    # aws s3 cp s3://$BUCKET/$lastversion/$lang.zip . > /dev/null
 | 
			
		||||
 | 
			
		||||
    rm $lang.zip
 | 
			
		||||
    popd > /dev/null
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Entry function to get all language files.
 | 
			
		||||
function get_languages {
 | 
			
		||||
    get_last_version
 | 
			
		||||
 | 
			
		||||
    if [ -d $LANGPACKSFOLDER ]; then
 | 
			
		||||
        lastupdate=`date -r $LANGPACKSFOLDER +%s`
 | 
			
		||||
        currenttime=`date +%s`
 | 
			
		||||
        ellapsedtime=$((currenttime - lastupdate))
 | 
			
		||||
        if [ $ellapsedtime -lt 3600 ]; then
 | 
			
		||||
            echo 'Recently updated, skip update languages'
 | 
			
		||||
            return
 | 
			
		||||
        fi
 | 
			
		||||
    else
 | 
			
		||||
        mkdir $LANGPACKSFOLDER
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if [ $AWS_SERVICE -eq 1 ]; then
 | 
			
		||||
        get_all_languages_aws
 | 
			
		||||
    else
 | 
			
		||||
        echo "Fallback language list will only get current installation languages"
 | 
			
		||||
        get_installed_languages
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    for lang in $langs; do
 | 
			
		||||
        get_language "$lang"
 | 
			
		||||
    done
 | 
			
		||||
}
 | 
			
		||||
@ -1,23 +1,23 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
#
 | 
			
		||||
# Script to update language packs on assets and detect new translated languages.
 | 
			
		||||
# ./update_lang.sh [language]
 | 
			
		||||
# If language is set it will only update the selected language.
 | 
			
		||||
#
 | 
			
		||||
source "functions.sh"
 | 
			
		||||
forceLang=$1
 | 
			
		||||
source "lang_functions.sh"
 | 
			
		||||
 | 
			
		||||
print_title 'Getting languages'
 | 
			
		||||
git clone --depth 1 --no-single-branch https://git.in.moodle.com/moodle/moodle-langpacks.git $LANGPACKSFOLDER
 | 
			
		||||
pushd $LANGPACKSFOLDER
 | 
			
		||||
BRANCHES=($(git branch -r --format="%(refname:lstrip=3)" --sort="refname" | grep MOODLE_))
 | 
			
		||||
BRANCH=${BRANCHES[${#BRANCHES[@]}-1]}
 | 
			
		||||
git checkout $BRANCH
 | 
			
		||||
git pull
 | 
			
		||||
popd
 | 
			
		||||
forceLang=$1
 | 
			
		||||
 | 
			
		||||
print_title 'Getting local mobile langs'
 | 
			
		||||
git clone --depth 1 https://github.com/moodlehq/moodle-local_moodlemobileapp.git ../../moodle-local_moodlemobileapp
 | 
			
		||||
 | 
			
		||||
if [ -z $forceLang ]; then
 | 
			
		||||
    get_languages
 | 
			
		||||
    php -f moodle_to_json.php
 | 
			
		||||
else
 | 
			
		||||
    get_language "$forceLang"
 | 
			
		||||
    php -f moodle_to_json.php "$forceLang"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
print_ok 'All done!'
 | 
			
		||||
print_ok 'All done!'
 | 
			
		||||
 | 
			
		||||
@ -74,7 +74,7 @@
 | 
			
		||||
    </ion-searchbar>
 | 
			
		||||
 | 
			
		||||
    <core-empty-box *ngIf="filteredCourses.length == 0" image="assets/img/icons/courses.svg"
 | 
			
		||||
        [message]="'addon.block_myoverview.nocourses' | translate" class="core-empty-inline">
 | 
			
		||||
        [message]="'addon.block_myoverview.nocourses' | translate" inline="true">
 | 
			
		||||
    </core-empty-box>
 | 
			
		||||
 | 
			
		||||
    <!-- List of courses. -->
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@
 | 
			
		||||
                    </core-format-text>
 | 
			
		||||
                </p>
 | 
			
		||||
 | 
			
		||||
                <ion-button fill="clear" class="ion-hide-md-up" (click)="action($event, event.action.url)"
 | 
			
		||||
                <ion-button fill="clear" class="ion-hide-md-up ion-text-wrap" (click)="action($event, event.action.url)"
 | 
			
		||||
                    [title]="event.action.name" [disabled]="!event.action.actionable" *ngIf="event.action">
 | 
			
		||||
                    {{event.action.name}}
 | 
			
		||||
                    <ion-badge slot="end" class="ion-margin-start" *ngIf="event.action.showitemcount">{{event.action.itemcount}}
 | 
			
		||||
@ -28,19 +28,23 @@
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </ion-label>
 | 
			
		||||
 | 
			
		||||
            <ion-grid slot="end">
 | 
			
		||||
                <ion-row class="ion-justify-content-end">
 | 
			
		||||
            <div slot="end" class="events-info">
 | 
			
		||||
                <div>
 | 
			
		||||
                    <ion-badge color="light">{{event.timesort * 1000 | coreFormatDate:"strftimetime24" }}</ion-badge>
 | 
			
		||||
                </ion-row>
 | 
			
		||||
                <ion-row class="ion-justify-content-end">
 | 
			
		||||
                    <ion-button fill="clear" class="ion-hide-md-down" (click)="action($event, event.action.url)"
 | 
			
		||||
                        [title]="event.action.name" [disabled]="!event.action.actionable" *ngIf="event.action">
 | 
			
		||||
                        {{event.action.name}}
 | 
			
		||||
                        <ion-badge slot="end" class="ion-margin-start" *ngIf="event.action.showitemcount">{{event.action.itemcount}}
 | 
			
		||||
                        </ion-badge>
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                </ion-row>
 | 
			
		||||
            </ion-grid>
 | 
			
		||||
                </div>
 | 
			
		||||
                <ion-button
 | 
			
		||||
                    class="ion-hide-md-down"
 | 
			
		||||
                    fill="clear"
 | 
			
		||||
                    (click)="action($event, event.action.url)"
 | 
			
		||||
                    [title]="event.action.name"
 | 
			
		||||
                    [disabled]="!event.action.actionable" *ngIf="event.action"
 | 
			
		||||
                >
 | 
			
		||||
                    {{event.action.name}}
 | 
			
		||||
                    <ion-badge slot="end" class="ion-margin-start" *ngIf="event.action.showitemcount">
 | 
			
		||||
                        {{event.action.itemcount}}
 | 
			
		||||
                    </ion-badge>
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
</ion-item-group>
 | 
			
		||||
@ -54,4 +58,5 @@
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<core-empty-box *ngIf="empty" image="assets/img/icons/activities.svg" [message]="'addon.block_timeline.noevents' | translate"
 | 
			
		||||
[inline]="!showCourse"></core-empty-box>
 | 
			
		||||
    inline="true">
 | 
			
		||||
</core-empty-box>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								src/addons/block/timeline/components/events/events.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/addons/block/timeline/components/events/events.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
.events-info {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    text-align: end;
 | 
			
		||||
    padding: 10px 0;
 | 
			
		||||
}
 | 
			
		||||
@ -29,6 +29,7 @@ import { AddonCalendarEvent } from '@addons/calendar/services/calendar';
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'addon-block-timeline-events',
 | 
			
		||||
    templateUrl: 'addon-block-timeline-events.html',
 | 
			
		||||
    styleUrls: ['events.scss'],
 | 
			
		||||
})
 | 
			
		||||
export class AddonBlockTimelineEventsComponent implements OnChanges {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -103,7 +103,7 @@ export class AddonBlockTimelineProvider {
 | 
			
		||||
    async getActionEventsByCourses(
 | 
			
		||||
        courseIds: number[],
 | 
			
		||||
        siteId?: string,
 | 
			
		||||
    ): Promise<{[courseId: string]: { events: AddonCalendarEvent[]; canLoadMore: number } }> {
 | 
			
		||||
    ): Promise<{[courseId: string]: { events: AddonCalendarEvent[]; canLoadMore?: number } }> {
 | 
			
		||||
        const site = await CoreSites.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        const time = moment().subtract(14, 'days').unix(); // Check two weeks ago.
 | 
			
		||||
@ -123,17 +123,13 @@ export class AddonBlockTimelineProvider {
 | 
			
		||||
            preSets,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (events && events.groupedbycourse) {
 | 
			
		||||
            const courseEvents = {};
 | 
			
		||||
        const courseEvents: {[courseId: string]: { events: AddonCalendarEvent[]; canLoadMore?: number } } = {};
 | 
			
		||||
 | 
			
		||||
            events.groupedbycourse.forEach((course) => {
 | 
			
		||||
                courseEvents[course.courseid] = this.treatCourseEvents(course, time);
 | 
			
		||||
            });
 | 
			
		||||
        events.groupedbycourse.forEach((course) => {
 | 
			
		||||
            courseEvents[course.courseid] = this.treatCourseEvents(course, time);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
            return courseEvents;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new CoreError('No events returned on core_calendar_get_action_events_by_courses.');
 | 
			
		||||
        return courseEvents;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -83,7 +83,7 @@
 | 
			
		||||
                contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
 | 
			
		||||
            </core-format-text>
 | 
			
		||||
            <core-empty-box *ngIf="!pageContent" icon="fas-file-alt" [message]="'addon.mod_wiki.nocontent' | translate"
 | 
			
		||||
                [inline]="true">
 | 
			
		||||
                inline="true">
 | 
			
		||||
            </core-empty-box>
 | 
			
		||||
        </article>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,4 +5,6 @@
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: space-around;
 | 
			
		||||
    align-content: center;
 | 
			
		||||
    min-height: var(--a11y-min-target-size);
 | 
			
		||||
    min-width: var(--a11y-min-target-size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ export class CoreEmptyBoxComponent {
 | 
			
		||||
     * If this has to be shown inline instead of occupying whole page.
 | 
			
		||||
     * If image or icon is not supplied, it's true by default.
 | 
			
		||||
     */
 | 
			
		||||
    @Input() inline?: boolean;
 | 
			
		||||
    @Input() flipIconRtl?: boolean; // Whether to flip the icon in RTL. Defaults to false.
 | 
			
		||||
    @Input() inline = false;
 | 
			
		||||
    @Input() flipIconRtl = false; // Whether to flip the icon in RTL. Defaults to false.
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
:host {
 | 
			
		||||
    --tabs-background: var(--background);
 | 
			
		||||
    --tabs-background: var(--core-tabs-background);
 | 
			
		||||
    --tabs-color: var(--color);
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    display: block;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
:host {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    display: block;
 | 
			
		||||
    background: var(--background);
 | 
			
		||||
 | 
			
		||||
    ion-item-divider {
 | 
			
		||||
        min-height: 60px;
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
            <core-dynamic-component [component]="sectionSelectorComponent" [data]="data">
 | 
			
		||||
 | 
			
		||||
                <div *ngIf="displaySectionSelector && sections && hasSeveralSections"
 | 
			
		||||
                    class="ion-text-wrap clearfix ion-justify-content-between core-button-selector-row"
 | 
			
		||||
                    class="ion-text-wrap ion-justify-content-between ion-align-items-center core-button-selector-row"
 | 
			
		||||
                    [class.core-section-download]="downloadEnabled">
 | 
			
		||||
                    <core-combobox [modalOptions]="sectionSelectorModalOptions" interface="modal" listboxId="core-course-section-button"
 | 
			
		||||
                        icon="fas-folder" [label]="'core.course.section' | translate" (onChange)="sectionChanged($event)">
 | 
			
		||||
@ -122,8 +122,6 @@
 | 
			
		||||
                    <core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course?.id">
 | 
			
		||||
                    </core-format-text>
 | 
			
		||||
                </h2>
 | 
			
		||||
                <!-- Section download. -->
 | 
			
		||||
                <ng-container *ngTemplateOutlet="sectionDownloadTemplate; context: {section: section}"></ng-container>
 | 
			
		||||
                <p *ngIf="section.visible === 0 || section.availabilityinfo">
 | 
			
		||||
                    <ion-badge color="info" *ngIf="section.visible === 0 && section.uservisible !== false" class="ion-text-wrap">
 | 
			
		||||
                        {{ 'core.course.hiddenfromstudents' | translate }}
 | 
			
		||||
@ -137,6 +135,8 @@
 | 
			
		||||
                    </ion-badge>
 | 
			
		||||
                </p>
 | 
			
		||||
            </ion-label>
 | 
			
		||||
            <!-- Section download. -->
 | 
			
		||||
            <ng-container *ngTemplateOutlet="sectionDownloadTemplate; context: {section: section}"></ng-container>
 | 
			
		||||
        </ion-item-divider>
 | 
			
		||||
 | 
			
		||||
        <ion-item class="ion-text-wrap" *ngIf="section.summary">
 | 
			
		||||
@ -155,7 +155,7 @@
 | 
			
		||||
 | 
			
		||||
<!-- Template to render a section download button/progress. -->
 | 
			
		||||
<ng-template #sectionDownloadTemplate let-section="section">
 | 
			
		||||
    <div *ngIf="section && downloadEnabled" class="core-button-spinner ion-float-end">
 | 
			
		||||
    <div *ngIf="section && downloadEnabled" slot="end">
 | 
			
		||||
        <!-- Download progress. -->
 | 
			
		||||
        <ion-badge class="core-course-download-section-progress"
 | 
			
		||||
            *ngIf="section.isDownloading && section.total > 0 && section.count < section.total">
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,13 @@
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .core-button-selector-row {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        core-combobox {
 | 
			
		||||
            flex-grow: 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
// @todo
 | 
			
		||||
//     .item-divider  {
 | 
			
		||||
//         .label {
 | 
			
		||||
@ -70,8 +77,6 @@
 | 
			
		||||
//         @include padding(null, 0, null, null);
 | 
			
		||||
//     }
 | 
			
		||||
 | 
			
		||||
//     .core-button-selector-row {
 | 
			
		||||
//         @include safe-area-padding-start($content-padding !important, $content-padding);
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -724,7 +724,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
 | 
			
		||||
 | 
			
		||||
        await Promise.all(modules.map(async (module) => {
 | 
			
		||||
            const handler = this.getPrefetchHandlerFor(module);
 | 
			
		||||
            if (!handler || onlyToDisplay || handler.skipListStatus) {
 | 
			
		||||
            if (!handler || (onlyToDisplay && handler.skipListStatus)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,25 +1,26 @@
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('download')" *ngIf="downloadCourseEnabled">
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('download')" *ngIf="downloadCourseEnabled" detail="false">
 | 
			
		||||
    <ion-icon *ngIf="!prefetch.loading" [name]="prefetch.icon" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
    <ion-spinner *ngIf="prefetch.loading" slot="start"></ion-spinner>
 | 
			
		||||
    <ion-label><h2>{{ prefetch.statusTranslatable | translate }}</h2></ion-label>
 | 
			
		||||
</ion-item>
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('delete')" *ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'">
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('delete')" detail="false"
 | 
			
		||||
    *ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'">
 | 
			
		||||
    <ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
    <ion-label><h2>{{ 'addon.storagemanager.deletecourse' | translate }}</h2></ion-label>
 | 
			
		||||
</ion-item>
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden">
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden" detail="false">
 | 
			
		||||
    <ion-icon name="fas-eye" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
    <ion-label><h2>{{ 'core.courses.hidecourse' | translate }}</h2></ion-label>
 | 
			
		||||
</ion-item>
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('show')" *ngIf="course.hidden">
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('show')" *ngIf="course.hidden" detail="false">
 | 
			
		||||
    <ion-icon name="fas-eye-slash" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
    <ion-label><h2>{{ 'core.courses.show' | translate }}</h2></ion-label>
 | 
			
		||||
</ion-item>
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('favourite')" *ngIf="!course.isfavourite">
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('favourite')" *ngIf="!course.isfavourite" detail="false">
 | 
			
		||||
    <ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
    <ion-label><h2>{{ 'core.courses.addtofavourites' | translate }}</h2></ion-label>
 | 
			
		||||
</ion-item>
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('unfavourite')" *ngIf="course.isfavourite">
 | 
			
		||||
<ion-item button class="ion-text-wrap" (click)="action('unfavourite')" *ngIf="course.isfavourite" detail="false">
 | 
			
		||||
    <ion-icon name="far-star" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
    <ion-label><h2>{{ 'core.courses.removefromfavourites' | translate }}</h2></ion-label>
 | 
			
		||||
</ion-item>
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <ion-item button lines="none" (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname"
 | 
			
		||||
        class="core-course-header" [class.item-disabled]="course.visible == 0"
 | 
			
		||||
        [class.core-course-more-than-title]="course.progress! >= 0">
 | 
			
		||||
        [class.core-course-more-than-title]="course.progress! >= 0" detail="false">
 | 
			
		||||
        <ion-label
 | 
			
		||||
            class="ion-text-wrap core-course-title"
 | 
			
		||||
            [class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)"
 | 
			
		||||
 | 
			
		||||
@ -135,7 +135,6 @@
 | 
			
		||||
    --core-tab-border-color-active: #{$core-tab-border-color-active};
 | 
			
		||||
 | 
			
		||||
    core-tabs, core-tabs-outlet {
 | 
			
		||||
        --background: var(--core-tabs-background);
 | 
			
		||||
        ion-slide {
 | 
			
		||||
            --background: var(--core-tab-background);
 | 
			
		||||
            --color: var(--core-tab-color);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user