Skip to content

Commit

Permalink
Merge pull request #4 from bitrise-io/changelog
Browse files Browse the repository at this point in the history
First version of the changlog scripts
  • Loading branch information
aorcsik authored Feb 2, 2024
2 parents a11520f + a5aa7a5 commit a717cc3
Show file tree
Hide file tree
Showing 10 changed files with 269 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
"HTMLElement",
"HTMLHeadingElement",
"HTMLImageElement",
"HTMLLIElement",
"HTMLMetaElement",
"HTMLParagraphElement",
"HTMLSpanElement",
"HTMLUListElement",
"Promise",
"URL"
]
Expand Down
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ addEventListener('common', event => {
});

includeWorkerScript("integrations", "./src/js/integrations/worker.js");
includeWorkerScript("changelog", "./src/js/changelog/worker.js");

/**
* @param {URL} urlObject
Expand All @@ -50,6 +51,9 @@ function getFetchEventHandler(urlObject) {
if (urlObject.pathname.match(/^\/integrations/)) {
return fetchEventHandlers['integrations'];
}
if (urlObject.pathname.match(/^\/changelog/)) {
return fetchEventHandlers['changelog'];
}
return fetchEventHandlers['common'];
}

Expand Down
17 changes: 17 additions & 0 deletions src/css/changelog.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.changelog-title img.emoji,
#changelog-topic-title img.emoji,
.changelog-topic-content img.emoji {
vertical-align: sub;
width: 1.25em;
height: 1.25em;
display: inline;
}

.changelog-topic-content .meta {
display: none;
}

.changelog-topic-content h2 {
font-size: 2rem;
margin-top: 1rem;
}
28 changes: 28 additions & 0 deletions src/js/changelog-topic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import ChangelogService from "./changelog/ChangelogService";

const style = document.createElement("style");
document.getElementsByTagName("head")[0].appendChild(style);
style.appendChild(document.createTextNode(require("../css/changelog.css")));

/**
* @param {URL} url
* @returns {?string}
*/
function detectTopicFromUrl(url) {
let path = url.pathname;
const match = path.match(/changelog\/(.+)$/);
if (match) {
return match[1];
}
return null;
}

const url = new URL(document.location.href);
const topicSlugId = detectTopicFromUrl(url);

ChangelogService.loadTopic(topicSlugId).then(topic => {

document.getElementById("changelog-topic-title").innerHTML = topic.fancyTitle;
document.getElementById("changelog-topic-meta").innerHTML = topic.createdAt.toLocaleDateString();
document.getElementById("changelog-topic-content").innerHTML = topic.posts[0].cooked;
});
36 changes: 36 additions & 0 deletions src/js/changelog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import ChangelogList from "./changelog/ChangelogList";
import ChangelogService from "./changelog/ChangelogService";

const style = document.createElement("style");
document.getElementsByTagName("head")[0].appendChild(style);
style.appendChild(document.createTextNode(require("../css/changelog.css")));

/** @type {string} */
const apiBase = document.location.hostname.match(/(localhost|127\.0\.0\.1)/) ? "" : "https://bitrise.io";
const changelogService = new ChangelogService(apiBase);

const changelogList = new ChangelogList(document.getElementById("changelog-list"));
/** @type {HTMLAnchorElement} */
const changelogLoadMoreButton = document.getElementById("changelog-load-more-button");

/** */
function loadMore() {
changelogLoadMoreButton.disabled = true;
changelogLoadMoreButton.innerHTML = "Loading...";
changelogService.loadMore().then(topics => {
changelogList.render(topics);
changelogLoadMoreButton.disabled = false;
changelogLoadMoreButton.innerHTML = "Load more...";

if (!changelogService.isMore) {
changelogLoadMoreButton.remove();
}
});
}

changelogLoadMoreButton.addEventListener('click', event => {
event.preventDefault();
loadMore();
});

loadMore();
51 changes: 51 additions & 0 deletions src/js/changelog/ChangelogList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import ChangelogTopic from "./ChangelogTopic";

