Skip to content

Commit

Permalink
Add build number support and enhance SKU feature display
Browse files Browse the repository at this point in the history
  • Loading branch information
rajbos committed Dec 13, 2024
1 parent abaaae8 commit ea6bfd0
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 66 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REACT_APP_BUILDNUMBER=localhost
4 changes: 2 additions & 2 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ jobs:
- name: Build project
env:
NODE_ENV: ${{ vars.NODE_ENV }} # use the vars to indicate the env that is uesd in the react-config.js to set the base url / folder
REACT_APP_BUILDNUMBER: ${{ github.run_number }}
run: |
export NODE_ENV=$NODE_ENV
export REPO_NAME="$(echo $GITHUB_REPOSITORY | cut -d'/' -f2)"
export BUILDNUMBER="$(echo $GITHUB_RUN_NUMBER)"
echo "Building in repo [$REPO_NAME] with build number [$BUILDNUMBER] for [$NODE_ENV] environment."
echo "Building in repo [$REPO_NAME] with build number [$REACT_APP_BUILDNUMBER] for [$NODE_ENV] environment."
npm run build
# copy the index file from the dist folder into the 404 file
Expand Down
68 changes: 68 additions & 0 deletions .github/workflows/duplicate-ids-detection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const fs = require('fs');
const path = require('path');

// Load the data.json file
const dataFilePath = path.join(__dirname, '..', '..', 'public', 'data.json');
const data = JSON.parse(fs.readFileSync(dataFilePath, 'utf8'));

// Check for duplicate IDs
const idMap = new Map();
const duplicates = [];

// keep track of the highest ID
let highestId = -1;

data.features.videos.forEach((videos, index) => {
console.log(`Checking for duplicates in SKU: ${videos.sku}`);
const sku = videos.sku;
videos.items.forEach((video, index) => {
if (idMap.has(video.id)) {
duplicates.push({
id: video.id,
title: video.title,
sku: sku,
location: `Index: ${index}`
});
// also mark the original as duplicate
let original = idMap.get(video.id);
original.id = video.id;
// get the sku from the originals parent
original.sku = videos.sku;
duplicates.push(original);
} else {
idMap.set(video.id, {
title: video.title,
location: `Index: ${index}`
});
}

// Update the highest ID if the current video's ID is greater
if (video.id > highestId) {
highestId = video.id;
}
});
});

