Skip to content

Commit

Permalink
Feature: add custom date format (#93)
Browse files Browse the repository at this point in the history
* chore(yarn.lock) : update yarn.lock

* chore(eslint): add EOL sequence to support windows

* feat: add custom date format

* chore; remove console log

* chore: fix typos

Co-authored-by: Michał Krassowski <[email protected]>

* chore(schema/settings.json): update title

Co-authored-by: Michał Krassowski <[email protected]>

* revert: yarn.lock (commit 84f2a89)

* chore(schema/settings.json): add unicode date field link

* fix: add date format argument

* feat: add date format validator

* feat: add regex to date format validator

* chore(schema/settings.json): add space

Co-authored-by: Michał Krassowski <[email protected]>

* refactor: apply suggestions from code review

Co-authored-by: Michał Krassowski <[email protected]>

* refactor: show error dialog on invalid format

* chore: add title to error message

* Move apputils pin to 4.0.0, update lock file

---------

Co-authored-by: Michał Krassowski <[email protected]>
  • Loading branch information
skngetich and krassowski authored Sep 13, 2023
1 parent 1ca883b commit 8da85c7
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 6 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,11 @@ module.exports = {
curly: ['error', 'all'],
eqeqeq: 'error',
'prefer-arrow-callback': 'error',
'prettier/prettier': [
'error',
{
endOfLine: 'auto',
},
],
},
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
},
"dependencies": {
"@jupyterlab/application": "^4.0.0",
"@jupyterlab/apputils": "^4.0.0",
"@jupyterlab/cells": "^4.0.0",
"@jupyterlab/docregistry": "^4.0.0",
"@jupyterlab/notebook": "^4.0.0",
Expand Down
7 changes: 7 additions & 0 deletions schema/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
"title": "History of Cell Execution Time",
"description": "Show the historical N previous execution times since the notebook was opened as a tooltip (0 to disabled)",
"default": 5
},
"dateFormat": {
"type": "string",
"title": "Date format",
"description": "Show the formatted date string in the given format. For example \"yyy-MM-dd HH:mm:ss\" results in \"2023-02-28 14:25:57 \", \"dd/MM/YYY HH:mm:ss (O)\" results in \"28/02/2023 14:25:57 (GMT +3)\". Find out more on unicode date field symbols on this link [https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table]",
"default": "yyy-MM-dd HH:mm:ss",
"pattern": "[yGuqQMLwdeEcabBhHkKmsSzOxX\\W].*"
}
}
}
32 changes: 28 additions & 4 deletions src/ExecuteTimeWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import {
import { ISettingRegistry } from '@jupyterlab/settingregistry';
import { IObservableList } from '@jupyterlab/observables';
import { Cell, CodeCell, ICellModel } from '@jupyterlab/cells';
import { getTimeDiff, getTimeString } from './formatters';
import { getTimeDiff, getTimeString, validateDateFormat } from './formatters';
import { differenceInMilliseconds } from 'date-fns';
import { showErrorMessage } from '@jupyterlab/apputils';

export const PLUGIN_NAME = 'jupyterlab-execute-time';
const EXECUTE_TIME_CLASS = 'execute-time';
Expand All @@ -29,6 +30,7 @@ export interface IExecuteTimeSettings {
textContrast: string;
showLiveExecutionTime: boolean;
historyCount: number;
dateFormat: string;
}

export default class ExecuteTimeWidget extends Widget {
Expand Down Expand Up @@ -271,7 +273,8 @@ export default class ExecuteTimeWidget extends Widget {
executionTimeNode.children[2].textContent = '';

msg = `Last executed at ${getTimeString(
endTime
endTime,
this._settings.dateFormat
)} in ${executionTime}`;
}
} else if (startTime) {
Expand Down Expand Up @@ -300,7 +303,10 @@ export default class ExecuteTimeWidget extends Widget {
}
}, 100);
}
msg = `Execution started at ${getTimeString(startTime)}`;
msg = `Execution started at ${getTimeString(
startTime,
this._settings.dateFormat
)}`;
} else if (queuedTime) {
const lastRunTime = executionTimeNode.getAttribute(
'data-prev-execution-time'
Expand All @@ -309,7 +315,10 @@ export default class ExecuteTimeWidget extends Widget {
executionTimeNode.children[2].textContent = `N/A (${lastRunTime})`;
}

msg = `Execution queued at ${getTimeString(queuedTime)}`;
msg = `Execution queued at ${getTimeString(
queuedTime,
this._settings.dateFormat
)}`;
}
if (executionTimeNode.textContent !== msg) {
executionTimeNode.children[0].textContent = msg;
Expand Down Expand Up @@ -347,6 +356,20 @@ export default class ExecuteTimeWidget extends Widget {
this._settings.historyCount = settings.get('historyCount')
.composite as number;

const dateFormat = settings.get('dateFormat').composite as string;
const formatValidationResult = validateDateFormat(dateFormat);
if (formatValidationResult.isValid) {
this._settings.dateFormat = dateFormat;
} else {
// fallback to default
this._settings.dateFormat = 'yyy-MM-dd HH:mm:ss';
// warn user once
showErrorMessage(
'Invalid date format in Execute Time extension setting',
formatValidationResult.message
);
}

const cells = this._panel.context.model.cells;
if (this._settings.enabled) {
cells.changed.connect(this.updateConnectedCell);
Expand Down Expand Up @@ -375,5 +398,6 @@ export default class ExecuteTimeWidget extends Widget {
textContrast: 'high',
showLiveExecutionTime: true,
historyCount: 5,
dateFormat: 'yyy-MM-dd HH:mm:ss',
};
}
36 changes: 34 additions & 2 deletions src/formatters.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
import { differenceInMilliseconds, format } from 'date-fns';

export const getTimeString = (date: Date): string => {
return format(date, 'yyy-MM-dd HH:mm:ss');
export interface IFormatValidationResult {
isValid: boolean;
message?: string;
}
/**
* Checks if a given date format string is valid.
*
* This function checks if the input date format string is valid.
*
* @param {string} dateFormat - The date format string to validate.
* @returns {IFormatValidationResult} Returns validation result.
*/
export const validateDateFormat = (
dateFormat: string
): IFormatValidationResult => {
const testDate = new Date();
try {
format(testDate, dateFormat);
return {
isValid: true,
};
} catch (error) {
return {
isValid: false,
message: (error as Error).message,
};
}
};

export const getTimeString = (
date: Date,
dateFormat = 'yyy-MM-dd HH:mm:ss'
): string => {
return format(date, dateFormat);
};

export const getTimeDiff = (end: Date, start: Date): string => {
Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4320,6 +4320,7 @@ __metadata:
resolution: "jupyterlab-execute-time@workspace:."
dependencies:
"@jupyterlab/application": ^4.0.0
"@jupyterlab/apputils": ^4.0.0
"@jupyterlab/builder": ^4.0.0
"@jupyterlab/cells": ^4.0.0
"@jupyterlab/docregistry": ^4.0.0
Expand Down

0 comments on commit 8da85c7

Please sign in to comment.