diff --git a/extension/src/experiments/columns/extract.ts b/extension/src/experiments/columns/extract.ts index 82cfc2bd6c..352bf2f776 100644 --- a/extension/src/experiments/columns/extract.ts +++ b/extension/src/experiments/columns/extract.ts @@ -1,6 +1,10 @@ import { Deps, ExperimentFields, ValueTreeRoot } from '../../cli/reader' import { shortenForLabel } from '../../util/string' -import { DepColumns, MetricOrParamColumns } from '../webview/contract' +import { + DepColumns, + Experiment, + MetricOrParamColumns +} from '../webview/contract' const extractMetricsOrParams = ( columns?: ValueTreeRoot @@ -21,7 +25,10 @@ const extractMetricsOrParams = ( return acc } -const extractDeps = (columns?: Deps): DepColumns | undefined => { +const extractDeps = ( + columns?: Deps, + branch?: Experiment +): DepColumns | undefined => { if (!columns) { return } @@ -29,20 +36,25 @@ const extractDeps = (columns?: Deps): DepColumns | undefined => { const acc: DepColumns = {} for (const [path, { hash }] of Object.entries(columns)) { - acc[path] = shortenForLabel(hash) + const value = shortenForLabel(hash) + acc[path] = { + changes: !!value && !!branch && branch?.deps?.[path].value !== value, + value + } } return acc } export const extractColumns = ( - experiment: ExperimentFields + experiment: ExperimentFields, + branch?: Experiment ): { deps: DepColumns | undefined metrics: MetricOrParamColumns | undefined params: MetricOrParamColumns | undefined } => ({ - deps: extractDeps(experiment.deps), + deps: extractDeps(experiment.deps, branch), metrics: extractMetricsOrParams(experiment.metrics), params: extractMetricsOrParams(experiment.params) }) diff --git a/extension/src/experiments/model/collect.ts b/extension/src/experiments/model/collect.ts index bded28af74..929009909d 100644 --- a/extension/src/experiments/model/collect.ts +++ b/extension/src/experiments/model/collect.ts @@ -112,9 +112,10 @@ const getCheckpointTipId = ( const transformColumns = ( experiment: Experiment, - experimentFields: ExperimentFields + experimentFields: ExperimentFields, + branch?: Experiment ) => { - const { metrics, params, deps } = extractColumns(experimentFields) + const { metrics, params, deps } = extractColumns(experimentFields, branch) if (metrics) { experiment.metrics = metrics @@ -133,7 +134,8 @@ const transformExperimentData = ( label: string | undefined, sha?: string, displayNameOrParent?: string, - logicalGroupName?: string + logicalGroupName?: string, + branch?: Experiment ): Experiment => { const experiment = { id, @@ -153,7 +155,7 @@ const transformExperimentData = ( experiment.sha = sha } - transformColumns(experiment, experimentFields) + transformColumns(experiment, experimentFields, branch) return experiment } @@ -162,7 +164,8 @@ const transformExperimentOrCheckpointData = ( sha: string, experimentData: ExperimentFieldsOrError, experimentsObject: ExperimentsObject, - branchSha: string + branchSha: string, + branch: Experiment ): { checkpointTipId?: string experiment: Experiment | undefined @@ -187,7 +190,8 @@ const transformExperimentOrCheckpointData = ( shortenForLabel(sha), sha, getDisplayNameOrParent(sha, branchSha, experimentsObject), - getLogicalGroupName(sha, branchSha, experimentsObject) + getLogicalGroupName(sha, branchSha, experimentsObject), + branch ) } } @@ -222,14 +226,17 @@ const collectFromExperimentsObject = ( acc: ExperimentsAccumulator, experimentsObject: ExperimentsObject, branchSha: string, - branchName: string + branch: Experiment ) => { + const branchName = branch.label + for (const [sha, experimentData] of Object.entries(experimentsObject)) { const { checkpointTipId, experiment } = transformExperimentOrCheckpointData( sha, experimentData, experimentsObject, - branchSha + branchSha, + branch ) if (!experiment) { continue @@ -257,7 +264,7 @@ const collectFromBranchesObject = ( const branch = transformExperimentData(name, experimentFields, name, sha) if (branch) { - collectFromExperimentsObject(acc, experimentsObject, sha, branch.label) + collectFromExperimentsObject(acc, experimentsObject, sha, branch) collectHasRunningExperiment(acc, branch) acc.branches.push(branch) diff --git a/extension/src/experiments/webview/contract.ts b/extension/src/experiments/webview/contract.ts index 39b6894a5f..8035b4591a 100644 --- a/extension/src/experiments/webview/contract.ts +++ b/extension/src/experiments/webview/contract.ts @@ -6,8 +6,13 @@ export interface MetricOrParamColumns { [filename: string]: ValueTree } +export interface ValueWithChanges { + value: string | number + changes: boolean +} + export interface DepColumns { - [path: string]: string + [path: string]: ValueWithChanges } export interface Experiment extends BaseExperimentFields { diff --git a/extension/src/test/fixtures/expShow/rows.ts b/extension/src/test/fixtures/expShow/rows.ts index 5285e66d45..f22e136e16 100644 --- a/extension/src/test/fixtures/expShow/rows.ts +++ b/extension/src/test/fixtures/expShow/rows.ts @@ -3,31 +3,36 @@ import { Row } from '../../../experiments/webview/contract' import { copyOriginalColors } from '../../../experiments/model/status/colors' import { shortenForLabel } from '../../../util/string' +const valueWithNoChanges = (str: string) => ({ + value: shortenForLabel(str), + changes: false +}) + const colorsList = copyOriginalColors() const data: Row[] = [ { deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges('46865edbf3d62fc5c039dd9d2b0567a4'), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( '935ee6803ac617d0ef138ac33a9e9a77' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -94,26 +99,26 @@ const data: Row[] = [ }, { deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges('46865edbf3d62fc5c039dd9d2b0567a4'), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -183,26 +188,26 @@ const data: Row[] = [ checkpoint_parent: 'd1343a87c6ee4a2e82d19525964d2fb2cb6756c9', checkpoint_tip: '4fb124aebddb2adf1545030907687fa9a4c80e70', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges('46865edbf3d62fc5c039dd9d2b0567a4'), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -274,26 +279,28 @@ const data: Row[] = [ checkpoint_parent: '1ee5f2ecb0fa4d83cbf614386536344cf894dd53', checkpoint_tip: '4fb124aebddb2adf1545030907687fa9a4c80e70', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges( + '46865edbf3d62fc5c039dd9d2b0567a4' + ), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -364,26 +371,28 @@ const data: Row[] = [ checkpoint_tip: '4fb124aebddb2adf1545030907687fa9a4c80e70', checkpoint_parent: '53c3851f46955fa3e2b8f6e1c52999acc8c9ea77', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges( + '46865edbf3d62fc5c039dd9d2b0567a4' + ), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -457,26 +466,26 @@ const data: Row[] = [ checkpoint_parent: '217312476f8854dda1865450b737eb6bc7a3ba1b', checkpoint_tip: '42b8736b08170529903cd203a1f40382a4b4a8cd', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges('46865edbf3d62fc5c039dd9d2b0567a4'), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -548,26 +557,28 @@ const data: Row[] = [ checkpoint_parent: '9523bde67538cf31230efaff2dbc47d38a944ab5', checkpoint_tip: '42b8736b08170529903cd203a1f40382a4b4a8cd', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges( + '46865edbf3d62fc5c039dd9d2b0567a4' + ), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -638,26 +649,28 @@ const data: Row[] = [ checkpoint_tip: '42b8736b08170529903cd203a1f40382a4b4a8cd', checkpoint_parent: '53c3851f46955fa3e2b8f6e1c52999acc8c9ea77', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges( + '46865edbf3d62fc5c039dd9d2b0567a4' + ), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -731,26 +744,26 @@ const data: Row[] = [ checkpoint_parent: '22e40e1fa3c916ac567f69b85969e3066a91dda4', checkpoint_tip: '1ba7bcd6ce6154e72e18b155475663ecbbd1f49d', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges('46865edbf3d62fc5c039dd9d2b0567a4'), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -822,26 +835,28 @@ const data: Row[] = [ checkpoint_tip: '1ba7bcd6ce6154e72e18b155475663ecbbd1f49d', checkpoint_parent: '91116c1eae4b79cb1f5ab0312dfd9b3e43608e15', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges( + '46865edbf3d62fc5c039dd9d2b0567a4' + ), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -912,26 +927,28 @@ const data: Row[] = [ checkpoint_tip: '1ba7bcd6ce6154e72e18b155475663ecbbd1f49d', checkpoint_parent: 'e821416bfafb4bc28b3e0a8ddb322505b0ad2361', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges( + '46865edbf3d62fc5c039dd9d2b0567a4' + ), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -1002,26 +1019,28 @@ const data: Row[] = [ checkpoint_parent: 'c658f8b14ac819ac2a5ea0449da6c15dbe8eb880', checkpoint_tip: '1ba7bcd6ce6154e72e18b155475663ecbbd1f49d', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges( + '46865edbf3d62fc5c039dd9d2b0567a4' + ), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -1092,26 +1111,28 @@ const data: Row[] = [ checkpoint_parent: '23250b33e3d6dd0e136262d1d26a2face031cb03', checkpoint_tip: '1ba7bcd6ce6154e72e18b155475663ecbbd1f49d', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges( + '46865edbf3d62fc5c039dd9d2b0567a4' + ), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -1182,26 +1203,28 @@ const data: Row[] = [ checkpoint_parent: '53c3851f46955fa3e2b8f6e1c52999acc8c9ea77', checkpoint_tip: '1ba7bcd6ce6154e72e18b155475663ecbbd1f49d', deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges( + '46865edbf3d62fc5c039dd9d2b0567a4' + ), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, @@ -1273,26 +1296,26 @@ const data: Row[] = [ }, { deps: { - [join('data', 'data.xml')]: shortenForLabel( + [join('data', 'data.xml')]: valueWithNoChanges( '22a1a2931c8370d3aeedd7183606fd7f' ), - [join('data', 'features')]: shortenForLabel( + [join('data', 'features')]: valueWithNoChanges( 'f35d4cc2c552ac959ae602162b8543f3.dir' ), - [join('data', 'prepared')]: shortenForLabel( + [join('data', 'prepared')]: valueWithNoChanges( '153aad06d376b6595932470e459ef42a.dir' ), - 'model.pkl': shortenForLabel('46865edbf3d62fc5c039dd9d2b0567a4'), - [join('src', 'evaluate.py')]: shortenForLabel( + 'model.pkl': valueWithNoChanges('46865edbf3d62fc5c039dd9d2b0567a4'), + [join('src', 'evaluate.py')]: valueWithNoChanges( '44e714021a65edf881b1716e791d7f59' ), - [join('src', 'featurization.py')]: shortenForLabel( + [join('src', 'featurization.py')]: valueWithNoChanges( 'e0265fc22f056a4b86d85c3056bc2894' ), - [join('src', 'prepare.py')]: shortenForLabel( + [join('src', 'prepare.py')]: valueWithNoChanges( 'f09ea0c15980b43010257ccb9f0055e2' ), - [join('src', 'train.py')]: shortenForLabel( + [join('src', 'train.py')]: valueWithNoChanges( 'c3961d777cfbd7727f9fde4851896006' ) }, diff --git a/webview/src/experiments/components/table/Cell.tsx b/webview/src/experiments/components/table/Cell.tsx index 787443a40e..ef5cbf9623 100644 --- a/webview/src/experiments/components/table/Cell.tsx +++ b/webview/src/experiments/components/table/Cell.tsx @@ -8,6 +8,7 @@ import ClockIcon from '../../../shared/components/icons/Clock' import { clickAndEnterProps } from '../../../util/props' import { StarFull, StarEmpty } from '../../../shared/components/icons' import { pluralize } from '../../../util/strings' +import { cellHasChanges } from '../../util/buildDynamicColumns' const RowExpansionButton: React.FC = ({ row }) => row.canExpand ? ( @@ -189,15 +190,19 @@ export const CellWrapper: React.FC< cellId: string children?: React.ReactNode } -> = ({ cell, cellId, changes }) => ( -
- {cell.render('Cell')} -
-) +> = ({ cell, cellId, changes }) => { + return ( +
+ {cell.render('Cell')} +
+ ) +} diff --git a/webview/src/experiments/components/table/styles.module.scss b/webview/src/experiments/components/table/styles.module.scss index 4420fef570..e3ba798e2e 100644 --- a/webview/src/experiments/components/table/styles.module.scss +++ b/webview/src/experiments/components/table/styles.module.scss @@ -407,7 +407,8 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; } } - .workspaceChange { + .workspaceChange, + .depChange { color: $changed-color; } diff --git a/webview/src/experiments/util/buildDynamicColumns.tsx b/webview/src/experiments/util/buildDynamicColumns.tsx index 4207665c9e..270a2ff03f 100644 --- a/webview/src/experiments/util/buildDynamicColumns.tsx +++ b/webview/src/experiments/util/buildDynamicColumns.tsx @@ -7,7 +7,11 @@ import { ColumnInstance, Cell } from 'react-table' -import { Experiment, Column } from 'dvc/src/experiments/webview/contract' +import { + Experiment, + Column, + ValueWithChanges +} from 'dvc/src/experiments/webview/contract' import { formatFloat } from './numberFormatting' import Tooltip, { CELL_TOOLTIP_DELAY @@ -15,6 +19,18 @@ import Tooltip, { import styles from '../components/table/styles.module.scss' import { CopyButton } from '../../shared/components/copyButton/CopyButton' import { OverflowHoverTooltip } from '../components/overflowHoverTooltip/OverflowHoverTooltip' + +export type CellValue = undefined | string | number | ValueWithChanges + +export const isValueWithChanges = (raw: CellValue): raw is ValueWithChanges => + typeof (raw as ValueWithChanges)?.changes === 'boolean' + +export const cellValue = (raw: CellValue) => + isValueWithChanges(raw) ? raw.value : raw + +export const cellHasChanges = (cellValue: CellValue) => + isValueWithChanges(cellValue) ? cellValue.changes : false + const UndefinedCell = (
. . . @@ -38,17 +54,18 @@ const CellTooltip: React.FC<{ ) } -const Cell: React.FC> = cell => { +const Cell: React.FC> = cell => { const { value } = cell if (value === undefined) { return UndefinedCell } - const stringValue = String(value) + const rawValue = cellValue(value) + const stringValue = String(rawValue) const displayValue = - typeof value === 'number' && !Number.isInteger(value) - ? formatFloat(value as number) + typeof rawValue === 'number' && !Number.isInteger(rawValue) + ? formatFloat(rawValue as number) : stringValue return (