// Write duplicates to GITHUB_STEP_SUMMARY
if (duplicates.length > 0) {
let summaryFilePath;
if (process.env.GITHUB_STEP_SUMMARY) {
summaryFilePath = process.env.GITHUB_STEP_SUMMARY;
}
else {
summaryFilePath = path.join(__dirname, '..', '..', 'duplicate-ids-summary.txt');
}
console.log(`Writing duplicate IDs to [${summaryFilePath}]`);
let summaryContent = duplicates.map(dup => `ID: ${dup.id}, Title: ${dup.title}, Location: ${dup.location}, SKU: ${dup.sku}`).join('\n');
// also report the highest ID
summaryContent += `\nHighest ID: [${highestId}]`;

fs.writeFileSync(summaryFilePath, summaryContent, 'utf8');
console.log('Duplicate IDs found and reported.');
console.log(`Highest ID: [${highestId}]`);
} else {
console.log('No duplicate IDs found.');

// Log the highest ID
console.log(`Highest ID: [${highestId}]`);
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules/
dist/
duplicate-ids-summary.txt
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"dev"
],
"port": 3000, // Default port for Vite development server
"console": "integratedTerminal"
"console": "integratedTerminal",
}
]
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"scripts": {
"build_number": "export REACT_APP_BUILDNUMBER=$(git rev-parse --short HEAD)",
"dev": "vite",
"build": "vite build",
"build": "npm run build_number && vite build",
"preview": "vite build && vite preview"
},
"dependencies": {
Expand Down
41 changes: 40 additions & 1 deletion public/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"features": {
"videos": [
{
"sku": "GitHub Copilot Business",
"sku": "GitHub Copilot Individual",
"items": [
{
"id": 0,
Expand Down Expand Up @@ -139,6 +139,39 @@
}
]
},
{
"sku": "GitHub Copilot Business",
"items": [
{
"id": 23,
"title": "Usage metrics",
"videoUrl": "",
"description": "Track your team's usage of Copilot with detailed metrics and insights.",
"ghes_support": false
},
{
"id": 24,
"title": "Data excluded from training by default",
"videoUrl": "",
"description": "From the business version and upwards, GitHub Copilot will not use your prompt and nteractions to train Copilot on.",
"ghes_support": false
},
{
"id": 25,
"title": "User management",
"videoUrl": "",
"description": "This lets you assign licenses per user, for example to every user in a team / organization / or repository.",
"ghes_support": false
},
{
"id": 26,
"title": "Content Exclusions",
"videoUrl": "",
"description": "With Content Exclusions you can exclude certain parts of your codebase from being sent to Copilot. Think for example of files containing sensitive information, like secrets.",
"ghes_support": false
}
]
},
{
"sku": "GitHub Copilot Enterprise",
"items": [
Expand All @@ -159,6 +192,12 @@
"title": "Fine tuned models",
"videoUrl": "",
"description": "Benefit from models fine-tuned for your specific coding needs with Copilot."
},
{
"id": 22,
"title": "Technical Preview access to Copilot Workspace",
"videoUrl": "https://youtu.be/N64ozm3x88k",
"description": "Technical Preview access to Copilot Workspace is available for Copilot Enterprise users. In this video Rob shows an early version of Workspace and how it lets you work in the context of an issue and the entire repository to get your task executed."
}
]
}
Expand Down
112 changes: 58 additions & 54 deletions src/pages/Index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const Index = () => {
const [feedCounts, setFeedCounts] = useState({});
const [totalItemCount, setTotalItemCount] = useState(0);

const REACT_APP_NODE_ENV = "bla";
const buildNumber = import.meta.env.REACT_APP_BUILDNUMBER || 'unknown';

useEffect(() => {
const fetchFeeds = async () => {
try {
Expand All @@ -22,62 +25,61 @@ const Index = () => {
}, []);

useEffect(() => {
const fetchRSSItems = async () => {
const counts = {};
let totalItems = 0;
const uniqueItems = new Map();

for (const feed of feeds) {

try {
let response;
if (feed.cors) {
// Todo: Use a proxy to avoid CORS issues
continue;
}
else {
response = await fetch(feed.url).then(res => res.text());
}
const data = new window.DOMParser().parseFromString(response, "text/xml");
const items = data.querySelectorAll("item");
counts[feed.name] = items.length;
totalItems += items.length;

items.forEach(item => {
const title = item.querySelector("title").textContent;
const description = item.querySelector("description").textContent;
const pubDate = new Date(item.querySelector("pubDate").textContent);
const formattedDate = pubDate.toLocaleDateString("en-US", { year: 'numeric', month: 'long', day: 'numeric' });

if (uniqueItems.has(title)) {
uniqueItems.get(title).feeds.push(feed.name);
const fetchRSSItems = async () => {;

const counts = {};
let totalItems = 0;
const uniqueItems = new Map();

for (const feed of feeds) {
try {
let response;
if (feed.cors) {
// Todo: Use a proxy to avoid CORS issues
continue;
} else {
uniqueItems.set(title, {
description,
pubDate: formattedDate,
feeds: [feed.name]
});
response = await fetch(feed.url).then(res => res.text());
}
});
} catch (error) {
console.error(`Error fetching feed ${feed.name}:`, error);
const data = new window.DOMParser().parseFromString(response, "text/xml");
const items = data.querySelectorAll("item");
counts[feed.name] = items.length;
totalItems += items.length;

items.forEach(item => {
const title = item.querySelector("title").textContent;
const description = item.querySelector("description").textContent;
const pubDate = new Date(item.querySelector("pubDate").textContent);
const formattedDate = pubDate.toLocaleDateString("en-US", { year: 'numeric', month: 'long', day: 'numeric' });

if (uniqueItems.has(title)) {
uniqueItems.get(title).feeds.push(feed.name);
} else {
uniqueItems.set(title, {
description,
pubDate: formattedDate,
feeds: [feed.name]
});
}
});
} catch (error) {
console.error(`Error fetching feed ${feed.name}:`, error);
}
}
}

uniqueItems.forEach((value, title) => {
const newsItem = document.createElement('div');
newsItem.className = 'news-item';
newsItem.innerHTML = `
<h4>${title}</h4>
<p>${value.description}</p>
${value.feeds.map(feed => `<span>${feed}</span>`).join('')}
<span class="date">Published: ${value.pubDate}</span>
`;
document.getElementById('news-content').appendChild(newsItem);
});
uniqueItems.forEach((value, title) => {
const newsItem = document.createElement('div');
newsItem.className = 'news-item';
newsItem.innerHTML = `
<h4>${title}</h4>
<p>${value.description}</p>
${value.feeds.map(feed => `<span>${feed}</span>`).join('')}
<span class="date">Published: ${value.pubDate}</span>
`;
document.getElementById('news-content').appendChild(newsItem);
});

setFeedCounts(counts);
setTotalItemCount(totalItems);
setFeedCounts(counts);
setTotalItemCount(totalItems);
};

if (feeds.length > 0) {
Expand Down Expand Up @@ -161,11 +163,13 @@ const Index = () => {
</div>

<div className="footer">
<div>Build: {process.env.BUILDNUMBER}</div>
<div>NODE_ENV: {process.env.NODE_ENV}</div>

<div>Build: {buildNumber}</div>
<div>NODE_ENV: {REACT_APP_NODE_ENV}</div>
</div>
</div>
);
};

export default Index;

export default Index;
26 changes: 23 additions & 3 deletions src/pages/Skus.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import getData from '../utils/getData';
import Header from './title-header';

const Skus = () => {
const [features, setFeatures] = useState({ business: [], enterprise: [], ghesFiltered: true });
const [features, setFeatures] = useState({ individual: [], business: [], enterprise: [], ghesFiltered: true });

const navigate = useNavigate();

Expand Down Expand Up @@ -58,17 +58,18 @@ const Skus = () => {
useEffect(() => {
getData()
.then(data => {
const individual = data.features.videos.find(feature => feature.sku === "GitHub Copilot Individual");
const business = data.features.videos.find(feature => feature.sku === "GitHub Copilot Business");
const enterprise = data.features.videos.find(feature => feature.sku === "GitHub Copilot Enterprise");
setFeatures({ business: business.items, enterprise: enterprise.items, ghesFiltered: false });
setFeatures({individual: individual.items, business: business.items, enterprise: enterprise.items, ghesFiltered: false });
handleGHESToggle();
})
.catch(error => console.error('Error loading SKU data:', error));
}, []);

return (
<div>
<Header title={`GitHub Copilot Business vs Enterprise`}/>
<Header title={`GitHub Copilot Features per license type`}/>

<button
id="ghesToggle"
Expand All @@ -79,6 +80,25 @@ const Skus = () => {
</button>

<div id="main-container">
<div>
<div>
<h2>GitHub Copilot Individual</h2>
</div>
<div id="individual-features" className="sku-grid individual">
{
features.individual.map(item => (
<div
data-key={item.id}
className={`video-box ${item.ghes_support ? 'ghes-support' : ''}`}
onClick={() => handleClick(item.id)}
>
<h3>{item.title}</h3>
{!item.videoUrl && <div className="coming-soon-small">Video coming soon</div>}
</div>
))
}
</div>
</div>
<div>
<div>
<h2>GitHub Copilot Business</h2>
Expand Down
Loading

0 comments on commit ea6bfd0

Please sign in to comment.