diff --git a/components/crud-web-apps/jupyter/backend/apps/common/utils.py b/components/crud-web-apps/jupyter/backend/apps/common/utils.py index d8eb7f5c..5d30459a 100644 --- a/components/crud-web-apps/jupyter/backend/apps/common/utils.py +++ b/components/crud-web-apps/jupyter/backend/apps/common/utils.py @@ -16,6 +16,7 @@ FILE_ABS_PATH = os.path.abspath(os.path.dirname(__file__)) NOTEBOOK_TEMPLATE_YAML = os.path.join( FILE_ABS_PATH, "yaml/notebook_template.yaml" ) +LAST_ACTIVITY_ANNOTATION = "notebooks.kubeflow.org/last-activity" # The production configuration is mounted on the app's pod via a configmap DEV_CONFIG = os.path.join(FILE_ABS_PATH, "yaml/spawner_ui_config.yaml") @@ -113,6 +114,11 @@ def get_storage_class(vol): # Functions for transforming the data from k8s api +def get_notebook_last_activity(notebook): + annotations = notebook["metadata"].get("annotations", {}) + return annotations.get(LAST_ACTIVITY_ANNOTATION, "") + + def notebook_dict_from_k8s_obj(notebook): cntr = notebook["spec"]["template"]["spec"]["containers"][0] server_type = None @@ -125,6 +131,7 @@ def notebook_dict_from_k8s_obj(notebook): "namespace": notebook["metadata"]["namespace"], "serverType": server_type, "age": helpers.get_uptime(notebook["metadata"]["creationTimestamp"]), + "last_activity": get_notebook_last_activity(notebook), "image": cntr["image"], "shortImage": cntr["image"].split("/")[-1], "cpu": cntr["resources"]["requests"]["cpu"], diff --git a/components/crud-web-apps/jupyter/frontend/src/app/pages/index/index-default/config.ts b/components/crud-web-apps/jupyter/frontend/src/app/pages/index/index-default/config.ts index 20ca07a7..4e6cad56 100644 --- a/components/crud-web-apps/jupyter/frontend/src/app/pages/index/index-default/config.ts +++ b/components/crud-web-apps/jupyter/frontend/src/app/pages/index/index-default/config.ts @@ -9,6 +9,7 @@ import { ComponentValue, TableConfig, TABLE_THEME, + DateTimeValue, } from 'kubeflow'; import { ServerTypeComponent } from './server-type/server-type.component'; @@ -73,6 +74,11 @@ export const defaultConfig: TableConfig = { textAlignment: 'right', value: new PropertyValue({ field: 'age', truncate: true }), }, + { + matHeaderCellDef: $localize`Last activity`, + matColumnDef: 'last_activity', + value: new DateTimeValue({ field: 'last_activity' }), + }, { matHeaderCellDef: $localize`Image`, matColumnDef: 'image',