Moment.js docker/metadata-action OCI Date Format REPL
A tool for fiddling with Docker OCI metadata formats (handlebars -> moment.js time format string). A simple REPL is implemented which accepts a bare handlebars string in the format: {{ date 'format-string' }} Where 'format-string' is a moment.js date format specifier (e.g. 'YYYY-MM-DD HH:mm:ss.SSSS A Z' )
by TrinitronX
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Docker OCI Timestamp Annotation Example</title>
<!--
/*
"xterm-old": "https://unpkg.com/@liudonghua123/xterm@5.5.0/lib/xterm-esm.js",
"@yarnpkg/broken-lockfile": "https://esm.sh/@yarnpkg/lockfile@1.1.0/?dev",
*/
-->
<script type="importmap">
{
"imports": {
"xterm": "https://esm.sh/@xterm/xterm@5.5.0",
"moment": "https://esm.sh/moment@2.30.1/?dev",
"handlebars": "https://esm.sh/handlebars@4.7.8/?dev"
}
}
</script>
<link rel="stylesheet" href="https://unpkg.com/@xterm/xterm@5.5.0/css/xterm.css" />
<!-- OLD xterm -->
<!-- <link rel="stylesheet" href="https://unpkg.com/@liudonghua123/xterm@5.5.0/css/xterm.css" /> -->
<style>
</style>
</head>
<body>
<div class="topcontainer">
<div class="container midcontainer">
<div id="time1" class="neumorphic time">
<p>
Nonstandard Time Format
</p>
<p id="datetime1" class="datetime">
</p>
</div>
<div id="pause-container" class="container">
<div id="pause-button" class="neumorphic button">
<p>
Pause
</p>
</div>
</div>
<div id="time2" class="neumorphic time">
<p>
RFC 3339 + ISO 8601ISO 8601-1:2019
</p>
<p id="datetime2" class="datetime">
</p>
</div>
</div>
<div id="termcontainer" class="midcontainer neumorphic-container">
<div id="xterm1" class="myterminal">
<!-- <p>
Hello term
</p> -->
</div>
</div>
</div>
</body>
</html>
CSS
body {
background-color: #e6e7ee;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
font-family: Arial, sans-serif;
}
.topcontainer {
display: flex;
/* flex-wrap: wrap; */
flex-direction: column;
align-content: space-between;
height: 100vh;
/* height: 100%; */
width: 95%;
/* align-content: center; */
/* justify-content: space-between; */
/* DEBUG */
/* border: 1rem solid magenta; */
}
.midcontainer {
display: flex;
flex-direction: row;
height: 50%;
/* DEBUG */
/* border: 1rem solid red; */
/* justify-content: flex-end; */
width: 100%;
/* gap: 20px 30px; */
}
.container {
display: flex;
gap: 20px;
justify-content: center;
}
.neumorphic {
background: #e6e7ee;
border-radius: 10px;
box-shadow: 9px 9px 16px #b8b9be, -9px -9px 16px #fff;
padding: 20px;
text-align: center;
width: 200px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.datetime {
align-self: flex-end;
align-content: flex-end;
}
.time {
flex-wrap: wrap;
align-content: center;
justify-content: center;
}
div#time2 {
width: 300px;
}
/* Align button at bottom of midcontainer */
div#pause-container {
align-self: flex-end;
}
.button {
color: #00084d;
background: #e5f2fc;
border-radius: 10px;
box-shadow: 9px 9px 16px #b8b9be, -9px -9px 16px #fff;
padding: 20px;
text-align: center;
width: 200px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
transition-property: all;
transition-duration: 0.25s;
transition-timing-function: ease-out;
transition-delay: 0s;
}
.button:hover {
color: #1d63ed;
}
.button:focus {
outline: 1px solid #1d63ed;
}
.button:active {
color: #00084d;
background-color: #cfe7fa;
box-shadow: -9px -9px 16px #b8b9be, 9px 9px 16px #fff;
}
.pauseActive {
color: #104dc5;
text-shadow: -1px -1px 1px #fff, 1px -1px 3px #092e76, -1px 1px 1px #fff, 1px 1px 1px...
JavaScript
// See https://www.npmjs.com/package/parse-yarn-lock documentation.
/* import parse as parseYarnLock from 'https://cdn.jsdelivr.net/npm/yarn-lockfile@latest/+esm'; */
import {
Terminal
} from 'xterm';
import moment from 'moment';
import * as handlebarsESMshImport from 'handlebars';
const handlebars = handlebarsESMshImport.default;
function showTimes() {
let now = moment().format('YYYYMMDD-hhmmss');
// console.log(now);
document.getElementById('datetime1').innerText = now;
let currentDate = new Date();
let format = "YYYY-MM-DDTHH:mm:ss.SSSSZ";
// Based on Intersection of RFC 3339 and ISO 8601 formats
// https://ijmacd.github.io/rfc3339-iso8601/
let dockerOCITimestamp = moment(currentDate).utc().format(format);
// console.log(dockerOCITimestamp);
document.getElementById('datetime2').innerText = dockerOCITimestamp;
}
var intervalId = window.setInterval(showTimes, 1000);
function pauseInterval() {
if (intervalId != null) {
clearInterval(intervalId);
intervalId = null;
document.getElementById('pause-button').classList.add('pauseActive');
} else {
intervalId = window.setInterval(showTimes, 1000);
document.getElementById('pause-button').classList.remove('pauseActive');
}
}
document.getElementById('pause-button').addEventListener('click', pauseInterval);
const PS1 = "docker@date-fiddle.js \x1B[1;3;31mxterm.js\x1B[0m $ ";
const terminal = new Terminal({ cursorBlink: 'block' });
/* const ws = new WebSocket("ws://localhost:3000", "echo-protocol"); */
function handlebarsDateFormat(dockerMetadataActionTagInputFormat) {
// Compile the Handlebars template from input
let template = handlebars.compile(dockerMetadataActionTagInputFormat);
let currentDate = new Date();
const context = {
date: function (format) {
return moment(currentDate).utc().format(format);
}
};
// Execute the compiled template with the context
const result = template(context);
console.log(result);
terminal.write(result);
...