class ChangelogList
{
constructor(list) {
/** @type {HTMLUListElement} */
this.list = list;

/** @type {HTMLLIElement[]} */
this.listItems = [];

/** @type {HTMLLIElement} */
this.unreadListItemTemplate = this.list.querySelector("#changelog-unread-template");
this.unreadListItemTemplate.id = "";
this.unreadListItemTemplate.remove();

/** @type {HTMLLIElement} */
this.readListItemTemplate = this.list.querySelector("#changelog-read-template");
this.readListItemTemplate.id = "";
this.readListItemTemplate.remove();
}


/**
* @param {ChangelogTopic} topic
* @param {boolean} isUnread
* @returns {HTMLLIElement}
*/
renderListItem(topic, isUnread = false) {
const listItem = (isUnread ? this.unreadListItemTemplate : this.readListItemTemplate).cloneNode(true);
listItem.querySelector(".changelog-timestamp").innerHTML = topic.createdAt.toLocaleDateString();
listItem.querySelector(".changelog-title").innerHTML = topic.fancyTitle;
listItem.querySelector("a").href = topic.webflowUrl;
return listItem;
}

/**
* @param {ChangelogTopic[]} topics
*/
render(topics) {
for (let topic of topics) {
if (!this.listItems[topic.id]) {
const listItem = this.renderListItem(topic);
this.listItems[topic.id] = listItem;
this.list.append(listItem);
}
}
}
}

export default ChangelogList;
64 changes: 64 additions & 0 deletions src/js/changelog/ChangelogService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import ChangelogTopic from "./ChangelogTopic";

class ChangelogService
{
/**
* @param {string} apiBase
*/
constructor(apiBase) {
/** @type {string} */
this.apiBase = apiBase;

/** @type {string} */
this.changelogUrl = "/changelog.json";

/** @type {ChangelogTopic[]} */
this.topics = [];

/** @type {number} */
this.nextPage = 0;
/** @type {number} */
this.currentPage = -1;
}

/** @returns {Promise<ChangelogTopic[]>} */
async loadMore() {
if (this.isMore) {
const url = this.apiBase + this.changelogUrl + "?page=" + this.nextPage;
const response = await fetch(url);
const json = await response.json();

this.currentPage = this.nextPage;

if (json.topic_list.more_topics_url) {
const moreTopicsUrlMatch = json.topic_list.more_topics_url.match(/page=(\d+)/);
this.nextPage = parseInt(moreTopicsUrlMatch[1]);
}

json.topic_list.topics.forEach(data => {
this.topics.push(new ChangelogTopic(data));
});
}

return this.topics;
}

/** @returns {boolean} */
get isMore() {
return this.nextPage > this.currentPage;
}

/**
* @param {string} topicSlugId
* @returns {Promise<ChangelogTopic>}
*/
async loadTopic(topicSlugId) {
const url = this.apiBase + `/changelog/${topicSlugId}.json`;
const response = await fetch(url);
const data = await response.json();
console.log(data);
return new ChangelogTopic(data);
}
}

export default ChangelogService;
45 changes: 45 additions & 0 deletions src/js/changelog/ChangelogTopic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class ChangelogTopic
{
constructor(data) {
this.data = data;
}

/** @returns {number} */
get id() {
return this.data.id;
}

/** @returns {string} */
get fancyTitle() {
return this.data.fancy_title.replace(/:([^\s]+):/ig, '<img src="https://emoji.discourse-cdn.com/twitter/$1.png?v=12" title="$1" alt="$1" class="emoji">');
}

/** @returns {Date} */
get createdAt() {
return new Date(this.data.created_at);
}

/** @returns {string} */
get slug() {
return this.data.slug;
}

/** @returns {string} */
get webflowUrl() {
return `/changelog/${this.slug}/${this.id}`;
}

/** @returns {boolean} */
get isPinned() {
return !!this.data.pinned;
}

get posts() {
if (this.data.post_stream) {
return this.data.post_stream.posts;
}
return [];
}
}

export default ChangelogTopic;
17 changes: 17 additions & 0 deletions src/js/changelog/worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
addEventListener('fetch', event => {
let urlObject = new URL(event.request.url);

urlObject.hostname = 'webflow.bitrise.io';

if (urlObject.pathname.match(/^\/changelog\/(.+\.json)$/)) {
urlObject.hostname = 'discuss.bitrise.io';
urlObject.pathname = urlObject.pathname.replace(/^\/changelog\/(.+\.json)$/, '/t/$1');
} else if (urlObject.pathname.match(/^\/changelog\.json$/)) {
urlObject.hostname = 'discuss.bitrise.io';
urlObject.pathname = '/c/product-updates/42.json';
} else if (urlObject.pathname.match(/^\/changelog\/.+/)) {
urlObject.pathname = '/changelog/topic';
}

event.respondWith(fetch(urlObject));
})
8 changes: 5 additions & 3 deletions webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ module.exports = {
]
},
entry: {
integrations: "js/integrations.js",
steps: "js/steps.js",
careers: "js/careers.js",
integrations: "js/integrations.js",
steps: "js/steps.js",
careers: "js/careers.js",
changelog: "js/changelog.js",
"changelog-topic": "js/changelog-topic.js",
},
output: {
path: path.resolve(__dirname, "dist"),
Expand Down

0 comments on commit a717cc3

Please sign in to comment.