diff --git a/label_studio/users/product_tours/serializers.py b/label_studio/users/product_tours/serializers.py index 0681c49fa43e..d600d5212d19 100644 --- a/label_studio/users/product_tours/serializers.py +++ b/label_studio/users/product_tours/serializers.py @@ -1,16 +1,23 @@ +import logging import pathlib from functools import cached_property import yaml +from core.utils.db import fast_first from rest_framework import serializers -from .models import ProductTourInteractionData, UserProductTour +from .models import ProductTourInteractionData, ProductTourState, UserProductTour + +logger = logging.getLogger(__name__) PRODUCT_TOURS_CONFIGS_DIR = pathlib.Path(__file__).parent / 'configs' class UserProductTourSerializer(serializers.ModelSerializer): + # steps is a list of steps in the tour loaded from the yaml file steps = serializers.SerializerMethodField(read_only=True) + # awaiting is a boolean that indicates if the tour is awaiting other tours in the list of "dependencies" + awaiting = serializers.SerializerMethodField(read_only=True) class Meta: model = UserProductTour @@ -29,14 +36,25 @@ def validate_name(self, value): return value + @cached_property def load_tour_config(self): # TODO: get product tour from yaml file. Later we move it to remote storage, e.g. S3 filepath = PRODUCT_TOURS_CONFIGS_DIR / f'{self.context["name"]}.yml' with open(filepath, 'r') as f: return yaml.safe_load(f) + def get_awaiting(self, obj): + config = self.load_tour_config + dependencies = config.get('dependencies', []) + for dependency in dependencies: + tour = fast_first(UserProductTour.objects.filter(user=self.context['request'].user, name=dependency)) + if not tour or tour.state != ProductTourState.COMPLETED: + logger.info(f'Tour {dependency} is not completed: skipping tour {self.context["name"]}') + return True + return False + def get_steps(self, obj): - config = self.load_tour_config() + config = self.load_tour_config return config.get('steps', []) def validate_interaction_data(self, value): diff --git a/web/libs/core/src/lib/Tour/TourProvider.tsx b/web/libs/core/src/lib/Tour/TourProvider.tsx index ae3167c97d4d..bfbb96a34d38 100644 --- a/web/libs/core/src/lib/Tour/TourProvider.tsx +++ b/web/libs/core/src/lib/Tour/TourProvider.tsx @@ -131,6 +131,11 @@ export const TourProvider: React.FC<{ return; } + if (response.awaiting) { + console.info(`Tour "${name}" is awaiting other tours`); + return; + } + if (!response.steps?.length) { console.info(`No steps found for tour "${name}"`); return;