mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2026-03-13 10:11:55 +08:00
Compare commits
273 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c628925ae | ||
|
|
96de50e15b | ||
|
|
f94c11d1ea | ||
|
|
d02f0e5d54 | ||
|
|
53bb1d922a | ||
|
|
8ebc67baa1 | ||
|
|
94231874b0 | ||
|
|
d7f74b34a6 | ||
|
|
e3361f96c1 | ||
|
|
eb0dac034d | ||
|
|
9e352be949 | ||
|
|
452c10a893 | ||
|
|
71c4a7d072 | ||
|
|
1d3a785027 | ||
|
|
c0d4faa385 | ||
|
|
0bd4c0af03 | ||
|
|
6abc5ff916 | ||
|
|
a143b0ec20 | ||
|
|
d9c25d8dff | ||
|
|
3101d8ae5d | ||
|
|
576c307a5f | ||
|
|
393022c826 | ||
|
|
932b513d98 | ||
|
|
e0ae5dd309 | ||
|
|
70bc2a1038 | ||
|
|
86c1120559 | ||
|
|
c3135e1470 | ||
|
|
23346ec007 | ||
|
|
c92a183ef8 | ||
|
|
ca7888aa37 | ||
|
|
33b36a7017 | ||
|
|
bff98e6448 | ||
|
|
5dd2bc439f | ||
|
|
24d10d212f | ||
|
|
4127f77aac | ||
|
|
dbebf593fc | ||
|
|
0e0b550f98 | ||
|
|
80741df13b | ||
|
|
14b6aea3b1 | ||
|
|
e0da1e4f0e | ||
|
|
5cc4b834d1 | ||
|
|
314eb5d7d2 | ||
|
|
ad2597f610 | ||
|
|
8d25eabe3a | ||
|
|
6186e12b05 | ||
|
|
158857c928 | ||
|
|
8e6959cc60 | ||
|
|
e351f653a1 | ||
|
|
83e315aef7 | ||
|
|
b15bdd5f78 | ||
|
|
0783330a70 | ||
|
|
7ec56fd1ff | ||
|
|
201632941a | ||
|
|
126501b40a | ||
|
|
34ba9162b2 | ||
|
|
e093eddabc | ||
|
|
1e4a4c96b8 | ||
|
|
0c3ea981cb | ||
|
|
5de9539af5 | ||
|
|
3722e5f3bd | ||
|
|
7f90b8a0b0 | ||
|
|
2bafd61f71 | ||
|
|
adc66cf97c | ||
|
|
c754a971c3 | ||
|
|
dbda69fc23 | ||
|
|
6f1087981c | ||
|
|
ec8a0917c1 | ||
|
|
60e5e38a55 | ||
|
|
5d77d36236 | ||
|
|
37b3140516 | ||
|
|
34b68478cc | ||
|
|
9bb86408c5 | ||
|
|
d07fd3d183 | ||
|
|
9aa363a01e | ||
|
|
9f2a33f078 | ||
|
|
91cfa88b3d | ||
|
|
d87ea1c972 | ||
|
|
dbf2353a41 | ||
|
|
8d78c17c77 | ||
|
|
698dbbd7d8 | ||
|
|
25216d4052 | ||
|
|
2be0d61a1e | ||
|
|
f3ee75e92d | ||
|
|
db0b5e77ad | ||
|
|
c239886049 | ||
|
|
aab03074f8 | ||
|
|
433302b910 | ||
|
|
a583937f5c | ||
|
|
412e3b5935 | ||
|
|
1ffa292c98 | ||
|
|
0bef28fa20 | ||
|
|
1af013d5f8 | ||
|
|
28af19cd1c | ||
|
|
4696af9c6a | ||
|
|
e2dece0e6a | ||
|
|
a5f483c335 | ||
|
|
4552d3f9c8 | ||
|
|
f213bd9604 | ||
|
|
de65909357 | ||
|
|
9a77ca8a17 | ||
|
|
7ab3f758fd | ||
|
|
bcf4126b3a | ||
|
|
f9dbd16afe | ||
|
|
21ed4a647f | ||
|
|
68cf2c00c6 | ||
|
|
d3b0c32eb7 | ||
|
|
37ca08f956 | ||
|
|
b40ec83137 | ||
|
|
edc7de8226 | ||
|
|
5bffdebeb8 | ||
|
|
e5e902a268 | ||
|
|
5842b0a692 | ||
|
|
f1592571db | ||
|
|
4058dff406 | ||
|
|
5a813eea04 | ||
|
|
e577ba095f | ||
|
|
069cb6fc06 | ||
|
|
b0a3cdc8c4 | ||
|
|
536a79ef59 | ||
|
|
5a132b6f07 | ||
|
|
e3b56ab716 | ||
|
|
2d8030a175 | ||
|
|
dca2ba5fac | ||
|
|
16fc4b08ff | ||
|
|
7a7590d872 | ||
|
|
073708e7e9 | ||
|
|
66a8c2e73c | ||
|
|
34425019b7 | ||
|
|
699e05a3b4 | ||
|
|
3bd379692f | ||
|
|
22f29a12f9 | ||
|
|
2640c82167 | ||
|
|
9ff560b1fd | ||
|
|
e16866009a | ||
|
|
2085a31894 | ||
|
|
0534e99093 | ||
|
|
19a6cb20ec | ||
|
|
7b59b5862e | ||
|
|
3d2db1b46e | ||
|
|
8cf272431d | ||
|
|
b05f6148ac | ||
|
|
19dd7f7f4f | ||
|
|
a22867bd96 | ||
|
|
23eb9b6626 | ||
|
|
2d3c86ceff | ||
|
|
5e97ded10d | ||
|
|
cbd290baa2 | ||
|
|
da968b6d5b | ||
|
|
07ebf3585d | ||
|
|
26b5ccd10f | ||
|
|
3c03cb46f7 | ||
|
|
514edea44e | ||
|
|
f0b740bfb2 | ||
|
|
8e68f7230c | ||
|
|
090100d784 | ||
|
|
e9e100d46e | ||
|
|
c2a206ac37 | ||
|
|
05d36c898e | ||
|
|
d4c33930b5 | ||
|
|
7a931f2f3b | ||
|
|
565ec779dc | ||
|
|
e716765f01 | ||
|
|
3b274f3b0a | ||
|
|
1623d09de6 | ||
|
|
d2bf09b405 | ||
|
|
f3110e99f6 | ||
|
|
cdc6591765 | ||
|
|
96db3e3920 | ||
|
|
f7df0acc90 | ||
|
|
1480b20dcb | ||
|
|
e11ce51b09 | ||
|
|
3c7761cbe8 | ||
|
|
65996a6982 | ||
|
|
99b1859de2 | ||
|
|
7b2a047046 | ||
|
|
6bbf384b73 | ||
|
|
4bd1c4aebc | ||
|
|
14835464de | ||
|
|
020def730d | ||
|
|
ca1cad9bfc | ||
|
|
5ac086036e | ||
|
|
5fbec97c8d | ||
|
|
94bc36d67e | ||
|
|
98997800b9 | ||
|
|
9b32685e88 | ||
|
|
9d0c2667fc | ||
|
|
aa3c065b51 | ||
|
|
657ee41900 | ||
|
|
ad203cca4e | ||
|
|
b83eedbb68 | ||
|
|
0d8b039114 | ||
|
|
0a1705fdc1 | ||
|
|
a2063c2822 | ||
|
|
4c6f0a1234 | ||
|
|
b1d87ae639 | ||
|
|
609faeacef | ||
|
|
6469ef3078 | ||
|
|
721456a82e | ||
|
|
ef958779d6 | ||
|
|
77ca038e8c | ||
|
|
e52608a48a | ||
|
|
85cc58b85e | ||
|
|
d9ec7b71ec | ||
|
|
80d4d37e5c | ||
|
|
c584325a7d | ||
|
|
942050e56c | ||
|
|
7cfdfaab1f | ||
|
|
8148cb23ad | ||
|
|
9e15f59660 | ||
|
|
2b07b2d4cd | ||
|
|
00c288855e | ||
|
|
b7848fd73c | ||
|
|
de1f9fc2d2 | ||
|
|
8cf5765349 | ||
|
|
b4621733be | ||
|
|
b7eb3166ed | ||
|
|
534a27e7a7 | ||
|
|
0c355f3cef | ||
|
|
3a72911bc6 | ||
|
|
6c099db875 | ||
|
|
8b80f4b00b | ||
|
|
7abe4ab91d | ||
|
|
c5f1e383c7 | ||
|
|
2b5134e0a5 | ||
|
|
f3b325e72f | ||
|
|
78084be9a4 | ||
|
|
bfcb32bd57 | ||
|
|
2623d7abeb | ||
|
|
90e20fcd8f | ||
|
|
78f28fb18e | ||
|
|
412676b0c7 | ||
|
|
c45314c991 | ||
|
|
d8aab6180c | ||
|
|
3727b33000 | ||
|
|
fd97b2810e | ||
|
|
62a8a5836c | ||
|
|
ca696e6f01 | ||
|
|
64b5bdfbe2 | ||
|
|
6c9b0c1fb8 | ||
|
|
03c85f29c8 | ||
|
|
c96886c929 | ||
|
|
f3584f8af6 | ||
|
|
7daf1e213b | ||
|
|
7d461a44b4 | ||
|
|
e2926012f4 | ||
|
|
a5afac7d6d | ||
|
|
e734563996 | ||
|
|
cc3db36fc2 | ||
|
|
d6e842169a | ||
|
|
96de0f98df | ||
|
|
4c05f135f0 | ||
|
|
a81c435500 | ||
|
|
add174a69b | ||
|
|
9023073f9b | ||
|
|
e8082ae75e | ||
|
|
e43bb2c1f8 | ||
|
|
d9cbc2f56e | ||
|
|
6158d4def8 | ||
|
|
a317d90f14 | ||
|
|
8e1ba1eae2 | ||
|
|
fa3312f70c | ||
|
|
d7ed3a1cb5 | ||
|
|
68675d6c16 | ||
|
|
7ba2d22463 | ||
|
|
18f77a01f8 | ||
|
|
faf70f6e35 | ||
|
|
bf734b0294 | ||
|
|
266d357e2a | ||
|
|
addf973c81 | ||
|
|
8d841b1bf2 | ||
|
|
c099f341b5 | ||
|
|
6f38dcccb8 | ||
|
|
9d65c49b8d |
@@ -3,6 +3,6 @@
|
||||
"enabled": false
|
||||
},
|
||||
"_variables": {
|
||||
"lastUpdateCheck": 1732419746256
|
||||
"lastUpdateCheck": 1739229597159
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
PUBLIC_API_URL=https://api.roadmap.sh
|
||||
PUBLIC_AVATAR_BASE_URL=https://dodrc8eu8m09s.cloudfront.net/avatars
|
||||
PUBLIC_EDITOR_APP_URL=https://draw.roadmap.sh
|
||||
PUBLIC_EDITOR_APP_URL=https://draw.roadmap.sh
|
||||
PUBLIC_COURSE_APP_URL=http://localhost:5173
|
||||
2
.github/workflows/cloudfront-fe-cache.yml
vendored
2
.github/workflows/cloudfront-fe-cache.yml
vendored
@@ -13,4 +13,4 @@ jobs:
|
||||
-H "Authorization: Bearer ${{ secrets.GH_PAT }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/roadmapsh/infra-ansible/actions/workflows/playbook.yml/dispatches \
|
||||
-d '{ "ref":"master", "inputs": { "playbook": "roadmap_web.yml", "tags": "cloudfront", "is_verbose": false } }'
|
||||
-d '{ "ref":"master", "inputs": { "playbook": "roadmap_web.yml", "tags": "cloudfront,cloudfront-course", "is_verbose": false } }'
|
||||
|
||||
23
.github/workflows/greetings.yml
vendored
Normal file
23
.github/workflows/greetings.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: ❤️ Greetings
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
pull_request_target:
|
||||
branches: [master]
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
greet:
|
||||
name: Greet New Contributors
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/first-interaction@v1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
pr-message: |
|
||||
Thank you for your first ever contribution to [roadmap.sh](https://roadmap.sh)! 🎉
|
||||
|
||||
Please make sure to follow the [contribution guidelines](https://github.com/kamranahmedse/developer-roadmap/blob/master/contributing.md) when contributing to this project. Any PRs that don't follow the guidelines will be closed.
|
||||
|
||||
Thanks for choosing to contribute, and for helping make this project better! 🌟
|
||||
2
.github/workflows/upgrade-dependencies.yml
vendored
2
.github/workflows/upgrade-dependencies.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
## Updated all Dependencies to Latest Versions.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This PR Upgrades the Dependencies to the Latest Their Versions.
|
||||
> This PR Upgrades the Dependencies to the their latest versions.
|
||||
>
|
||||
> Commit: ${{ github.sha }}
|
||||
> Workflow Path: ${{ github.workflow_ref }}
|
||||
|
||||
@@ -55,6 +55,8 @@ Find [the content directory inside the relevant roadmap](https://github.com/kamr
|
||||
- Maximum of 8 links per topic.
|
||||
- Follow the below style guide for content.
|
||||
|
||||
Please note that we are intentionally keeping the content under the topic popup concise. You MUST always aim to explain the topic simply in a **single paragraph** or so and provide external resources where users can learn more about the topic.
|
||||
|
||||
### How To Structure Content
|
||||
|
||||
Please adhere to the following style when adding content to a topic:
|
||||
|
||||
3
license
3
license
@@ -1,6 +1,7 @@
|
||||
Everything including text and images in this project are protected by the copyright laws.
|
||||
You are allowed to use this material for personal use but are not allowed to use it for
|
||||
any other purpose including publishing the images, the project files or the content in the images in any form either digital, non-digital, textual, graphical or written formats.
|
||||
any other purpose including publishing the images, the project files or the content in
|
||||
the images in any form either digital, non-digital, textual, graphical or written formats.
|
||||
You are allowed to share the links to the repository or the website roadmap.sh but not
|
||||
the content for any sort of usage that involves the content of this repository taken out
|
||||
of the repository and be shared from any other medium including but not limited to blog
|
||||
|
||||
@@ -67,10 +67,12 @@
|
||||
"rehype-external-links": "^3.0.0",
|
||||
"remark-parse": "^11.0.0",
|
||||
"roadmap-renderer": "^1.0.6",
|
||||
"sanitize-html": "^2.13.1",
|
||||
"satori": "^0.11.2",
|
||||
"satori-html": "^0.3.2",
|
||||
"sharp": "^0.33.5",
|
||||
"slugify": "^1.6.6",
|
||||
"tiptap-markdown": "^0.8.10",
|
||||
"tailwind-merge": "^2.5.3",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"turndown": "^7.2.0",
|
||||
@@ -86,6 +88,7 @@
|
||||
"@types/prismjs": "^1.26.4",
|
||||
"@types/react-calendar-heatmap": "^1.6.7",
|
||||
"@types/react-slick": "^0.23.13",
|
||||
"@types/sanitize-html": "^2.13.0",
|
||||
"@types/turndown": "^5.0.5",
|
||||
"csv-parser": "^3.0.0",
|
||||
"gh-pages": "^6.2.0",
|
||||
|
||||
2718
pnpm-lock.yaml
generated
2718
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
public/pdfs/roadmaps/php.pdf
Normal file
BIN
public/pdfs/roadmaps/php.pdf
Normal file
Binary file not shown.
Binary file not shown.
@@ -170,7 +170,7 @@
|
||||
},
|
||||
"Gd2egqKZPnbPW1W2jw4j8": {
|
||||
"title": "Econometrics",
|
||||
"description": "Ecenometrics is the application of statistical methods to economic data. It is a branch of economics that aims to give empirical content to economic relations. More precisely, it is \"the quantitative analysis of actual economic phenomena based on the concurrent development of theory and observation, related by appropriate methods of inference.\" Econometrics can be described as something that allows economists \"to sift through mountains of data to extract simple relationships.\"",
|
||||
"description": "Econometrics is the application of statistical methods to economic data. It is a branch of economics that aims to give empirical content to economic relations. More precisely, it is \"the quantitative analysis of actual economic phenomena based on the concurrent development of theory and observation, related by appropriate methods of inference.\" Econometrics can be described as something that allows economists \"to sift through mountains of data to extract simple relationships.\"",
|
||||
"links": []
|
||||
},
|
||||
"y6xXsc-uSAmRDnNuyhqH2": {
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
"title": "Introduction",
|
||||
"description": "AI Engineering is the process of designing and implementing AI systems using pre-trained models and existing AI tools to solve practical problems. AI Engineers focus on applying AI in real-world scenarios, improving user experiences, and automating tasks, without developing new models from scratch. They work to ensure AI systems are efficient, scalable, and can be seamlessly integrated into business applications, distinguishing their role from AI Researchers and ML Engineers, who concentrate more on creating new models or advancing AI theory.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "AI Engineering",
|
||||
"url": "https://en.wikipedia.org/wiki/Artificial_intelligence_engineering",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "AI vs Machine Learning",
|
||||
"url": "https://www.youtube.com/watch?v=4RixMPF4xis",
|
||||
@@ -62,7 +67,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How Large Langauge Models Work",
|
||||
"title": "How Large Language Models Work",
|
||||
"url": "https://www.youtube.com/watch?v=5sLYAQS9sWQ",
|
||||
"type": "video"
|
||||
},
|
||||
@@ -120,12 +125,12 @@
|
||||
"description": "Embeddings are dense, continuous vector representations of data, such as words, sentences, or images, in a lower-dimensional space. They capture the semantic relationships and patterns in the data, where similar items are placed closer together in the vector space. In machine learning, embeddings are used to convert complex data into numerical form that models can process more easily. For example, word embeddings represent words based on their meanings and contexts, allowing models to understand relationships like synonyms or analogies. Embeddings are widely used in tasks like natural language processing, recommendation systems, and image recognition to improve model performance and efficiency.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What are embeddings in machine learning?",
|
||||
"title": "What are Embeddings in Machine Learning?",
|
||||
"url": "https://www.cloudflare.com/en-gb/learning/ai/what-are-embeddings/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is embedding?",
|
||||
"title": "What is Embedding?",
|
||||
"url": "https://www.ibm.com/topics/embedding",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -178,7 +183,7 @@
|
||||
"description": "Prompt engineering is the process of crafting effective inputs (prompts) to guide AI models, like GPT, to generate desired outputs. It involves strategically designing prompts to optimize the model’s performance by providing clear instructions, context, and examples. Effective prompt engineering can improve the quality, relevance, and accuracy of responses, making it essential for applications like chatbots, content generation, and automated support. By refining prompts, developers can better control the model’s behavior, reduce ambiguity, and achieve more consistent results, enhancing the overall effectiveness of AI-driven systems.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Prompt Engineering Roadmap",
|
||||
"title": "Visit DedicatedPrompt Engineering Roadmap",
|
||||
"url": "https://roadmap.sh/prompt-engineering",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -263,7 +268,7 @@
|
||||
"description": "Pre-trained models are Machine Learning (ML) models that have been previously trained on a large dataset to solve a specific task or set of tasks. These models learn patterns, features, and representations from the training data, which can then be fine-tuned or adapted for other related tasks. Pre-training provides a good starting point, reducing the amount of data and computation required to train a new model from scratch.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Pre-trained models: Past, present and future",
|
||||
"title": "Pre-trained Models: Past, Present and Future",
|
||||
"url": "https://www.sciencedirect.com/science/article/pii/S2666651021000231",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -290,7 +295,7 @@
|
||||
"description": "Pre-trained models, while powerful, come with several limitations and considerations. They may carry biases present in the training data, leading to unintended or discriminatory outcomes, these models are also typically trained on general data, so they might not perform well on niche or domain-specific tasks without further fine-tuning. Another concern is the \"black-box\" nature of many pre-trained models, which can make their decision-making processes hard to interpret and explain.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Pretrained Topic Models: Advantages and Limitation",
|
||||
"title": "Pre-trained Topic Models: Advantages and Limitation",
|
||||
"url": "https://www.kaggle.com/code/amalsalilan/pretrained-topic-models-advantages-and-limitation",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -371,6 +376,11 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "Google Gemini",
|
||||
"url": "https://gemini.google.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Google's Gemini Documentation",
|
||||
"url": "https://workspace.google.com/solutions/ai/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -469,8 +479,14 @@
|
||||
},
|
||||
"zdeuA4GbdBl2DwKgiOA4G": {
|
||||
"title": "OpenAI API",
|
||||
"description": "The OpenAI API provides access to powerful AI models like GPT, Codex, DALL-E, and Whisper, enabling developers to integrate capabilities such as text generation, code assistance, image creation, and speech recognition into their applications via a simple, scalable interface.",
|
||||
"links": []
|
||||
"description": "The OpenAI API provides access to powerful AI models like GPT, Codex, DALL-E, and Whisper, enabling developers to integrate capabilities such as text generation, code assistance, image creation, and speech recognition into their applications via a simple, scalable interface.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Open AI API",
|
||||
"url": "https://openai.com/api/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"_bPTciEA1GT1JwfXim19z": {
|
||||
"title": "Chat Completions API",
|
||||
@@ -482,7 +498,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"title": "Getting Start with Chat Completions API",
|
||||
"url": "https://medium.com/the-ai-archives/getting-started-with-openais-chat-completions-api-in-2024-462aae00bf0a",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -493,7 +509,7 @@
|
||||
"description": "Prompts for the OpenAI API are carefully crafted inputs designed to guide the language model in generating specific, high-quality content. These prompts can be used to direct the model to create stories, articles, dialogue, or even detailed responses on particular topics. Effective prompts set clear expectations by providing context, specifying the format, or including examples, such as \"Write a short sci-fi story about a future where humans can communicate with animals,\" or \"Generate a detailed summary of the key benefits of using renewable energy.\" Well-designed prompts help ensure that the API produces coherent, relevant, and creative outputs, making it easier to achieve desired results across various applications.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "",
|
||||
"title": "Visit Dedicated Prompt Engineering Roadmap",
|
||||
"url": "https://roadmap.sh/prompt-engineering",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -589,7 +605,7 @@
|
||||
"description": "AI safety and ethics involve establishing guidelines and best practices to ensure that artificial intelligence systems are developed, deployed, and used in a manner that prioritizes human well-being, fairness, and transparency. This includes addressing risks such as bias, privacy violations, unintended consequences, and ensuring that AI operates reliably and predictably, even in complex environments. Ethical considerations focus on promoting accountability, avoiding discrimination, and aligning AI systems with human values and societal norms. Frameworks like explainability, human-in-the-loop design, and robust monitoring are often used to build systems that not only achieve technical objectives but also uphold ethical standards and mitigate potential harms.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Understanding artificial intelligence ethics and safety",
|
||||
"title": "Understanding Artificial Intelligence Ethics and Safety",
|
||||
"url": "https://www.turing.ac.uk/news/publications/understanding-artificial-intelligence-ethics-and-safety",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -617,7 +633,7 @@
|
||||
]
|
||||
},
|
||||
"lhIU0ulpvDAn1Xc3ooYz_": {
|
||||
"title": "Bias and Fareness",
|
||||
"title": "Bias and Fairness",
|
||||
"description": "Bias and fairness in AI refer to the challenges of ensuring that machine learning models do not produce discriminatory or skewed outcomes. Bias can arise from imbalanced training data, flawed assumptions, or biased algorithms, leading to unfair treatment of certain groups based on race, gender, or other factors. Fairness aims to address these issues by developing techniques to detect, mitigate, and prevent biases in AI systems. Ensuring fairness involves improving data diversity, applying fairness constraints during model training, and continuously monitoring models in production to avoid unintended consequences, promoting ethical and equitable AI use.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
@@ -760,12 +776,12 @@
|
||||
"description": "Open-source models are freely available for customization and collaboration, promoting transparency and flexibility, while closed-source models are proprietary, offering ease of use but limiting modification and transparency.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "OpenAI vs. open-source LLM",
|
||||
"title": "OpenAI vs. Open Source LLM",
|
||||
"url": "https://ubiops.com/openai-vs-open-source-llm/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "AI360 | Open-Source vs Closed-Source LLMs",
|
||||
"title": "Open-Source vs Closed-Source LLMs",
|
||||
"url": "https://www.youtube.com/watch?v=710PDpuLwOc",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -818,7 +834,7 @@
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Documentation",
|
||||
"title": "Hugging Face Documentation",
|
||||
"url": "https://huggingface.co/docs/hub/en/index",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -932,20 +948,31 @@
|
||||
},
|
||||
"--ig0Ume_BnXb9K2U7HJN": {
|
||||
"title": "What are Embeddings",
|
||||
"description": "Embeddings are dense, numerical vector representations of data, such as words, sentences, images, or audio, that capture their semantic meaning and relationships. By converting data into fixed-length vectors, embeddings allow machine learning models to process and understand the data more effectively. For example, word embeddings represent similar words with similar vectors, enabling tasks like semantic search, recommendation systems, and clustering. Embeddings make it easier to compare, search, and analyze complex, unstructured data by mapping similar items close together in a high-dimensional space.",
|
||||
"links": []
|
||||
"description": "Embeddings are dense, numerical vector representations of data, such as words, sentences, images, or audio, that capture their semantic meaning and relationships. By converting data into fixed-length vectors, embeddings allow machine learning models to process and understand the data more effectively. For example, word embeddings represent similar words with similar vectors, enabling tasks like semantic search, recommendation systems, and clustering. Embeddings make it easier to compare, search, and analyze complex, unstructured data by mapping similar items close together in a high-dimensional space.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Introducing Text and Code Embeddings",
|
||||
"url": "https://openai.com/index/introducing-text-and-code-embeddings/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What are Embeddings",
|
||||
"url": "https://www.cloudflare.com/learning/ai/what-are-embeddings/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"eMfcyBxnMY_l_5-8eg6sD": {
|
||||
"title": "Semantic Search",
|
||||
"description": "Embeddings are used for semantic search by converting text, such as queries and documents, into high-dimensional vectors that capture the underlying meaning and context, rather than just exact words. These embeddings represent the semantic relationships between words or phrases, allowing the system to understand the query’s intent and retrieve relevant information, even if the exact terms don’t match.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is semantic search?",
|
||||
"title": "What is Semantic Search?",
|
||||
"url": "https://www.elastic.co/what-is/semantic-search",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is Semantic Search? Cohere",
|
||||
"title": "What is Semantic Search? - Cohere",
|
||||
"url": "https://www.youtube.com/watch?v=fFt4kR4ntAA",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -972,7 +999,7 @@
|
||||
"description": "Anomaly detection with embeddings works by transforming data, such as text, images, or time-series data, into vector representations that capture their patterns and relationships. In this high-dimensional space, similar data points are positioned close together, while anomalies stand out as those that deviate significantly from the typical distribution. This approach is highly effective for detecting outliers in tasks like fraud detection, network security, and quality control.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Anomoly in Embeddings",
|
||||
"title": "Anomaly in Embeddings",
|
||||
"url": "https://ai.google.dev/gemini-api/tutorials/anomaly_detection",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -999,7 +1026,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Master OpenAI EMBEDDING API",
|
||||
"title": "Master OpenAI Embedding API",
|
||||
"url": "https://www.youtube.com/watch?v=9oCS-VQupoc",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -1065,8 +1092,19 @@
|
||||
},
|
||||
"tt9u3oFlsjEMfPyojuqpc": {
|
||||
"title": "Vector Databases",
|
||||
"description": "Vector databases are systems specialized in storing, indexing, and retrieving high-dimensional vectors, often used as embeddings for data like text, images, or audio. Unlike traditional databases, they excel at managing unstructured data by enabling fast similarity searches, where vectors are compared to find the closest matches. This makes them essential for tasks like semantic search, recommendation systems, and content discovery. Using techniques like approximate nearest neighbor (ANN) search, vector databases handle large datasets efficiently, ensuring quick and accurate retrieval even at scale.",
|
||||
"links": []
|
||||
"description": "Vector databases are systems specialized in storing, indexing, and retrieving high-dimensional vectors, often used as embeddings for data like text, images, or audio. Unlike traditional databases, they excel at managing unstructured data by enabling fast similarity searches, where vectors are compared to find the closest matches. This makes them essential for tasks like semantic search, recommendation systems, and content discovery. Using techniques like approximate nearest neighbor (ANN) search, vector databases handle large datasets efficiently, ensuring quick and accurate retrieval even at scale.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Vector Databases",
|
||||
"url": "https://developers.cloudflare.com/vectorize/reference/what-is-a-vector-database/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What are Vector Databases?",
|
||||
"url": "https://www.mongodb.com/resources/basics/databases/vector-databases",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"WcjX6p-V-Rdd77EL8Ega9": {
|
||||
"title": "Purpose and Functionality",
|
||||
@@ -1110,7 +1148,7 @@
|
||||
"description": "Pinecone is a managed vector database designed for efficient similarity search and real-time retrieval of high-dimensional data, such as embeddings. It allows developers to store, index, and query vector representations, making it easy to build applications like recommendation systems, semantic search, and AI-driven content discovery. Pinecone is scalable, handles large datasets, and provides fast, low-latency searches using optimized indexing techniques.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Pinecone Website",
|
||||
"title": "Pinecone",
|
||||
"url": "https://www.pinecone.io",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1131,7 +1169,7 @@
|
||||
"description": "Weaviate is an open-source vector database that allows users to store, search, and manage high-dimensional vectors, often used for tasks like semantic search and recommendation systems. It enables efficient similarity searches by converting data (like text, images, or audio) into embeddings and indexing them for fast retrieval. Weaviate also supports integrating external data sources and schemas, making it easy to combine structured and unstructured data.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Weaviate Website",
|
||||
"title": "Weaviate",
|
||||
"url": "https://weaviate.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1173,9 +1211,14 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "LanceDB Website",
|
||||
"title": "LanceDB",
|
||||
"url": "https://lancedb.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "LanceDB Documentation",
|
||||
"url": "https://docs.lancedb.com/enterprise/introduction",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1189,7 +1232,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Qdrant Website",
|
||||
"title": "Qdrant",
|
||||
"url": "https://qdrant.tech/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1205,7 +1248,7 @@
|
||||
"description": "Supabase Vector is an extension of the Supabase platform, specifically designed for AI and machine learning applications that require vector operations. It leverages PostgreSQL's pgvector extension to provide efficient vector storage and similarity search capabilities. This makes Supabase Vector particularly useful for applications involving embeddings, semantic search, and recommendation systems. With Supabase Vector, developers can store and query high-dimensional vector data alongside regular relational data, all within the same PostgreSQL database.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Supabase Vector website",
|
||||
"title": "Supabase Vector",
|
||||
"url": "https://supabase.com/vector",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1237,7 +1280,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Vector Databases simply explained! (Embeddings & Indexes)",
|
||||
"title": "Vector Databases Simply Explained! (Embeddings & Indexes)",
|
||||
"url": "https://www.youtube.com/watch?v=dN0lsF2cvm4",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -1250,8 +1293,19 @@
|
||||
},
|
||||
"lVhWhZGR558O-ljHobxIi": {
|
||||
"title": "RAG & Implementation",
|
||||
"description": "Retrieval-Augmented Generation (RAG) combines information retrieval with language generation to produce more accurate, context-aware responses. It uses two components: a retriever, which searches a database to find relevant information, and a generator, which crafts a response based on the retrieved data. Implementing RAG involves using a retrieval model (e.g., embeddings and vector search) alongside a generative language model (like GPT). The process starts by converting a query into embeddings, retrieving relevant documents from a vector database, and feeding them to the language model, which then generates a coherent, informed response. This approach grounds outputs in real-world data, resulting in more reliable and detailed answers.",
|
||||
"links": []
|
||||
"description": "Retrieval-Augmented Generation (RAG) combines information retrieval with language generation to produce more accurate, context-aware responses. It uses two components: a retriever, which searches a database to find relevant information, and a generator, which crafts a response based on the retrieved data. Implementing RAG involves using a retrieval model (e.g., embeddings and vector search) alongside a generative language model (like GPT). The process starts by converting a query into embeddings, retrieving relevant documents from a vector database, and feeding them to the language model, which then generates a coherent, informed response. This approach grounds outputs in real-world data, resulting in more reliable and detailed answers.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is RAG?",
|
||||
"url": "https://aws.amazon.com/what-is/retrieval-augmented-generation/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is Retrieval-Augmented Generation? IBM",
|
||||
"url": "https://www.youtube.com/watch?v=T-D1OfcDW1M",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
"GCn4LGNEtPI0NWYAZCRE-": {
|
||||
"title": "RAG Usecases",
|
||||
@@ -1382,7 +1436,7 @@
|
||||
},
|
||||
"WZVW8FQu6LyspSKm1C_sl": {
|
||||
"title": "Using SDKs Directly",
|
||||
"description": "While tools like Langchain and LlamaIndex make it easy to implement RAG, you don't have to necessarily learn and use them. If you know about the different steps of implementing RAG you can simply do it all yourself e.g. do the chunking using @langchain/textsplitters package, create embeddings using any LLM e.g. use OpenAI Embedding API through their SDK, save the embeddings to any vector database e.g. if you are using Supabase Vector DB, you can use their SDK and similarly you can use the relevant SDKs for the rest of the steps as well.\n\nLearn more from the following resources:",
|
||||
"description": "While tools like Langchain and LlamaIndex make it easy to implement RAG, you don't have to necessarily learn and use them. If you know about the different steps of implementing RAG you can simply do it all yourself e.g. do the chunking using `@langchain/textsplitters` package, create embeddings using any LLM e.g. use OpenAI Embedding API through their SDK, save the embeddings to any vector database e.g. if you are using Supabase Vector DB, you can use their SDK and similarly you can use the relevant SDKs for the rest of the steps as well.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Langchain Text Splitter Package",
|
||||
@@ -1406,7 +1460,7 @@
|
||||
"description": "LangChain is a development framework that simplifies building applications powered by language models, enabling seamless integration of multiple AI models and data sources. It focuses on creating chains, or sequences, of operations where language models can interact with databases, APIs, and other models to perform complex tasks. LangChain offers tools for prompt management, data retrieval, and workflow orchestration, making it easier to develop robust, scalable applications like chatbots, automated data analysis, and multi-step reasoning systems.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "LangChain Website",
|
||||
"title": "LangChain",
|
||||
"url": "https://www.langchain.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1422,7 +1476,7 @@
|
||||
"description": "LlamaIndex, formerly known as GPT Index, is a tool designed to facilitate the integration of large language models (LLMs) with structured and unstructured data sources. It acts as a data framework that helps developers build retrieval-augmented generation (RAG) applications by indexing various types of data, such as documents, databases, and APIs, enabling LLMs to query and retrieve relevant information efficiently.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "llamaindex Website",
|
||||
"title": "Llama Index",
|
||||
"url": "https://docs.llamaindex.ai/en/stable/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1525,7 +1579,7 @@
|
||||
},
|
||||
"6xaRB34_g0HGt-y1dGYXR": {
|
||||
"title": "Manual Implementation",
|
||||
"description": "Services like [Open AI functions](https://platform.openai.com/docs/guides/function-calling) and Tools or [Vercel's AI SDK](https://sdk.vercel.ai/docs/foundations/tools) make it really easy to make SDK agents however it is a good idea to learn how these tools work under the hood. You can also create fully custom implementation of agents using by implementing custom loop.\n\nLearn more from the following resources:",
|
||||
"description": "Services like Open AI functions and Tools or Vercel's AI SDK make it really easy to make SDK agents however it is a good idea to learn how these tools work under the hood. You can also create fully custom implementation of agents using by implementing custom loop.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "OpenAI Function Calling",
|
||||
@@ -1637,8 +1691,19 @@
|
||||
},
|
||||
"TxaZCtTCTUfwCxAJ2pmND": {
|
||||
"title": "Video Understanding",
|
||||
"description": "Video understanding with multimodal AI involves analyzing and interpreting both visual and audio content to provide a more comprehensive understanding of videos. Common use cases include video summarization, where AI extracts key scenes and generates summaries; content moderation, where the system detects inappropriate visuals or audio; and video indexing for easier search and retrieval of specific moments within a video. Other applications include enhancing video-based recommendations, security surveillance, and interactive entertainment, where video and audio are processed together for real-time user interaction.",
|
||||
"links": []
|
||||
"description": "Video understanding with multimodal AI involves analyzing and interpreting both visual and audio content to provide a more comprehensive understanding of videos. Common use cases include video summarization, where AI extracts key scenes and generates summaries; content moderation, where the system detects inappropriate visuals or audio; and video indexing for easier search and retrieval of specific moments within a video. Other applications include enhancing video-based recommendations, security surveillance, and interactive entertainment, where video and audio are processed together for real-time user interaction.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Awesome LLM for Video Understanding",
|
||||
"url": "https://github.com/yunlong10/Awesome-LLMs-for-Video-Understanding",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Video Understanding",
|
||||
"url": "https://dl.acm.org/doi/10.1145/3503161.3551600",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mxQYB820447DC6kogyZIL": {
|
||||
"title": "Audio Processing",
|
||||
@@ -1677,17 +1742,17 @@
|
||||
"description": "In the context of multimodal AI, speech-to-text technology converts spoken language into written text, enabling seamless integration with other data types like images and text. This allows AI systems to process audio input and combine it with visual or textual information, enhancing applications such as virtual assistants, interactive chatbots, and multimedia content analysis. For example, a multimodal AI can transcribe a video’s audio while simultaneously analyzing on-screen visuals and text, providing richer and more context-aware insights.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is speech to text? Amazon",
|
||||
"title": "What is Speech to Text?",
|
||||
"url": "https://aws.amazon.com/what-is/speech-to-text/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Turn speech into text using Google AI",
|
||||
"title": "Turn Speech into Text using Google AI",
|
||||
"url": "https://cloud.google.com/speech-to-text",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How is Speech to Text Used? ",
|
||||
"title": "How is Speech to Text Used?",
|
||||
"url": "https://h2o.ai/wiki/speech-to-text/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1778,7 +1843,7 @@
|
||||
"description": "LlamaIndex enables multi-modal apps by linking language models (LLMs) to diverse data sources, including text and images. It indexes and retrieves information across formats, allowing LLMs to process and integrate data from multiple modalities. This supports applications like visual question answering, content summarization, and interactive systems by providing structured, context-aware inputs from various content types.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "LlamaIndex Multy-modal",
|
||||
"title": "LlamaIndex Multi-modal",
|
||||
"url": "https://docs.llamaindex.ai/en/stable/use_cases/multimodal/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1791,7 +1856,7 @@
|
||||
},
|
||||
"NYge7PNtfI-y6QWefXJ4d": {
|
||||
"title": "Development Tools",
|
||||
"description": "AI has given rise to a collection of AI powered development tools of various different varieties. We have IDEs like Cursor that has AI baked into it, live context capturing tools such as Pieces and a variety of brower based tools like V0, Claude and more.",
|
||||
"description": "AI has given rise to a collection of AI powered development tools of various different varieties. We have IDEs like Cursor that has AI baked into it, live context capturing tools such as Pieces and a variety of brower based tools like V0, Claude and more.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "v0 Website",
|
||||
@@ -1809,7 +1874,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Pieces Website",
|
||||
"title": "Pieces",
|
||||
"url": "https://pieces.app",
|
||||
"type": "article"
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@
|
||||
},
|
||||
"U8iMGGOd2EgPxSuwSG39Z": {
|
||||
"title": "Linear",
|
||||
"description": "**LinearLayout** is a view group that aligns all children in a single directioni, vertically or horizontally. You can specify the layout direction with the `android:orientation` attribute.\n\n**LinearLayout** was commonly used in earlier Android development, but with the introduction of ConstraintLayout, it’s less frequently used in modern apps.\n\nVisit the following resources to learn more:",
|
||||
"description": "**LinearLayout** is a view group that aligns all children in a single direction, vertically or horizontally. You can specify the layout direction with the `android:orientation` attribute.\n\n**LinearLayout** was commonly used in earlier Android development, but with the introduction of ConstraintLayout, it’s less frequently used in modern apps.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Linear Layout",
|
||||
@@ -792,6 +792,11 @@
|
||||
"title": "Observer Pattern",
|
||||
"url": "https://en.wikipedia.org/wiki/Observer_pattern",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Observer Pattern",
|
||||
"url": "https://refactoring.guru/design-patterns/observer",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
},
|
||||
"hpShWwL0M57ZAzqkB4I8t": {
|
||||
"title": "Angular and History",
|
||||
"description": "Angular is a web framework that empowers developers to build fast, reliable applications.\n\nMaintained by a dedicated team at Google, Angular provides a broad suite of tools, APIs, and libraries to simplify and streamline your development workflow. Angular gives you a solid platform on which to build fast, reliable applications that scale with both the size of your team and the size of your codebase.\n\nVisit the following resources to learn more:",
|
||||
"description": "Angular is a TypeScript-based open-source front-end web framework developed and maintained by Google.\n\nIt is used for building dynamic, single-page web applications (SPAs). Angular provides comprehensive tools, including dependency injection, data binding, routing, and testing, to create robust and scalable web applications.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is Angular?",
|
||||
|
||||
@@ -709,7 +709,7 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "API Authorization Methods",
|
||||
"url": "https://konghq.com/blog/engineering/common-api-authentication-methods",
|
||||
"url": "https://www.pingidentity.com/en/resources/identity-fundamentals/authorization/authorization-methods.html",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -1540,9 +1540,35 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"grpc-apis@1DrqtOwxCuFtWQXQ6ZALp.md": {
|
||||
"1DrqtOwxCuFtWQXQ6ZALp": {
|
||||
"title": "gRPC APIs",
|
||||
"description": "",
|
||||
"links": []
|
||||
"description": "gRPC is a platform agnostic serialization protocol that is used to communicate between services. Designed by Google in 2015, it is a modern alternative to REST APIs. It is a binary protocol that uses HTTP/2 as a transport layer. It is a high performance, open source, general-purpose RPC framework that puts mobile and HTTP/2 first. It's main use case is for communication between two different languages within the same application. You can use Python to communicate with Go, or Java to communicate with C#.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "gRPC Website",
|
||||
"url": "https://grpc.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "gRPC Introduction",
|
||||
"url": "https://grpc.io/docs/what-is-grpc/introduction/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "gRPC Core Concepts",
|
||||
"url": "https://grpc.io/docs/what-is-grpc/core-concepts/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about gRPC",
|
||||
"url": "https://app.daily.dev/tags/grpc?ref=roadmapsh",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Stephane Maarek - gRPC Introduction",
|
||||
"url": "https://youtu.be/XRXTsQwyZSU",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,11 @@
|
||||
"title": "Rust",
|
||||
"description": "Rust is a systems programming language known for its focus on safety, performance, and concurrency. It provides fine-grained control over system resources while ensuring memory safety without needing a garbage collector. Rust's ownership model enforces strict rules on how data is accessed and managed, preventing common issues like null pointer dereferences and data races. Its strong type system and modern features, such as pattern matching and concurrency support, make it suitable for a wide range of applications, from low-level systems programming to high-performance web servers and tools. Rust is gaining traction in both industry and open source for its reliability and efficiency.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Visit Dedicated Rust Roadmap",
|
||||
"url": "https://roadmap.sh/rust",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The Rust Programming Language - Book",
|
||||
"url": "https://doc.rust-lang.org/book/",
|
||||
@@ -119,7 +124,12 @@
|
||||
"description": "PHP (Hypertext Preprocessor) is a widely-used, open-source scripting language designed primarily for web development but also applicable for general-purpose programming. It is embedded within HTML to create dynamic web pages and interact with databases, often working with MySQL or other database systems. PHP is known for its simplicity, ease of integration with various web servers, and extensive support for web-related functionalities. Its wide adoption is driven by its role in powering major platforms and content management systems like WordPress, Joomla, and Drupal. PHP's features include server-side scripting, session management, and support for various web protocols and formats.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PHP Website",
|
||||
"title": "Visit Dedicated PHP Roadmap",
|
||||
"url": "https://roadmap.sh/php",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PHP",
|
||||
"url": "https://php.net/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -196,7 +206,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Build 30 Javascript projects in 30 days",
|
||||
"title": "Build 30 Javascript Projects in 30 days",
|
||||
"url": "https://javascript30.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -288,6 +298,11 @@
|
||||
"url": "https://docs.microsoft.com/en-us/learn/paths/csharp-first-steps/?WT.mc_id=dotnet-35129-website",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "C# Tour",
|
||||
"url": "https://learn.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "C# on W3 schools",
|
||||
"url": "https://www.w3schools.com/cs/index.php",
|
||||
@@ -338,7 +353,7 @@
|
||||
},
|
||||
"2f0ZO6GJElfZ2Eis28Hzg": {
|
||||
"title": "Pick a Language",
|
||||
"description": "Even if you’re a beginner the least you would have known is that Web Development is majorly classified into two facets: Frontend Development and Backend Development. And obviously, they both have their respective set of tools and technologies. For instance, when we talk about Frontend Development, there always comes 3 names first and foremost – HTML, CSS, and JavaScript. In the same way, when it comes to Backend Web Development – we primarily require a backend (or you can say server-side) programming language to make the website function along with various other tools & technologies such as databases, frameworks, web servers, etc.",
|
||||
"description": "Even if you’re a beginner, the first thing you’ll learn is that web development is primarily divided into two aspects: Frontend Development and Backend Development, each with its unique tools and technologies. For Frontend Development, foundational technologies include HTML, CSS, and JavaScript. Similarly, Backend Development revolves around server-side programming languages like Python, Java, or Node.js, complemented by databases, frameworks, and web servers that enable website functionality.",
|
||||
"links": []
|
||||
},
|
||||
"_I1E__wCIVrhjMk6IMieE": {
|
||||
@@ -346,7 +361,7 @@
|
||||
"description": "Git is a distributed version control system designed to handle projects of any size with speed and efficiency. Created by Linus Torvalds in 2005, it tracks changes in source code during software development, allowing multiple developers to work together on non-linear development. Git maintains a complete history of all changes, enabling easy rollbacks and comparisons between versions. Its distributed nature means each developer has a full copy of the repository, allowing for offline work and backup. Git's key features include branching and merging capabilities, staging area for commits, and support for collaborative workflows like pull requests. Its speed, flexibility, and robust branching and merging capabilities have made it the most widely used version control system in software development, particularly for open-source projects and team collaborations.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Learn Git & GitHub",
|
||||
"title": "Visit Dedicated Git & GitHub Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -382,7 +397,7 @@
|
||||
"description": "Version Control Systems (VCS) are tools that manage and track changes to code or documents over time, allowing multiple users to collaborate on a project efficiently. They record every change made to files, enabling developers to revert to previous versions, compare changes, and maintain a history of modifications. VCS can be centralized, where the repository is hosted on a central server (e.g., Subversion), or distributed, where each user has a complete copy of the repository (e.g., Git, Mercurial). Version control facilitates collaboration, enhances code integrity, and supports continuous integration by enabling smooth management of concurrent changes and resolving conflicts.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Learn Git & GitHub",
|
||||
"title": "Visit Dedicated Git & GitHub Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -408,7 +423,7 @@
|
||||
"description": "GitHub is a web-based platform for version control and collaboration using Git. Owned by Microsoft, it provides hosting for software development and offers features beyond basic Git functionality. GitHub includes tools for project management, code review, and social coding. Key features include repositories for storing code, pull requests for proposing and reviewing changes, issues for tracking bugs and tasks, and actions for automating workflows. It supports both public and private repositories, making it popular for open-source projects and private development. GitHub's collaborative features, like forking repositories and inline code comments, facilitate team development and community contributions. With its extensive integrations and large user base, GitHub has become a central hub for developers, serving as a portfolio, collaboration platform, and deployment tool for software projects of all sizes.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Learn Git & GitHub",
|
||||
"title": "Visit Dedicated Git & GitHub Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -417,6 +432,11 @@
|
||||
"url": "https://github.com",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Documentation",
|
||||
"url": "https://docs.github.com",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about GitHub",
|
||||
"url": "https://app.daily.dev/tags/github?ref=roadmapsh",
|
||||
@@ -444,10 +464,15 @@
|
||||
"description": "Bitbucket is a web-based version control repository hosting service owned by Atlassian. It primarily uses Git version control systems, offering both cloud-hosted and self-hosted options. Bitbucket provides features such as pull requests for code review, branch permissions, and inline commenting on code. It integrates seamlessly with other Atlassian products like Jira and Trello, making it popular among teams already using Atlassian tools. Bitbucket supports continuous integration and deployment through Bitbucket Pipelines. It offers unlimited private repositories for small teams, making it cost-effective for smaller organizations.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Bitbucket Website",
|
||||
"title": "Bitbucket",
|
||||
"url": "https://bitbucket.org/product",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Overview of Bitbucket",
|
||||
"url": "https://bitbucket.org/product/guides/getting-started/overview#a-brief-overview-of-bitbucket",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Using Git with Bitbucket Cloud",
|
||||
"url": "https://www.atlassian.com/git/tutorials/learn-git-with-bitbucket-cloud",
|
||||
@@ -509,11 +534,6 @@
|
||||
"title": "BitBucket",
|
||||
"url": "https://bitbucket.org/product/guides/getting-started/overview",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to choose the best source code repository",
|
||||
"url": "https://blockandcapital.com/en/choose-code-repository/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -558,7 +578,7 @@
|
||||
"description": "Microsoft SQL Server (MS SQL) is a relational database management system developed by Microsoft for managing and storing structured data. It supports a wide range of data operations, including querying, transaction management, and data warehousing. SQL Server provides tools and features for database design, performance optimization, and security, including support for complex queries through T-SQL (Transact-SQL), data integration with SQL Server Integration Services (SSIS), and business intelligence with SQL Server Analysis Services (SSAS) and SQL Server Reporting Services (SSRS). It is commonly used in enterprise environments for applications requiring reliable data storage, transaction processing, and reporting.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "SQL Roadmap",
|
||||
"title": "Visit Dedicated SQL Roadmap",
|
||||
"url": "https://roadmap.sh/sql",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -609,7 +629,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "MySQL Full Course for free",
|
||||
"title": "MySQL Complete Course",
|
||||
"url": "https://www.youtube.com/watch?v=5OdVJbNCSso",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -983,8 +1003,19 @@
|
||||
},
|
||||
"95d9itpUZ4s9roZN8kG9x": {
|
||||
"title": "Scaling Databases",
|
||||
"description": "Scaling databases is the process of adapting them to handle more data and users efficiently. It's achieved by either upgrading existing hardware (vertical scaling) or adding more servers (horizontal scaling). Techniques like sharding and replication are key. This ensures databases continue to be a robust asset as they grow.",
|
||||
"links": []
|
||||
"description": "Scaling databases is the process of adapting them to handle more data and users efficiently. It's achieved by either upgrading existing hardware (vertical scaling) or adding more servers (horizontal scaling). Techniques like sharding and replication are key. This ensures databases continue to be a robust asset as they grow.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Strategies for Scaling Databases: A Comprehensive Guide",
|
||||
"url": "https://medium.com/@anil.goyal0057/strategies-for-scaling-databases-a-comprehensive-guide-b69cda7df1d3",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Horizontal vs. Vertical Scaling - How to Scale a Database",
|
||||
"url": "https://www.freecodecamp.org/news/horizontal-vs-vertical-scaling-in-database/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dLY0KafPstajCcSbslC4M": {
|
||||
"title": "HATEOAS",
|
||||
@@ -1127,7 +1158,7 @@
|
||||
"description": "GraphQL is a query language for APIs and a runtime for executing those queries, developed by Facebook. Unlike REST, where fixed endpoints return predefined data, GraphQL allows clients to request exactly the data they need, making API interactions more flexible and efficient. It uses a single endpoint and relies on a schema that defines the types and structure of the available data. This approach reduces over-fetching and under-fetching of data, making it ideal for complex applications with diverse data needs across multiple platforms (e.g., web, mobile).\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "GraphQL Roadmap",
|
||||
"title": "Visit Dedicated GraphQL Roadmap",
|
||||
"url": "https://roadmap.sh/graphql",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1310,7 +1341,7 @@
|
||||
"description": "Unit testing is a software testing method where individual components or units of a program are tested in isolation to ensure they function correctly. This approach focuses on verifying the smallest testable parts of an application, such as functions or methods, by executing them with predefined inputs and comparing the results to expected outcomes. Unit tests are typically automated and written by developers during the coding phase to catch bugs early, facilitate code refactoring, and ensure that each unit of code performs as intended. By isolating and testing each component, unit testing helps improve code reliability and maintainability.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Unit testing",
|
||||
"title": "Unit Testing",
|
||||
"url": "https://en.wikipedia.org/wiki/Unit_testing",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1397,6 +1428,11 @@
|
||||
"url": "https://www.digitalocean.com/community/tutorials/gangs-of-four-gof-design-patterns",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Design Patterns for Humans",
|
||||
"url": "https://github.com/kamranahmedse/design-patterns-for-humans",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Tutorial - Builder Pattern (Gang of Four Design Patterns Series)",
|
||||
"url": "https://www.youtube.com/watch?v=_sa2WlAFWQos",
|
||||
@@ -1727,7 +1763,7 @@
|
||||
"description": "Message brokers are intermediaries that facilitate communication between distributed systems or components by receiving, routing, and delivering messages. They enable asynchronous message passing, decoupling producers (senders) from consumers (receivers), which improves scalability and flexibility. Common functions of message brokers include message queuing, load balancing, and ensuring reliable message delivery through features like persistence and acknowledgment. Popular message brokers include Apache Kafka, RabbitMQ, and ActiveMQ, each offering different features and capabilities suited to various use cases like real-time data processing, event streaming, or task management.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What are message brokers?",
|
||||
"title": "What are Message Brokers?",
|
||||
"url": "https://www.ibm.com/topics/message-brokers",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1795,13 +1831,13 @@
|
||||
"description": "WebSockets provide a protocol for full-duplex, real-time communication between a client (usually a web browser) and a server over a single, long-lived connection. Unlike traditional HTTP, which requires multiple request-response cycles to exchange data, WebSockets establish a persistent connection that allows for continuous data exchange in both directions. This enables efficient real-time interactions, such as live chat, online gaming, and real-time updates on web pages. WebSocket connections start with an HTTP handshake, then upgrade to a WebSocket protocol, facilitating low-latency communication and reducing overhead compared to HTTP polling or long polling.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Introduction to WebSockets",
|
||||
"url": "https://www.tutorialspoint.com/websockets/index.htm",
|
||||
"title": "Socket.io Library Bidirectional and Low-latency Communication for Every Platform",
|
||||
"url": "https://socket.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Socket.io Library Bidirectional and low-latency communication for every platform",
|
||||
"url": "https://socket.io/",
|
||||
"title": "Introduction to WebSockets",
|
||||
"url": "https://www.tutorialspoint.com/websockets/index.htm",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -1868,7 +1904,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Caddy Server",
|
||||
"url": "https://caddyserver.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1884,10 +1920,15 @@
|
||||
"description": "Apache, officially known as the Apache HTTP Server, is a free, open-source web server software developed and maintained by the Apache Software Foundation. It's one of the most popular web servers worldwide, known for its robustness, flexibility, and extensive feature set. Apache supports a wide range of operating systems and can handle various content types and programming languages through its modular architecture. It offers features like virtual hosting, SSL/TLS support, and URL rewriting. Apache's configuration files allow for detailed customization of server behavior. While it has faced competition from newer alternatives like Nginx, especially in high-concurrency scenarios, Apache remains widely used due to its stability, comprehensive documentation, and large community support. It's particularly favored for its ability to integrate with other open-source technologies in the LAMP (Linux, Apache, MySQL, PHP/Perl/Python) stack.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Apache Server Website",
|
||||
"title": "Apache Server",
|
||||
"url": "https://httpd.apache.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Apache Server Documentation",
|
||||
"url": "https://httpd.apache.org/docs/2.4/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about Apache",
|
||||
"url": "https://app.daily.dev/tags/apache?ref=roadmapsh",
|
||||
@@ -1978,10 +2019,20 @@
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Redis Website",
|
||||
"title": "Visit Dedicated Redis Roadmap",
|
||||
"url": "https://roadmap.sh/redis",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Redis",
|
||||
"url": "https://redis.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Redis Documentation",
|
||||
"url": "https://redis.io/docs/latest/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about Redis",
|
||||
"url": "https://app.daily.dev/tags/redis?ref=roadmapsh",
|
||||
@@ -2051,10 +2102,15 @@
|
||||
"description": "Apache CouchDB is an open-source document-oriented NoSQL database. It uses JSON to store data, JavaScript as its query language using MapReduce, and HTTP for an API. Unlike a relational database, a CouchDB database does not store data and relationships in tables. Instead, each database is a collection of independent documents. Each document maintains its own data and self-contained schema.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "CouchDB Website",
|
||||
"title": "CouchDB",
|
||||
"url": "https://couchdb.apache.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "CouchDB Documentation",
|
||||
"url": "https://docs.couchdb.org/en/stable/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about CouchDB",
|
||||
"url": "https://app.daily.dev/tags/couchdb?ref=roadmapsh",
|
||||
@@ -2160,6 +2216,11 @@
|
||||
"title": "Loadshifting",
|
||||
"description": "Load shifting is a strategy used to manage and distribute computing or system workloads more efficiently by moving or redistributing the load from peak times to off-peak periods. This approach helps in balancing the demand on resources, optimizing performance, and reducing costs. In cloud computing and data centers, load shifting can involve rescheduling jobs, leveraging different regions or availability zones, or adjusting resource allocation based on real-time demand. By smoothing out peak loads, organizations can enhance system reliability, minimize latency, and better utilize their infrastructure.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Load Shifting",
|
||||
"url": "https://en.wikipedia.org/wiki/Load_shifting",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Load Shifting 101",
|
||||
"url": "https://www.youtube.com/watch?v=DOyMJEdk5aE",
|
||||
@@ -2231,7 +2292,7 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "What is Instrumentation?",
|
||||
"url": "https://en.wikipedia.org/wiki/Instrumentation_(computer_programming)",
|
||||
"url": "https://en.wikipedia.org/wiki/Instrumentation_/(computer_programming/)",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -2353,6 +2414,11 @@
|
||||
"title": "sCrypt: A Beginner’s Guide",
|
||||
"url": "https://medium.com/@yusufedresmaina/scrypt-a-beginners-guide-cf1aecf8b010",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Wikipedia - scrypt",
|
||||
"url": "https://en.wikipedia.org/wiki/Scrypt",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -2574,7 +2640,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "An overview of HTTP",
|
||||
"title": "Overview of HTTP",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2626,7 +2692,7 @@
|
||||
"description": "Hosting refers to the service of providing server space and resources for storing and delivering website files and applications to users over the internet. Hosting providers offer the infrastructure, such as servers, storage, and network connectivity, required to make websites and applications accessible online. There are various types of hosting, including shared hosting (where multiple websites share a single server), virtual private servers (VPS), dedicated hosting (where a single server is dedicated to one user), and cloud hosting (which uses a network of servers to provide scalable resources). Hosting services often include domain registration, security features, and technical support to ensure websites are reliably available and perform well.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is the difference between webpage, website, web server, and search engine?",
|
||||
"title": "What is the difference between Webpage, Website, Web server, and search engine?",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Web_mechanics/Pages_sites_servers_and_search_engines",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2801,6 +2867,11 @@
|
||||
"title": "Token Authentication",
|
||||
"description": "Token-based authentication is a protocol which allows users to verify their identity, and in return receive a unique access token. During the life of the token, users then access the website or app that the token has been issued for, rather than having to re-enter credentials each time they go back to the same webpage, app, or any resource protected with that same token. Auth tokens work like a stamped ticket. The user retains access as long as the token remains valid. Once the user logs out or quits an app, the token is invalidated. Token-based authentication is different from traditional password-based or server-based authentication techniques. Tokens offer a second layer of security, and administrators have detailed control over each action and transaction.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Token Based Authentication",
|
||||
"url": "https://roadmap.sh/guides/token-authentication",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What Is Token-Based Authentication?",
|
||||
"url": "https://www.okta.com/identity-101/what-is-token-based-authentication/",
|
||||
@@ -3017,10 +3088,20 @@
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Redis Website",
|
||||
"title": "Visit Dedicated Redis Roadmap",
|
||||
"url": "https://roadmap.sh/redis",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Redis",
|
||||
"url": "https://redis.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Redis Documentation",
|
||||
"url": "https://redis.io/docs/latest/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about Redis",
|
||||
"url": "https://app.daily.dev/tags/redis?ref=roadmapsh",
|
||||
@@ -3064,10 +3145,15 @@
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Firebase Website",
|
||||
"title": "Firebase",
|
||||
"url": "https://firebase.google.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Firebase Documentation",
|
||||
"url": "https://firebase.google.com/docs",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Firebase in 100 seconds",
|
||||
"url": "https://www.youtube.com/watch?v=vAoB4VbhRzM",
|
||||
@@ -3195,7 +3281,7 @@
|
||||
"description": "Oracle Base Database Service enables you to maintain absolute control over your data while using the combined capabilities of Oracle Database and Oracle Cloud Infrastructure. Oracle Base Database Service offers database systems (DB systems) on virtual machines. They are available as single-node DB systems and multi-node RAC DB systems on Oracle Cloud Infrastructure (OCI). You can manage these DB systems by using the OCI Console, the OCI API, the OCI CLI, the Database CLI (DBCLI), Enterprise Manager, or SQL Developer.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Base Database Website",
|
||||
"title": "Base Database Documentation",
|
||||
"url": "https://docs.oracle.com/en-us/iaas/base-database/index.html",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -3206,7 +3292,7 @@
|
||||
"description": "Amazon Neptune is a fully managed graph database service provided by Amazon Web Services (AWS). It's designed to store and navigate highly connected data, supporting both property graph and RDF (Resource Description Framework) models. Neptune uses graph query languages like Gremlin and SPARQL, making it suitable for applications involving complex relationships, such as social networks, recommendation engines, fraud detection systems, and knowledge graphs. It offers high availability, with replication across multiple Availability Zones, and supports up to 15 read replicas for improved performance. Neptune integrates with other AWS services, provides encryption at rest and in transit, and offers fast recovery from failures. Its scalability and performance make it valuable for handling large-scale, complex data relationships in enterprise-level applications.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "AWS Neptune Website",
|
||||
"title": "AWS Neptune",
|
||||
"url": "https://aws.amazon.com/neptune/",
|
||||
"type": "article"
|
||||
},
|
||||
|
||||
@@ -826,13 +826,13 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "CS 61B Lecture 19: Asymptotic Analysis",
|
||||
"url": "https://archive.org/details/ucberkeley_webcast_VIS4YDpuP98",
|
||||
"title": "Big-O Cheat Sheet",
|
||||
"url": "https://www.bigocheatsheet.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Big-O Cheat Sheet",
|
||||
"url": "https://www.bigocheatsheet.com/",
|
||||
"title": "Big O Notation | Brilliant Math & Science Wiki",
|
||||
"url": "https://brilliant.org/wiki/big-o-notation/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -849,18 +849,28 @@
|
||||
"title": "Asymptotic Notation - CS50",
|
||||
"url": "https://www.youtube.com/watch?v=iOq5kSKqeR4",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "CS 61B Lecture 19: Asymptotic Analysis",
|
||||
"url": "https://archive.org/details/ucberkeley_webcast_VIS4YDpuP98",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
"c-NrTtJuNihbHzyPEOKTW": {
|
||||
"title": "Big O",
|
||||
"description": "Big O Notation describes, how well an algorithm scales with the input size. It is used to describe the worst case scenario of an algorithm. It is used to compare algorithms and to determine which algorithm is better.\n\nVisit the following resources to learn more:",
|
||||
"description": "The Big O notation can be used to describe how the running time of an algorithm scales with the growth of the input size, ignoring implementation details such as programming language and computer speed. Specifically, it denotes the upper bound of the growth rate of a function that relates the running time of an algorithm to its input size. It can be used to compare algorithms and determine which one is better.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "moviesCS 61B Lecture 19: Asymptotic Analysis",
|
||||
"url": "https://archive.org/details/ucberkeley_webcast_VIS4YDpuP98",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Big O Notation | Brilliant Math & Science Wiki",
|
||||
"url": "https://brilliant.org/wiki/big-o-notation/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Big O Notation — Calculating Time Complexity",
|
||||
"url": "https://www.youtube.com/watch?v=Z0bH0cMY0E8",
|
||||
@@ -880,8 +890,13 @@
|
||||
},
|
||||
"ThLpVZQIJ4diY5m0dik8m": {
|
||||
"title": "Big-Theta",
|
||||
"description": "While Big O Notation refers to the upper bound of a function, Big Theta Notation refers to the exact bound of a function. Big Theta Notation is used to describe the exact growth rate of a function. It is denoted by the symbol Θ.\n\nVisit the following resources to learn more:",
|
||||
"description": "If a function has the same Big O and Big Omega, they also become the function's Big Theta. Big Theta is used to describe the exact growth rate of a function. It is denoted by the symbol Θ.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Big O Notation | Brilliant Math & Science Wiki",
|
||||
"url": "https://brilliant.org/wiki/big-o-notation/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Big Oh Notation (and Omega and Theta)",
|
||||
"url": "https://www.youtube.com/watch?v=ei-A_wy5Yxw&list=PL1BaGV1cIH4UhkL8a9bJGG356covJ76qN&index=3",
|
||||
@@ -896,8 +911,13 @@
|
||||
},
|
||||
"X33735aeAVSlJ6yv9GS-h": {
|
||||
"title": "Big Omega",
|
||||
"description": "Big Omega notation is used to describe the lower bound of a function. It is the opposite of Big O notation. While Big O is used to describe the worst case scenario of an algorithm, Big Omega is used to describe the best case scenario of an algorithm.\n\nVisit the following resources to learn more:",
|
||||
"description": "The Big Omega notation is similar to the Big O notation. The only difference is that it denotes the lower bound on the growth rate of a function.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Big O Notation | Brilliant Math & Science Wiki",
|
||||
"url": "https://brilliant.org/wiki/big-o-notation/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Big Oh Notation (and Omega and Theta)",
|
||||
"url": "https://www.youtube.com/watch?v=ei-A_wy5Yxw&list=PL1BaGV1cIH4UhkL8a9bJGG356covJ76qN&index=3",
|
||||
@@ -1832,8 +1852,18 @@
|
||||
},
|
||||
"vjMqqFsTxSjaiYxmliwLi": {
|
||||
"title": "Endianess",
|
||||
"description": "Endianess is the order in which bytes are stored in memory. The two most common types of endianess are big endian and little endian. Big endian stores the most significant byte first, while little endian stores the least significant byte first.\n\nVisit the following resources to learn more:",
|
||||
"description": "Endianness is the order in which bytes are stored in memory. The two most common types of endianness are big endian and little endian. Big endian stores the most significant byte first, while little endian stores the least significant byte first.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Endianness",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Glossary/Endianness",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Big-Endian vs Little-Endian Explained with Examples",
|
||||
"url": "https://www.freecodecamp.org/news/what-is-endianness-big-endian-vs-little-endian/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Big Endian vs Little Endian.mp4",
|
||||
"url": "https://www.youtube.com/watch?v=JrNF0KRAlyo",
|
||||
@@ -2638,7 +2668,7 @@
|
||||
},
|
||||
"0btHNkzWL1w_-pUgU_k2y": {
|
||||
"title": "P = NP",
|
||||
"description": "The P = NP problem is one of the most famous problems in computer science. It asks if the problem of determining if a given input belongs to a certain class of problems is as hard as the problem of solving the given input. In other words, it asks if the problem of determining if a given input belongs to a certain class of problems is as hard as the problem of determining if a given input belongs to a certain class of problems. This problem is also known as the Halting Problem.\n\nVisit the following resources to learn more:",
|
||||
"description": "The P = NP problem is one of the most famous problems in computer science. It asks whether a problem that can be solved in polynomial time on a non-deterministic machine (i.e., the problem is in NP) can also be solved in polynomial time on a deterministic machine (i.e., the problem is in P).\n\nIf you can find a polynomial-time solution to an NP-complete problem, then all problems in NP can be solved in polynomial time. This shows that P = NP.\n\nIf you can prove for any single NP-complete problem that it is only solvable in exponential time, then all NP-complete problems are only solvable in exponential time. This shows that P ≠ NP.\n\nSo far, we don't know whether P = NP or P ≠ NP.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Whats P=NP?, and why is it such a famous question?",
|
||||
@@ -3336,8 +3366,19 @@
|
||||
},
|
||||
"tcQSH-eAvJUZuePTDjAIb": {
|
||||
"title": "DML",
|
||||
"description": "The SQL commands that deals with the manipulation of data present in the database belong to DML or Data Manipulation Language and this includes most of the SQL statements. It is the component of the SQL statement that controls access to data and to the database. Basically, DCL statements are grouped with DML statements.\n\nVisit the following resources to learn more:",
|
||||
"links": []
|
||||
"description": "The SQL commands that manipulate data in the database belong to DML, or Data Manipulation Language, and this includes most of the SQL statements. DCL is the component of the SQL statement that controls access to data and to the database. Basically, DCL statements are grouped with DML statements.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "DML: Data Manipulation Language",
|
||||
"url": "https://satoricyber.com/glossary/dml-data-manipulation-language",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Difference Between DDL and DML",
|
||||
"url": "https://appmaster.io/blog/difference-between-ddl-and-dml",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"05lkb3B86Won7Rkf-8DeD": {
|
||||
"title": "DQL",
|
||||
@@ -3901,7 +3942,7 @@
|
||||
},
|
||||
"GDLKJkKgB-i7n0YcV2NDa": {
|
||||
"title": "How Computers Calculate",
|
||||
"description": "Visit the following resources to learn more:",
|
||||
"description": "Computers calculate using the binary system, where all data is represented as 0s and 1s. These binary states correspond to the ON/OFF positions of transistors, which are the building blocks of logic gates (AND, OR, NOT). Numbers, characters, and instructions are broken into binary sequences (bits), and grouped into bytes (8 bits). Arithmetic operations like addition are performed through logic gates, which combine binary values. The CPU executes these calculations by following a fetch-decode-execute cycle. Complex calculations, such as handling decimals, use floating-point representation. Programs written in high-level languages are compiled into machine code for the CPU to execute.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How computers calculate - ALU",
|
||||
|
||||
@@ -406,7 +406,7 @@
|
||||
},
|
||||
"s86x24SHPEbbOB9lYNU-w": {
|
||||
"title": "CISM",
|
||||
"description": "The Certified Information Security Manager (CISM) is an advanced cybersecurity certification offered by ISACA that focuses on information security management. It is designed for professionals who have a strong understanding of information security and are responsible for overseeing, designing, and managing an organization's information security programs.\n\nCommon ports are standardized communication endpoints used by various network protocols and services. In cybersecurity, understanding these ports is crucial for configuring firewalls, detecting potential threats, and managing network traffic. Some widely used ports include 80 and 443 for HTTP and HTTPS web traffic, 22 for SSH secure remote access, 25 for SMTP email transmission, and 53 for DNS name resolution. FTP typically uses port 21 for control and 20 for data transfer, while ports 137-139 and 445 are associated with SMB file sharing. Database services often use specific ports, such as 3306 for MySQL and 1433 for Microsoft SQL Server. Cybersecurity professionals must be familiar with these common ports and their expected behaviors to effectively monitor network activities, identify anomalies, and secure systems against potential attacks targeting specific services.\n\nLearn more from the following resources:",
|
||||
"description": "The Certified Information Security Manager (CISM) is an advanced cybersecurity certification offered by ISACA that focuses on information security management. It is designed for professionals who have a strong understanding of information security and are responsible for overseeing, designing, and managing an organization's information security programs.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "CISM Website",
|
||||
@@ -4451,7 +4451,7 @@
|
||||
]
|
||||
},
|
||||
"RJctUpvlUJGAdwBNtDSXw": {
|
||||
"title": "Understand the concept of Infrastructure as Cloud",
|
||||
"title": "Understand the concept of Infrastructure as Code",
|
||||
"description": "Infrastructure as Code (IaC) is a practice of managing and provisioning computing infrastructure through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools. It treats infrastructure configuration as software, allowing it to be version-controlled, tested, and automatically deployed. IaC enables consistent, repeatable environment setups, reduces manual errors, facilitates rapid scaling and disaster recovery, and improves collaboration between development and operations teams. Popular IaC tools include Terraform, AWS CloudFormation, and Ansible, which use declarative or imperative approaches to define infrastructure states. This approach is fundamental to DevOps practices, cloud computing, and the efficient management of complex, dynamic IT environments.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
|
||||
@@ -6,12 +6,18 @@
|
||||
},
|
||||
"yCnn-NfSxIybUQ2iTuUGq": {
|
||||
"title": "What is Data Analytics",
|
||||
"description": "Data Analytics is a core component of a Data Analyst's role. The field involves extracting meaningful insights from raw data to drive decision-making processes. It includes a wide range of techniques and disciplines ranging from the simple data compilation to advanced algorithms and statistical analysis. As a data analyst, you are expected to understand and interpret complex digital data, such as the usage statistics of a website, the sales figures of a company, or client engagement over social media, etc. This knowledge enables data analysts to support businesses in identifying trends, making informed decisions, predicting potential outcomes - hence playing a crucial role in shaping business strategies.",
|
||||
"links": []
|
||||
"description": "Data Analytics is a core component of a Data Analyst's role. The field involves extracting meaningful insights from raw data to drive decision-making processes. It includes a wide range of techniques and disciplines ranging from the simple data compilation to advanced algorithms and statistical analysis. As a data analyst, you are expected to understand and interpret complex digital data, such as the usage statistics of a website, the sales figures of a company, or client engagement over social media, etc. This knowledge enables data analysts to support businesses in identifying trends, making informed decisions, predicting potential outcomes - hence playing a crucial role in shaping business strategies.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Introduction to Data Analytics",
|
||||
"url": "https://www.coursera.org/learn/introduction-to-data-analytics",
|
||||
"type": "course"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Lsapbmg-eMIYJAHpV97nO": {
|
||||
"title": "Types of Data Analytics",
|
||||
"description": "Data Analytics has proven to be a critical part of decision-making in modern business ventures. It is responsible for discovering, interpreting, and transforming data into valuable information. Different types of data analytics look at past, present, or predictive views of business operations.\n\nData Analysts, as ambassadors of this domain, employ these types, to answer various questions:\n\n* Descriptive Analytics _(what happened in the past?)_\n* Diagnostic Analytics _(why did it happened in the past?)_\n* Predictive Analytics _(what will happen in the future?)_\n* Prescriptive Analytics _(how can we make it happen?)_\n\nUnderstanding these types gives data analysts the power to transform raw datasets into strategic insights.\n\nVisit the following resources to learn more:",
|
||||
"description": "Data Analytics has proven to be a critical part of decision-making in modern business ventures. It is responsible for discovering, interpreting, and transforming data into valuable information. Different types of data analytics look at past, present, or predictive views of business operations.\n\nData Analysts, as ambassadors of this domain, employ these types, to answer various questions:\n\n* Descriptive Analytics _(what happened in the past?)_\n* Diagnostic Analytics _(why did it happened in the past?)_\n* Predictive Analytics _(what will happen in the future?)_\n* Prescriptive Analytics _(how can we make it happen?)_\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Data Analytics and its type",
|
||||
@@ -72,12 +78,12 @@
|
||||
"description": "Predictive analysis is a crucial type of data analytics that any competent data analyst should comprehend. It refers to the practice of extracting information from existing data sets in order to determine patterns and forecast future outcomes and trends. Data analysts apply statistical algorithms, machine learning techniques, and artificial intelligence to the data to anticipate future results. Predictive analysis enables organizations to be proactive, forward-thinking, and strategic by providing them valuable insights on future occurrences. It's a powerful tool that gives companies a significant competitive edge by enabling risk management, opportunity identification, and strategic decision-making.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is predictive analytics? - Google",
|
||||
"title": "What is Predictive Analytics? - Google",
|
||||
"url": "https://cloud.google.com/learn/what-is-predictive-analytics",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is predictive analytics?",
|
||||
"title": "What is Predictive Analytics?",
|
||||
"url": "https://www.youtube.com/watch?v=cVibCHRSxB0",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -125,7 +131,7 @@
|
||||
"description": "The Cleanup of Data is a critical component of a Data Analyst's role. It involves the process of inspecting, cleaning, transforming, and modeling data to discover useful information, inform conclusions, and support decision making. This process is crucial for Data Analysts to generate accurate and significant insights from data, ultimately resulting in better and more informed business decisions. A solid understanding of data cleanup procedures and techniques is a fundamental skill for any Data Analyst. Hence, it is necessary to hold a high emphasis on maintaining data quality by managing data integrity, accuracy, and consistency during the data cleanup process.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Top 10 ways to clean your data",
|
||||
"title": "Top 10 Ways to Clean Your Data",
|
||||
"url": "https://support.microsoft.com/en-gb/office/top-ten-ways-to-clean-your-data-2844b620-677c-47a7-ac3e-c2e157d1db19",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -157,7 +163,7 @@
|
||||
"description": "The visualization of data is an essential skill in the toolkit of every data analyst. This practice is about transforming complex raw data into a graphical format that allows for an easier understanding of large data sets, trends, outliers, and important patterns. Whether pie charts, line graphs, bar graphs, or heat maps, data visualization techniques not only streamline data analysis, but also facilitate a more effective communication of the findings to others. This key concept underscores the importance of presenting data in a digestible and visually appealing manner to drive data-informed decision making in an organization.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Data visualization beginner's guide",
|
||||
"title": "Data Visualization Beginner's Guide",
|
||||
"url": "https://www.tableau.com/en-gb/learn/articles/data-visualization",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -200,21 +206,10 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"sgXIjVTbwdwdYoaxN3XBM": {
|
||||
"title": "Analaysis / Reporting with Excel",
|
||||
"description": "Excel is a powerful tool utilized by data analysts worldwide to store, manipulate, and analyze data. It offers a vast array of features such as pivot tables, graphs and a powerful suite of formulas and functions to help sift through large sets of data. A data analyst uses Excel to perform a wide range of tasks, from simple data entry and cleaning, to more complex statistical analysis and predictive modeling. Proficiency in Excel is often a key requirement for a data analyst, as its versatility and ubiquity make it an indispensable tool in the field of data analysis.",
|
||||
"links": [
|
||||
{
|
||||
"title": "Microsoft Excel Course",
|
||||
"url": "https://support.microsoft.com/en-us/office/excel-video-training-9bc05390-e94c-46af-a5b3-d7c22f6990bb",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "W3Schools - Excel",
|
||||
"url": "https://www.w3schools.com/excel/index.php",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
"analysis--reporting-with-excel@sgXIjVTbwdwdYoaxN3XBM.md": {
|
||||
"title": "Analysis / Reporting with Excel",
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"wME4MSldOWlMB54ekpReS": {
|
||||
"title": "IF",
|
||||
@@ -234,7 +229,7 @@
|
||||
},
|
||||
"yBlJrNo9eO470dLp6OaQZ": {
|
||||
"title": "DATEDIF",
|
||||
"description": "The `DATEDIF` function is an incredibly valuable tool for a Data Analyst in Excel or Google Sheets, by providing the ability to calculate the difference between two dates. This function takes in three parameters: start date, end date and the type of difference required (measured in years, months, days, etc.). In Data Analysis, particularly when dealing with time-series data or when you need to uncover trends over specific periods, the `DATEDIF` function is a necessary asset. Recognizing its functionality will enable a data analyst to manipulate or shape data progressively and efficiently.\n\n* `DATEDIF` is technically still supported, but wont show as an option. For additional information, see Excel \"Help\" page.\n\nLearn more from the following resources:",
|
||||
"description": "The `DATEDIF` function is an incredibly valuable tool for a Data Analyst in Excel or Google Sheets, by providing the ability to calculate the difference between two dates. This function takes in three parameters: start date, end date and the type of difference required (measured in years, months, days, etc.). In Data Analysis, particularly when dealing with time-series data or when you need to uncover trends over specific periods, the `DATEDIF` function is a necessary asset. Recognizing its functionality will enable a data analyst to manipulate or shape data progressively and efficiently.\n\n`DATEDIF` is technically still supported, but wont show as an option. For additional information, see Excel \"Help\" page.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "DATEDIF function",
|
||||
@@ -418,17 +413,17 @@
|
||||
"description": "Data Analysts recurrently find the need to summarize, investigate, and analyze their data to make meaningful and insightful decisions. One of the most powerful tools to accomplish this in Microsoft Excel is the Pivot Table. Pivot Tables allow analysts to organize and summarize large quantities of data in a concise, tabular format. The strength of pivot tables comes from their ability to manipulate data dynamically, leading to quicker analysis and richer insights. Understanding and employing Pivot Tables efficiently is a fundamental skill for any data analyst, as it directly impacts their ability to derive significant information from raw datasets.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Create a pivot table",
|
||||
"title": "Create a Pivot Table",
|
||||
"url": "https://support.microsoft.com/en-gb/office/create-a-pivottable-to-analyze-worksheet-data-a9a84538-bfe9-40a9-a8e9-f99134456576",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Pivot tables in excel",
|
||||
"title": "Pivot Tables in Excel",
|
||||
"url": "https://www.excel-easy.com/data-analysis/pivot-tables.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to create a pivot table in excel",
|
||||
"title": "How to Create a Pivot Table in Excel",
|
||||
"url": "https://www.youtube.com/watch?v=PdJzy956wo4",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -463,15 +458,31 @@
|
||||
},
|
||||
"M1QtGTLyygIjePoCfvjve": {
|
||||
"title": "Data Manipulation Libraries",
|
||||
"description": "Data manipulation libraries are essential tools in data science and analytics, enabling efficient handling, transformation, and analysis of large datasets. Python, a popular language for data science, offers several powerful libraries for this purpose. Pandas is a highly versatile library that provides data structures like DataFrames, which allow for easy manipulation and analysis of tabular data. NumPy, another fundamental library, offers support for large, multi-dimensional arrays and matrices, along with a collection of mathematical functions to operate on these arrays. Together, Pandas and NumPy form the backbone of data manipulation in Python, facilitating tasks such as data cleaning, merging, reshaping, and statistical analysis, thus streamlining the data preparation process for machine learning and other data-driven applications.",
|
||||
"links": []
|
||||
"description": "Data manipulation libraries are essential tools in data science and analytics, enabling efficient handling, transformation, and analysis of large datasets. Python, a popular language for data science, offers several powerful libraries for this purpose. Pandas is a highly versatile library that provides data structures like DataFrames, which allow for easy manipulation and analysis of tabular data. NumPy, another fundamental library, offers support for large, multi-dimensional arrays and matrices, along with a collection of mathematical functions to operate on these arrays. Together, Pandas and NumPy form the backbone of data manipulation in Python, facilitating tasks such as data cleaning, merging, reshaping, and statistical analysis, thus streamlining the data preparation process for machine learning and other data-driven applications.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Pandas",
|
||||
"url": "https://pandas.pydata.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "NumPy",
|
||||
"url": "https://numpy.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Top Python Libraries for Data Science",
|
||||
"url": "https://www.simplilearn.com/top-python-libraries-for-data-science-article",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"8OXmF2Gn6TYJotBRvDjqA": {
|
||||
"title": "Pandas",
|
||||
"description": "Pandas is a widely acknowledged and highly useful data manipulation library in the world of data analysis. Known for its robust features like data cleaning, wrangling and analysis, pandas has become one of the go-to tools for data analysts. Built on NumPy, it provides high-performance, easy-to-use data structures and data analysis tools. In essence, its flexibility and versatility make it a critical part of the data analyst's toolkit, as it holds the capability to cater to virtually every data manipulation task.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Pandas Website",
|
||||
"title": "Pandas",
|
||||
"url": "https://pandas.pydata.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -484,7 +495,7 @@
|
||||
},
|
||||
"l1SnPc4EMqGdaIAhIQfrT": {
|
||||
"title": "Data Visualisation Libraries",
|
||||
"description": "Data visualization libraries are crucial in data science for transforming complex datasets into clear and interpretable visual representations, facilitating better understanding and communication of data insights. In Python, several libraries are widely used for this purpose. Matplotlib is a foundational library that offers comprehensive tools for creating static, animated, and interactive plots. Seaborn, built on top of Matplotlib, provides a high-level interface for drawing attractive and informative statistical graphics with minimal code. Plotly is another powerful library that allows for the creation of interactive and dynamic visualizations, which can be easily embedded in web applications. Additionally, libraries like Bokeh and Altair offer capabilities for creating interactive plots and dashboards, enhancing exploratory data analysis and the presentation of data findings. Together, these libraries enable data scientists to effectively visualize trends, patterns, and outliers in their data, making the analysis more accessible and actionable.",
|
||||
"description": "Data visualization libraries are crucial in data science for transforming complex datasets into clear and interpretable visual representations, facilitating better understanding and communication of data insights. In Python, several libraries are widely used for this purpose. Matplotlib is a foundational library that offers comprehensive tools for creating static, animated, and interactive plots. Seaborn, built on top of Matplotlib, provides a high-level interface for drawing attractive and informative statistical graphics with minimal code. Plotly is another powerful library that allows for the creation of interactive and dynamic visualizations, which can be easily embedded in web applications. Additionally, libraries like Bokeh and Altair offer capabilities for creating interactive plots and dashboards, enhancing exploratory data analysis and the presentation of data findings. Together, these libraries enable data scientists to effectively visualize trends, patterns, and outliers in their data, making the analysis more accessible and actionable.\n\nLearn more from the following resources:",
|
||||
"links": []
|
||||
},
|
||||
"uGkXxdMXUMY-3fQFS1jK8": {
|
||||
@@ -492,7 +503,7 @@
|
||||
"description": "Matplotlib is a paramount data visualization library used extensively by data analysts for generating a wide array of plots and graphs. Through Matplotlib, data analysts can convey results clearly and effectively, driving insights from complex data sets. It offers a hierarchical environment which is very natural for a data scientist to work with. Providing an object-oriented API, it allows for extensive customization and integration into larger applications. From histograms, bar charts, scatter plots to 3D graphs, the versatility of Matplotlib assists data analysts in the better comprehension and compelling representation of data.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Matplotlib Website",
|
||||
"title": "Matplotlib",
|
||||
"url": "https://matplotlib.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -508,7 +519,7 @@
|
||||
"description": "Dplyr is a powerful and popular toolkit for data manipulation in R. As a data analyst, this library provides integral functions to manipulate, clean, and process data efficiently. It has been designed to be easy and intuitive, ensuring a robust and consistent syntax. Dplyr ensures data reliability and fast processing, essential for analysts dealing with large datasets. With a strong focus on efficiency, dplyr functions like select, filter, arrange, mutate, summarise, and group\\_by optimise data analysis operations, making data manipulation a smoother and hassle-free procedure for data analysts.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "dplyr website",
|
||||
"title": "dplyr",
|
||||
"url": "https://dplyr.tidyverse.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -524,7 +535,7 @@
|
||||
"description": "When it comes to data visualization in R programming, ggplot2 stands tall as one of the primary tools for data analysts. This data visualization library, which forms part of the tidyverse suite of packages, facilitates the creation of complex and sophisticated visual narratives. With its grammar of graphics philosophy, ggplot2 enables analysts to build graphs and charts layer by layer, thereby offering detailed control over graphical features and design. Its versatility in creating tailored and aesthetically pleasing graphics is a vital asset for any data analyst tackling exploratory data analysis, reporting, or dashboard building.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "ggplot2 website",
|
||||
"title": "ggplot2",
|
||||
"url": "https://ggplot2.tidyverse.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -537,21 +548,27 @@
|
||||
},
|
||||
"_sjXCLHHTbZromJYn6fnu": {
|
||||
"title": "Data Collection",
|
||||
"description": "In the context of the Data Analyst role, data collection is a foundational process that entails gathering relevant data from various sources. This data can be quantitative or qualitative and may be sourced from databases, online platforms, customer feedback, among others. The gathered information is then cleaned, processed, and interpreted to extract meaningful insights. A data analyst performs this whole process carefully, as the quality of data is paramount to ensuring accurate analysis, which in turn informs business decisions and strategies. This highlights the importance of an excellent understanding, proper tools, and precise techniques when it comes to data collection in data analysis.",
|
||||
"links": []
|
||||
"description": "Data collection is a foundational process that entails gathering relevant data from various sources. This data can be quantitative or qualitative and may be sourced from databases, online platforms, customer feedback, among others. The gathered information is then cleaned, processed, and interpreted to extract meaningful insights. A data analyst performs this whole process carefully, as the quality of data is paramount to ensuring accurate analysis, which in turn informs business decisions and strategies. This highlights the importance of an excellent understanding, proper tools, and precise techniques when it comes to data collection in data analysis.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Data Collection",
|
||||
"url": "https://en.wikipedia.org/wiki/Data_collection",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tYPeLCxbqvMFlTkCGjdHg": {
|
||||
"title": "Databases",
|
||||
"description": "Behind every strong data analyst, there's not just a rich assortment of data, but a set of robust databases that enable effective data collection. Databases are a fundamental aspect of data collection in a world where the capability to manage, organize, and evaluate large volumes of data is critical. As a data analyst, the understanding and use of databases is instrumental in capturing the necessary data for conducting qualitative and quantitative analysis, forecasting trends and making data-driven decisions. Thorough knowledge of databases, therefore, can be considered a key component of a data analyst's arsenal. These databases can vary from relational databases like SQL to NoSQL databases like MongoDB, each serving a unique role in the data collection process.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL Roadmap",
|
||||
"url": "https://roadmap.sh/postgresql-dba",
|
||||
"title": "Visit Dedicated SQL Roadmap",
|
||||
"url": "https://roadmap.sh/sql",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "MongoDB Roadmap",
|
||||
"url": "https://roadmap.sh/mongodb",
|
||||
"title": "Visit Dedicated PostgreSQL Roadmap",
|
||||
"url": "https://roadmap.sh/postgresql-dba",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -582,7 +599,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "A beginners guide to APIs",
|
||||
"title": "A Beginner's Guide to APIs",
|
||||
"url": "https://www.postman.com/what-is-an-api/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -593,12 +610,12 @@
|
||||
"description": "Web scraping plays a significant role in collecting unique datasets for data analysis. In the realm of a data analyst's tasks, web scraping refers to the method of extracting information from websites and converting it into a structured usable format like a CSV, Excel spreadsheet, or even into databases. This technique allows data analysts to gather large sets of data from the internet, which otherwise could be time-consuming if done manually. The capability of web scraping and parsing data effectively can give data analysts a competitive edge in their data analysis process, from unlocking in-depth, insightful information to making data-driven decisions.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is web scraping what is it used for?",
|
||||
"title": "What is Web Scraping & What is it used for?",
|
||||
"url": "https://www.parsehub.com/blog/what-is-web-scraping/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is web scraping?",
|
||||
"title": "What is Web Scraping?",
|
||||
"url": "https://www.youtube.com/watch?v=dlj_QL-ENJM",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -606,8 +623,14 @@
|
||||
},
|
||||
"E6cpb6kvluJM8OGuDcFBT": {
|
||||
"title": "Data Cleanup",
|
||||
"description": "Data cleaning, which is often referred as data cleansing or data scrubbing, is one of the most important and initial steps in the data analysis process. As a data analyst, the bulk of your work often revolves around understanding, cleaning, and standardizing raw data before analysis. Data cleaning involves identifying, correcting or removing any errors or inconsistencies in datasets in order to improve their quality. The process is crucial because it directly determines the accuracy of the insights you generate - garbage in, garbage out. Even the most sophisticated models and visualizations would not be of much use if they're based on dirty data. Therefore, mastering data cleaning techniques is essential for any data analyst.",
|
||||
"links": []
|
||||
"description": "Data cleaning, which is often referred as data cleansing or data scrubbing, is one of the most important and initial steps in the data analysis process. As a data analyst, the bulk of your work often revolves around understanding, cleaning, and standardizing raw data before analysis. Data cleaning involves identifying, correcting or removing any errors or inconsistencies in datasets in order to improve their quality. The process is crucial because it directly determines the accuracy of the insights you generate - garbage in, garbage out. Even the most sophisticated models and visualizations would not be of much use if they're based on dirty data. Therefore, mastering data cleaning techniques is essential for any data analyst.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Data Cleaning",
|
||||
"url": "https://www.tableau.com/learn/articles/what-is-data-cleaning#:~:text=tools%20and%20software-,What%20is%20data%20cleaning%3F,to%20be%20duplicated%20or%20mislabeled.",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"X9WmfHOks82BIAzs6abqO": {
|
||||
"title": "Handling Missing Data",
|
||||
@@ -647,14 +670,14 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "Outliers",
|
||||
"url": "%5Bhttps://www.mathsisfun.com/data/outliers.html",
|
||||
"url": "https://www.mathsisfun.com/data/outliers.html",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"t_BRtEharsrOZxoyX0OzV": {
|
||||
"title": "Data Transformation",
|
||||
"description": "Data Transformation, also known as Data Wrangling, is an essential part of a Data Analyst's role. This process involves the conversion of data from a raw format into another format to make it more appropriate and valuable for a variety of downstream purposes such as analytics. Data Analysts transform data to make the data more suitable for analysis, ensure accuracy, and to improve data quality. The right transformation techniques can give the data a structure, multiply its value, and enhance the accuracy of the analytics performed by serving meaningful results.",
|
||||
"description": "Data Transformation, also known as Data Wrangling, is an essential part of a Data Analyst's role. This process involves the conversion of data from a raw format into another format to make it more appropriate and valuable for a variety of downstream purposes such as analytics. Data Analysts transform data to make the data more suitable for analysis, ensure accuracy, and to improve data quality. The right transformation techniques can give the data a structure, multiply its value, and enhance the accuracy of the analytics performed by serving meaningful results.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is data transformation?",
|
||||
@@ -673,7 +696,7 @@
|
||||
"description": "In the realms of data analysis, data cleaning is a crucial preliminary process, this is where `pandas` - a popular python library - shines. Primarily used for data manipulation and analysis, pandas adopts a flexible and powerful data structure (DataFrames and Series) that greatly simplifies the process of cleaning raw, messy datasets. Data analysts often work with large volumes of data, some of which may contain missing or inconsistent data that can negatively impact the results of their analysis. By utilizing pandas, data analysts can quickly identify, manage and fill these missing values, drop unnecessary columns, rename column headings, filter specific data, apply functions for more complex data transformations and much more. Thus, making pandas an invaluable tool for effective data cleaning in data analysis.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Pandas Website",
|
||||
"title": "Pandas",
|
||||
"url": "https://pandas.pydata.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -689,7 +712,7 @@
|
||||
"description": "Data cleaning plays a crucial role in the data analysis pipeline, where it rectifies and enhances the quality of data to increase the efficiency and authenticity of the analytical process. The `dplyr` package, an integral part of the `tidyverse` suite in R, has become a staple in the toolkit of data analysts dealing with data cleaning. `dplyr` offers a coherent set of verbs that significantly simplifies the process of manipulating data structures, such as dataframes and databases. This involves selecting, sorting, filtering, creating or modifying variables, and aggregating records, among other operations. Incorporating `dplyr` into the data cleaning phase enables data analysts to perform operations more effectively, improve code readability, and handle large and complex data with ease.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "dplyr website",
|
||||
"title": "dplyr",
|
||||
"url": "https://dplyr.tidyverse.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -801,7 +824,7 @@
|
||||
"description": "When focusing on data analysis, understanding key statistical concepts is crucial. Amongst these, central tendency is a foundational element. Central Tendency refers to the measure that determines the center of a distribution. The average is a commonly used statistical tool by which data analysts discern trends and patterns. As one of the most recognized forms of central tendency, figuring out the \"average\" involves summing all values in a data set and dividing by the number of values. This provides analysts with a 'typical' value, around which the remaining data tends to cluster, facilitating better decision-making based on existing data.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How to calculate the average",
|
||||
"title": "How to Calculate the Average",
|
||||
"url": "https://support.microsoft.com/en-gb/office/calculate-the-average-of-a-group-of-numbers-e158ef61-421c-4839-8290-34d7b1e68283#:~:text=Average%20This%20is%20the%20arithmetic,by%206%2C%20which%20is%205.",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -817,7 +840,7 @@
|
||||
"description": "The concept of Range refers to the spread of a dataset, primarily in the realm of statistics and data analysis. This measure is crucial for a data analyst as it provides an understanding of the variability amongst the numbers within a dataset. Specifically in a role such as Data Analyst, understanding the range and dispersion aids in making more precise analyses and predictions. Understanding the dispersion within a range can highlight anomalies, identify standard norms, and form the foundation for statistical conclusions like the standard deviation, variance, and interquartile range. It allows for the comprehension of the reliability and stability of particular datasets, which can help guide strategic decisions in many industries. Therefore, range is a key concept that every data analyst must master.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How to find the range of a data set",
|
||||
"title": "How to Find the Range of a Data Set",
|
||||
"url": "https://www.scribbr.co.uk/stats/range-statistics/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -828,12 +851,12 @@
|
||||
"description": "Data analysts heavily rely on statistical concepts to analyze and interpret data, and one such fundamental concept is variance. Variance, an essential measure of dispersion, quantifies the spread of data, providing insight into the level of variability within the dataset. Understanding variance is crucial for data analysts as the reliability of many statistical models depends on the assumption of constant variance across observations. In other words, it helps analysts determine how much data points diverge from the expected value or mean, which can be pivotal in identifying outliers, understanding data distribution, and driving decision-making processes. However, variance can't be interpreted in the original units of measurement due to its squared nature, which is why it is often used in conjunction with its square root, the standard deviation.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is variance?",
|
||||
"title": "What is Variance?",
|
||||
"url": "https://www.investopedia.com/terms/v/variance.asp",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to calculate variance",
|
||||
"title": "How to Calculate Variance",
|
||||
"url": "https://www.scribbr.co.uk/stats/variance-meaning/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -903,7 +926,7 @@
|
||||
"description": "Tableau is a powerful data visualization tool utilized extensively by data analysts worldwide. Its primary role is to transform raw, unprocessed data into an understandable format without any technical skills or coding. Data analysts use Tableau to create data visualizations, reports, and dashboards that help businesses make more informed, data-driven decisions. They also use it to perform tasks like trend analysis, pattern identification, and forecasts, all within a user-friendly interface. Moreover, Tableau's data visualization capabilities make it easier for stakeholders to understand complex data and act on insights quickly.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Tableau Website",
|
||||
"title": "Tableau",
|
||||
"url": "https://www.tableau.com/en-gb",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -919,7 +942,7 @@
|
||||
"description": "PowerBI, an interactive data visualization and business analytics tool developed by Microsoft, plays a crucial role in the field of a data analyst's work. It helps data analysts to convert raw data into meaningful insights through it's easy-to-use dashboards and reports function. This tool provides a unified view of business data, allowing analysts to track and visualize key performance metrics and make better-informed business decisions. With PowerBI, data analysts also have the ability to manipulate and produce visualizations of large data sets that can be shared across an organization, making complex statistical information more digestible.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Power BI Website",
|
||||
"title": "Power BI",
|
||||
"url": "https://www.microsoft.com/en-us/power-platform/products/power-bi",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -935,7 +958,7 @@
|
||||
"description": "For a Data Analyst, understanding data and being able to represent it in a visually insightful form is a crucial part of effective decision-making in any organization. Matplotlib, a plotting library for the Python programming language, is an extremely useful tool for this purpose. It presents a versatile framework for generating line plots, scatter plots, histogram, bar charts and much more in a very straightforward manner. This library also allows for comprehensive customizations, offering a high level of control over the look and feel of the graphics it produces, which ultimately enhances the quality of data interpretation and communication.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Matplotlib Website",
|
||||
"title": "Matplotlib",
|
||||
"url": "https://matplotlib.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -951,7 +974,7 @@
|
||||
"description": "Seaborn is a robust, comprehensive Python library focused on the creation of informative and attractive statistical graphics. As a data analyst, seaborn plays an essential role in elaborating complex visual stories with the data. It aids in understanding the data by providing an interface for drawing attractive and informative statistical graphics. Seaborn is built on top of Python's core visualization library Matplotlib, and is integrated with data structures from Pandas. This makes seaborn an integral tool for data visualization in the data analyst's toolkit, making the exploration and understanding of data easier and more intuitive.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Seaborn Website",
|
||||
"title": "Seaborn",
|
||||
"url": "https://seaborn.pydata.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -983,12 +1006,12 @@
|
||||
"description": "As a vital tool in the data analyst's arsenal, bar charts are essential for analyzing and interpreting complex data. Bar charts, otherwise known as bar graphs, are frequently used graphical displays for dealing with categorical data groups or discrete variables. With their stark visual contrast and definitive measurements, they provide a simple yet effective means of identifying trends, understanding data distribution, and making data-driven decisions. By analyzing the lengths or heights of different bars, data analysts can effectively compare categories or variables against each other and derive meaningful insights effectively. Simplicity, readability, and easy interpretation are key features that make bar charts a favorite in the world of data analytics.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "A complete guide to bar charts",
|
||||
"title": "A Complete Guide to Bar Charts",
|
||||
"url": "https://www.atlassian.com/data/charts/bar-chart-complete-guide",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is a bar chart?",
|
||||
"title": "What is a Bar Chart?",
|
||||
"url": "https://www.youtube.com/watch?v=WTVdncVCvKo",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -1015,7 +1038,7 @@
|
||||
"description": "A scatter plot, a crucial aspect of data visualization, is a mathematical diagram using Cartesian coordinates to represent values from two different variables. As a data analyst, understanding and interpreting scatter plots can be instrumental in identifying correlations and trends within a dataset, drawing meaningful insights, and showcasing these findings in a clear, visual manner. In addition, scatter plots are paramount in predictive analytics as they reveal patterns which can be used to predict future occurrences.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Mastering scatter plots",
|
||||
"title": "Mastering Scatter Plots",
|
||||
"url": "https://www.atlassian.com/data/charts/what-is-a-scatter-plot",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1063,7 +1086,7 @@
|
||||
"description": "A stacked chart is an essential tool for a data analyst in the field of data visualization. This type of chart presents quantitative data in a visually appealing manner and allows users to easily compare different categories while still being able to compare the total sizes. These charts are highly effective when trying to measure part-to-whole relationships, displaying accumulated totals over time or when presenting data with multiple variables. Data analysts often use stacked charts to detect patterns, trends and anomalies which can aid in strategic decision making.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is a stacked chart?",
|
||||
"title": "What is a Stacked Chart?",
|
||||
"url": "https://www.spotfire.com/glossary/what-is-a-stacked-chart",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1079,12 +1102,12 @@
|
||||
"description": "Heatmaps are a crucial component of data visualization that Data Analysts regularly employ in their analyses. As one of many possible graphical representations of data, heatmaps show the correlation or scale of variation between two or more variables in a dataset, making them extremely useful for pattern recognition and outlier detection. Individual values within a matrix are represented in a heatmap as colors, with differing intensities indicating the degree or strength of an occurrence. In short, a Data Analyst would use a heatmap to decode complex multivariate data and turn it into an easily understandable visual that aids in decision making.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "A complete guide to heatmaps",
|
||||
"title": "A Complete Guide to Heatmaps",
|
||||
"url": "https://www.hotjar.com/heatmaps/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is a heatmap?",
|
||||
"title": "What is a Heatmap?",
|
||||
"url": "https://www.atlassian.com/data/charts/heatmap-complete-guide",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1095,12 +1118,12 @@
|
||||
"description": "As a data analyst, understanding and efficiently using various forms of data visualization is crucial. Among these, Pie Charts represent a significant tool. Essentially, pie charts are circular statistical graphics divided into slices to illustrate numerical proportions. Each slice of the pie corresponds to a particular category. The pie chart's beauty lies in its simplicity and visual appeal, making it an effective way to convey relative proportions or percentages at a glance. For a data analyst, it's particularly useful when you want to show a simple distribution of categorical data. Like any tool, though, it's important to use pie charts wisely—ideally, when your data set has fewer than seven categories, and the proportions between categories are distinct.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "A complete guide to pie charts",
|
||||
"title": "A Complete Guide to Pie Charts",
|
||||
"url": "https://www.atlassian.com/data/charts/pie-chart-complete-guide",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is a a pie chart",
|
||||
"title": "What is a Pie Chart",
|
||||
"url": "https://www.youtube.com/watch?v=GjJdZaQrItg",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -1108,13 +1131,30 @@
|
||||
},
|
||||
"2g19zjEASJw2ve57hxpr0": {
|
||||
"title": "Data Visualisation",
|
||||
"description": "Data Visualization is a fundamental fragment of the responsibilities of a data analyst. It involves the presentation of data in a graphical or pictorial format which allows decision-makers to see analytics visually. This practice can help them comprehend difficult concepts or establish new patterns. With interactive visualization, data analysts can take the data analysis process to a whole new level — drill down into charts and graphs for more detail, and interactively changing what data is presented or how it’s processed. Thereby it forms a crucial link in the chain of converting raw data to actionable insights which is one of the primary roles of a Data Analyst.",
|
||||
"links": []
|
||||
"description": "Data Visualization is a fundamental fragment of the responsibilities of a data analyst. It involves the presentation of data in a graphical or pictorial format which allows decision-makers to see analytics visually. This practice can help them comprehend difficult concepts or establish new patterns. With interactive visualization, data analysts can take the data analysis process to a whole new level — drill down into charts and graphs for more detail, and interactively changing what data is presented or how it’s processed. Thereby it forms a crucial link in the chain of converting raw data to actionable insights which is one of the primary roles of a Data Analyst.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is Data Visualization?",
|
||||
"url": "https://www.ibm.com/think/topics/data-visualization",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"TeewVruErSsD4VLXcaDxp": {
|
||||
"title": "Statistical Analysis",
|
||||
"description": "Statistical analysis is a core component of a data analyst's toolkit. As professionals dealing with vast amount of structured and unstructured data, data analysts often turn to statistical methods to extract insights and make informed decisions. The role of statistical analysis in data analytics involves gathering, reviewing, and interpreting data for various applications, enabling businesses to understand their performance, trends, and growth potential. Data analysts use a range of statistical techniques from modeling, machine learning, and data mining, to convey vital information that supports strategic company actions.\n\nLearn more from the following resources:",
|
||||
"links": []
|
||||
"links": [
|
||||
{
|
||||
"title": "Understanding Statistical Analysis",
|
||||
"url": "https://www.simplilearn.com/what-is-statistical-analysis-article",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Statistical Analysis",
|
||||
"url": "https://www.youtube.com/watch?v=XjMBZE1DuBY",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Xygwu0m5TeYT6S_8FKKXh": {
|
||||
"title": "Hypothesis Testing",
|
||||
@@ -1166,7 +1206,7 @@
|
||||
},
|
||||
"mCUW07rx74_dUNi7OGVlj": {
|
||||
"title": "Visualizing Distributions",
|
||||
"description": "Visualising Distributions, from a data analyst's perspective, plays a key role in understanding the overall distribution and identifying patterns within data. It aids in summarising, structuring, and plotting structured data graphically to provide essential insights. This includes using different chart types like bar graphs, histograms, and scatter plots for interval data, and pie or bar graphs for categorical data. Ultimately, the aim is to provide a straightforward and effective manner to comprehend the data's characteristics and underlying structure. A data analyst uses these visualisation techniques to make initial conclusions, detect anomalies, and decide on further analysis paths.\n\nLearn more from the following resources:",
|
||||
"description": "Visualising Distributions, from a data analyst's perspective, plays a key role in understanding the overall distribution and identifying patterns within data. It aids in summarizing, structuring, and plotting structured data graphically to provide essential insights. This includes using different chart types like bar graphs, histograms, and scatter plots for interval data, and pie or bar graphs for categorical data. Ultimately, the aim is to provide a straightforward and effective manner to comprehend the data's characteristics and underlying structure. A data analyst uses these visualisation techniques to make initial conclusions, detect anomalies, and decide on further analysis paths.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Data Visualizations that Capture Distributions",
|
||||
@@ -1206,12 +1246,12 @@
|
||||
"description": "Unsupervised learning, as a fundamental aspect of Machine Learning, holds great implications in the realm of data analytics. It is an approach where a model learns to identify patterns and relationships within a dataset that isn't labelled or classified. It is especially useful for a Data Analyst as it can assist in recognizing unforeseen trends, providing new insights or preparing data for other machine learning tasks. This ability to infer without direct supervision allows a vast potential for latent structure discovery and new knowledge derivation from raw data.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is unsupervised learning?",
|
||||
"title": "What is Unsupervised Learning?",
|
||||
"url": "https://cloud.google.com/discover/what-is-unsupervised-learning",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Introduction to unsupervised learning",
|
||||
"title": "Introduction to Unsupervised Learning",
|
||||
"url": "https://www.datacamp.com/blog/introduction-to-unsupervised-learning",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1222,7 +1262,7 @@
|
||||
"description": "Supervised machine learning forms an integral part of the toolset for a Data Analyst. With a direct focus on building predictive models from labeled datasets, it involves training an algorithm based on these known inputs and outputs, helping Data Analysts establish correlations and make reliable predictions. Fortifying a Data Analyst's role, supervised machine learning enables the accurate interpretation of complex data, enhancing decision-making processes.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is supervised learning?",
|
||||
"title": "What is Supervised Learning?",
|
||||
"url": "https://cloud.google.com/discover/what-is-supervised-learning",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1286,12 +1326,12 @@
|
||||
"description": "As a data analyst, it's crucial to understand various model evaluation techniques. These techniques involve different methods to measure the performance or accuracy of machine learning models. For instance, using confusion matrix, precision, recall, F1 score, ROC curves or Root Mean Squared Error (RMSE) among others. Knowing how to apply these techniques effectively not only helps in selecting the best model for a specific problem but also guides in tuning the performance of the models for optimal results. Understanding these model evaluation techniques also allows data analysts to interpret evaluation results and determine the effectiveness and applicability of a model.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is model evaluation",
|
||||
"title": "What is Model Evaluation",
|
||||
"url": "https://domino.ai/data-science-dictionary/model-evaluation",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Model evaluation metrics",
|
||||
"title": "Model Evaluation Metrics",
|
||||
"url": "https://www.markovml.com/blog/model-evaluation-metrics",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1299,8 +1339,14 @@
|
||||
},
|
||||
"_aUQZWUhFRvNu0MZ8CPit": {
|
||||
"title": "Big Data Technologies",
|
||||
"description": "In the modern digitized world, Big Data refers to extremely large datasets that are challenging to manage and analyze using traditional data processing applications. These datasets often come from numerous different sources and are not only voluminous but also diverse in nature, including structured and unstructured data. The role of a data analyst in the context of big data is crucial. Data analysts are responsible for inspecting, cleaning, transforming, and modeling big data to discover useful information, conclude and support decision-making. They leverage their analytical skills and various big data tools and technologies to extract insights that can benefit the organization and drive strategic business initiatives.",
|
||||
"links": []
|
||||
"description": "In the modern digitized world, Big Data refers to extremely large datasets that are challenging to manage and analyze using traditional data processing applications. These datasets often come from numerous different sources and are not only voluminous but also diverse in nature, including structured and unstructured data. The role of a data analyst in the context of big data is crucial. Data analysts are responsible for inspecting, cleaning, transforming, and modeling big data to discover useful information, conclude and support decision-making. They leverage their analytical skills and various big data tools and technologies to extract insights that can benefit the organization and drive strategic business initiatives.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Big Data Analytics",
|
||||
"url": "https://www.ibm.com/think/topics/big-data-analytics",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"m1IfG2sEedUxMXrv_B8GW": {
|
||||
"title": "Big Data Concepts",
|
||||
@@ -1371,7 +1417,7 @@
|
||||
"description": "Hadoop is a critical element in the realm of data processing frameworks, offering an effective solution for storing, managing, and analyzing massive amounts of data. Unraveling meaningful insights from a large deluge of data is a challenging pursuit faced by many data analysts. Regular data processing tools fail to handle large-scale data, paving the way for advanced frameworks like Hadoop. This open-source platform by Apache Software Foundation excels at storing and processing vast data across clusters of computers. Notably, Hadoop comprises two key modules - the Hadoop Distributed File System (HDFS) for storage and MapReduce for processing. Hadoop’s ability to handle both structured and unstructured data further broadens its capacity. For any data analyst, a thorough understanding of Hadoop can unlock powerful ways to manage data effectively and construct meaningful analytics.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Apache Hadoop Website",
|
||||
"title": "Apache Hadoop",
|
||||
"url": "https://hadoop.apache.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1392,7 +1438,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Apache Spark Website",
|
||||
"title": "Apache Spark",
|
||||
"url": "https://spark.apache.org/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1432,15 +1478,21 @@
|
||||
},
|
||||
"SiYUdtYMDImRPmV2_XPkH": {
|
||||
"title": "Deep Learning (Optional)",
|
||||
"description": "Deep learning, a subset of machine learning technique, is increasingly becoming a critical tool for data analysts. Deep learning algorithms utilize multiple layers of neural networks to understand and interpret intricate structures in large data, a skill that is integral to the daily functions of a data analyst. With the ability to learn from unstructured or unlabeled data, deep learning opens a whole new range of possibilities for data analysts in terms of data processing, prediction, and categorization. It has applications in a variety of industries from healthcare to finance to e-commerce and beyond. A deeper understanding of deep learning methodologies can augment a data analyst's capability to evaluate and interpret complex datasets and provide valuable insights for decision making.",
|
||||
"links": []
|
||||
"description": "Deep learning, a subset of machine learning technique, is increasingly becoming a critical tool for data analysts. Deep learning algorithms utilize multiple layers of neural networks to understand and interpret intricate structures in large data, a skill that is integral to the daily functions of a data analyst. With the ability to learn from unstructured or unlabeled data, deep learning opens a whole new range of possibilities for data analysts in terms of data processing, prediction, and categorization. It has applications in a variety of industries from healthcare to finance to e-commerce and beyond. A deeper understanding of deep learning methodologies can augment a data analyst's capability to evaluate and interpret complex datasets and provide valuable insights for decision making.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Deep Learning for Data Analysis",
|
||||
"url": "https://www.ibm.com/think/topics/deep-learning",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"gGHsKcS92StK5FolzmVvm": {
|
||||
"title": "Neural Networks",
|
||||
"description": "Neural Networks play a pivotal role in the landscape of deep learning, offering a plethora of benefits and applications for data analysts. They are computational models that emulate the way human brain processes information, enabling machines to make intelligent decisions. As a data analyst, understanding and utilizing neural networks can greatly enhance decision-making process as it allows to quickly and effectively analyze large datasets, recognize patterns, and forecast future trends. In deep learning, these networks are used for creating advanced models that can tackle complex tasks such as image recognition, natural language processing, and speech recognition, to name but a few. Therefore, an in-depth knowledge of neural networks is a significant asset for any aspiring or professional data analyst.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is a neural network?",
|
||||
"title": "What is a Neural Network?",
|
||||
"url": "https://aws.amazon.com/what-is/neural-network/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1472,12 +1524,12 @@
|
||||
"description": "Recurrent Neural Networks(RNNs) are a type of Artificial Neural Networks(ANNs) which introduces us to the realm of Deep Learning, an aspect that has been significantly contributing to the evolution of Data Analysis. RNNs are specifically designed to recognize patterns in sequences of data, such as text, genomes, handwriting, or the spoken word. This inherent feature of RNNs makes them extremely useful and versatile for a data analyst.\n\nA data analyst leveraging RNNs can effectively charter the intrinsic complexity of data sequences, classify them, and make accurate predictions. With the fundamental understanding of deep learning, data analysts can unlock the full potential of RNNs in delivering insightful data analysis that goes beyond traditional statistical methods. Modern research and applications of RNNs extend to multiple domains including natural language processing, speech recognition, and even in the financial sphere for stock price prediction making this a key tool in a data analyst’s arsenal.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is a recurrent neural network (RNN)?",
|
||||
"title": "What is a Recurrent Neural Network (RNN)?",
|
||||
"url": "https://www.ibm.com/topics/recurrent-neural-networks",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Recurrent Neural Networks cheatsheet",
|
||||
"title": "Recurrent Neural Networks Cheat-sheet",
|
||||
"url": "https://stanford.edu/~shervine/teaching/cs-230/cheatsheet-recurrent-neural-networks",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1488,10 +1540,15 @@
|
||||
"description": "TensorFlow, developed by Google Brain Team, has become a crucial tool in the realm of data analytics, particularly within the field of deep learning. It's an open-source platform for machine learning, offering a comprehensive and flexible ecosystem of tools, libraries, and community resources. As a data analyst, understanding and implementing TensorFlow for deep learning models allows us to identify complex patterns and make insightful predictions which standard analysis could miss. It's in-demand skill that enhances our ability to generate accurate insights from colossal and complicated structured or unstructured data sets.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Tensorflow Website",
|
||||
"title": "Tensorflow",
|
||||
"url": "https://www.tensorflow.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Tensorflow Documentation",
|
||||
"url": "https://www.tensorflow.org/learn",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Tensorflow in 100 seconds",
|
||||
"url": "https://www.youtube.com/watch?v=i8NETqtGHms",
|
||||
@@ -1504,10 +1561,15 @@
|
||||
"description": "PyTorch, an open-source machine learning library, has gained considerable popularity among data analysts due to its simplicity and high performance in tasks such as natural language processing and artificial intelligence. Specifically, in the domain of deep learning, PyTorch stands out due to its dynamic computational graph, allowing for a highly intuitive and flexible platform for building complex models. For data analysts, mastering PyTorch can open up a broad range of opportunities for data model development, data processing, and integration of machine learning algorithms.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PyTorch Website",
|
||||
"title": "PyTorch",
|
||||
"url": "https://pytorch.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PyTorch Documentation",
|
||||
"url": "https://pytorch.org/docs/stable/index.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PyTorch in 100 seconds",
|
||||
"url": "https://www.youtube.com/watch?v=ORMx45xqWkA",
|
||||
@@ -1520,7 +1582,7 @@
|
||||
"description": "Image Recognition has become a significant domain because of its diverse applications, including facial recognition, object detection, character recognition, and much more. As a Data Analyst, understanding Image Recognition under Deep Learning becomes crucial. The data analyst's role in this context involves deciphering complex patterns and extracting valuable information from image data. This area of machine learning combines knowledge of data analysis, image processing, and deep neural networks to provide accurate results, contributing significantly to the progression of fields like autonomous vehicles, medical imaging, surveillance, among others. Therefore, proficiency in this field paves the way for proficient data analysis, leading to innovative solutions and improved decision-making.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is image recognition?",
|
||||
"title": "What is Image Recognition?",
|
||||
"url": "https://www.techtarget.com/searchenterpriseai/definition/image-recognition",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1552,12 +1614,12 @@
|
||||
"description": "As a business enterprise expands, so does its data. For data analysts, the surge in information means they need efficient and scalable data storage solutions to manage vast volumes of structured and unstructured data, collectively referred to as Big Data. Big Data storage solutions are critical in preserving the integrity of data while also providing quick and easy access to the data when needed. These solutions use software and hardware components to securely store massive amounts of information across numerous servers, allowing data analysts to perform robust data extraction, data processing and complex data analyses. There are several options, from the traditional Relational Database Management Systems (RDBMS) to the more recent NoSQL databases, Hadoop ecosystems, and Cloud storage solutions, each offering unique capabilities and benefits to cater for different big data needs.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "SQL Roadmap",
|
||||
"title": "Visit Dedicated SQL Roadmap",
|
||||
"url": "https://roadmap.sh/sql",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL Roadmap",
|
||||
"title": "Visit Dedicated PostgreSQL Roadmap",
|
||||
"url": "https://roadmap.sh/postgresql-dba",
|
||||
"type": "article"
|
||||
}
|
||||
|
||||
@@ -123,7 +123,12 @@
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "The Rust Programming Language - online book",
|
||||
"title": "Visit Dedicated Rust Roadmap",
|
||||
"url": "https://roadmap.sh/rust",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The Rust Programming Language - Online Book",
|
||||
"url": "https://doc.rust-lang.org/book/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -319,7 +324,7 @@
|
||||
"description": "FreeBSD is a free, open-source Unix-like operating system descended from the Berkeley Software Distribution (BSD). Known for its stability, performance, and advanced networking capabilities, FreeBSD is popular for server environments, embedded systems, and as a basis for network appliances. It features a monolithic kernel, a comprehensive set of userland utilities, and a ports collection for easy software installation. FreeBSD supports a wide range of architectures and includes advanced features like the ZFS file system, jails for containerization, and the pf packet filter. While less common in desktop environments, it's widely used in internet infrastructure, storage systems, and by companies requiring a robust, customizable OS with a permissive license.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "FreeBSD Website",
|
||||
"title": "FreeBSD",
|
||||
"url": "https://www.freebsd.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -329,7 +334,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official FreeBSD Documentation",
|
||||
"title": "FreeBSD Documentation",
|
||||
"url": "https://docs.freebsd.org/en/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -350,7 +355,7 @@
|
||||
"description": "OpenBSD is a free, open-source Unix-like operating system known for its strong focus on security, code correctness, and proactive approach to eliminating vulnerabilities. It's renowned for its stringent code review process, integrated cryptography, and default security features like stack protection and memory safeguards. OpenBSD pioneered many security innovations, including OpenSSH, and maintains a \"secure by default\" philosophy. The system is prized for its comprehensive documentation, clean and consistent codebase, and adherence to standards. While primarily used in server environments, especially for firewalls and network appliances, OpenBSD also supports desktop use. Its emphasis on security and stability makes it popular in high-security environments and among developers focused on system-level programming and network security.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "OpenBSD Website",
|
||||
"title": "OpenBSD",
|
||||
"url": "https://www.openbsd.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -410,7 +415,7 @@
|
||||
},
|
||||
"wjJPzrFJBNYOD3SJLzW2M": {
|
||||
"title": "Terminal Knowledge",
|
||||
"description": "A terminal is simply a text-based interface to the computer, it is used to interact with your computer system via CLI (command line interface)\n\nVisit the following resources to learn more:",
|
||||
"description": "A terminal is simply a text-based interface to the computer, it is used to interact with your computer system via CLI (command line interface).\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is CLI?",
|
||||
@@ -450,7 +455,7 @@
|
||||
"description": "Performance monitoring is the systematic observation and measurement of an IT system's operational efficiency and effectiveness. It involves collecting, analyzing, and reporting on key performance indicators (KPIs) across various components including applications, networks, servers, and databases. This process uses specialized tools to track metrics such as response time, throughput, resource utilization, and error rates. Performance monitoring helps identify bottlenecks, predict potential issues, and optimize system resources. It's crucial for maintaining service level agreements (SLAs), ensuring user satisfaction, and supporting capacity planning. In modern IT environments, performance monitoring often incorporates real-time analytics, AI-driven insights, and automated alerting systems, enabling proactive management of complex, distributed systems and supporting continuous improvement in IT operations and service delivery.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Linux commands: exploring virtual memory with vmstat",
|
||||
"title": "Linux Commands: Exploring Virtual Memory with vmstat",
|
||||
"url": "https://www.redhat.com/sysadmin/linux-commands-vmstat",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -567,18 +572,13 @@
|
||||
},
|
||||
"Jt8BmtLUH6fHT2pGKoJs3": {
|
||||
"title": "Vim / Nano / Emacs",
|
||||
"description": "Text editors are software tools used for creating, editing, and managing text files. They range from simple editors with basic features to complex Integrated Development Environments (IDEs). Popular text editors include:\n\n* **Notepad**: A basic editor for Windows, suitable for simple text files.\n* **Vim**: A highly configurable and powerful editor known for its efficiency and modal interface.\n* **Emacs**: A versatile editor with extensive customization options and a wide range of plugins.\n* **Sublime Text**: A feature-rich editor with a focus on speed and a user-friendly interface.\n* **Visual Studio Code**: A modern, open-source editor with built-in support for debugging, extensions, and integration with various development tools.\n\nEach editor offers different features, such as syntax highlighting, code completion, and version control integration, catering to diverse needs in programming and text processing. Visit the following resources to learn more:",
|
||||
"description": "Text editors are software tools used for creating, editing, and managing text files. They range from simple editors with basic features to complex Integrated Development Environments (IDEs). Popular text editors include:\n\n* **Notepad**: A basic editor for Windows, suitable for simple text files.\n* **Vim**: A highly configurable and powerful editor known for its efficiency and modal interface.\n* **Emacs**: A versatile editor with extensive customization options and a wide range of plugins.\n* **Sublime Text**: A feature-rich editor with a focus on speed and a user-friendly interface.\n* **Visual Studio Code**: A modern, open-source editor with built-in support for debugging, extensions, and integration with various development tools.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Vim",
|
||||
"url": "https://www.vim.org",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Vim Adventures",
|
||||
"url": "https://vim-adventures.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GNU Nano",
|
||||
"url": "https://www.nano-editor.org/",
|
||||
@@ -589,6 +589,11 @@
|
||||
"url": "https://www.gnu.org/software/emacs/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Vim Adventures",
|
||||
"url": "https://vim-adventures.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Vim Tutorial for Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=RZ4p-saaQkc",
|
||||
@@ -611,7 +616,7 @@
|
||||
"description": "Version control systems (VCS) are tools that track changes to code and files over time, enabling multiple users to collaborate on projects, maintain history, and manage different versions of codebases. They help in tracking modifications, merging changes, and resolving conflicts. There are two main types of VCS: centralized and distributed. Centralized systems (like Subversion and CVS) rely on a single central repository, while distributed systems (like Git and Mercurial) allow each user to have a complete copy of the repository, including its history. Distributed VCSs, such as Git, are particularly popular for their flexibility, branching capabilities, and robust support for collaborative workflows.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Learn Git & GitHub",
|
||||
"title": "Visit Dedicated Git & GitHub Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -652,7 +657,7 @@
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Learn Git & GitHub",
|
||||
"title": "Visit Dedicated Git & GitHub Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -709,13 +714,13 @@
|
||||
"description": "GitHub is a web-based platform for version control and collaboration using Git. It provides cloud-based Git repository hosting, offering features like bug tracking, task management, and project wikis. GitHub facilitates code review through pull requests, supports issue tracking, and enables social coding with features like forking and starring repositories. It offers both public and private repositories, making it popular for open-source projects and private development. GitHub's ecosystem includes integrations with various development tools and CI/CD platforms. With features like GitHub Actions for automation, GitHub Packages for package management, and GitHub Pages for web hosting, it serves as a comprehensive platform for software development workflows, fostering collaboration among developers worldwide. Visit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Learn Git & GitHub",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"title": "GitHub",
|
||||
"url": "https://github.com",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Website",
|
||||
"url": "https://github.com",
|
||||
"title": "Visit Dedicated Git & GitHub Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -742,7 +747,7 @@
|
||||
{
|
||||
"title": "GitLab Website",
|
||||
"url": "https://gitlab.com/",
|
||||
"type": "opensource"
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitLab Documentation",
|
||||
@@ -770,6 +775,11 @@
|
||||
"url": "https://bitbucket.org",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Bitbucket Overview",
|
||||
"url": "https://bitbucket.org/product/guides/getting-started/overview",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Git and Bitbucket Introduction",
|
||||
"url": "https://www.w3schools.com/git/git_intro.asp?remote=bitbucket",
|
||||
@@ -781,7 +791,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Bitbucket tutorial | How to use Bitbucket Cloud",
|
||||
"title": "Bitbucket Tutorial | How to use Bitbucket Cloud",
|
||||
"url": "https://www.youtube.com/watch?v=M44nEyd_5To",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -854,7 +864,7 @@
|
||||
"description": "NGINX is a high-performance, open-source web server, reverse proxy, and load balancer. Known for its efficiency in handling concurrent connections, NGINX uses an event-driven, asynchronous architecture that consumes minimal resources. It excels at serving static content, proxying requests to application servers, and load balancing across multiple backends. NGINX is widely used for its ability to improve website performance, scalability, and security. It supports various protocols including HTTP, HTTPS, SMTP, and WebSocket, and offers features like SSL/TLS termination, caching, and content compression. Popular in both small-scale and enterprise environments, NGINX is a key component in many modern web architectures, particularly in microservices and containerized deployments.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Nginx",
|
||||
"url": "https://nginx.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -885,7 +895,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation(Tomcat 10.0)",
|
||||
"title": "Tomcat Documentation",
|
||||
"url": "https://tomcat.apache.org/tomcat-10.0-doc/index.html",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -948,7 +958,7 @@
|
||||
"description": "Microsoft Internet Information Services (IIS) is a flexible, secure and manageable Web server for hosting anything on the Web. It's an extensible web server created by Microsoft for use with Windows NT family. IIS supports HTTP, HTTPS, FTP, FTPS, SMTP and NNTP. It's been an integral part of the Windows NT family since Windows NT 4.0, and is included with Windows Server versions. IIS features a modular architecture, allowing administrators to customize server functionality. It supports various programming languages and frameworks, particularly [ASP.NET](http://ASP.NET). IIS provides tools for web application deployment, security management, and performance optimization, making it a popular choice for hosting Windows-based web applications in enterprise environments.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Microsoft IIS",
|
||||
"url": "https://www.iis.net/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1026,7 +1036,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "NGINX documentation",
|
||||
"title": "NGINX Documentation",
|
||||
"url": "https://www.nginx.com/resources/glossary/reverse-proxy-server/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1057,7 +1067,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Articles about Containers - The New Stack",
|
||||
"title": "Containers - The New Stack",
|
||||
"url": "https://thenewstack.io/category/containers/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1218,7 +1228,7 @@
|
||||
"description": "Google Cloud is Google's cloud computing service offering, providing over 150 products/services to choose from. It consists of a set of physical assets, such as computers and hard disk drives, and virtual resources, such as virtual machines(VMs), that are contained in Google's data centers. It runs on the same infrastructure that Google uses internally for its end-user products, such as Search, Gmail, Google Drive, and YouTube.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Google Cloud Website",
|
||||
"title": "Google Cloud",
|
||||
"url": "https://cloud.google.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1244,7 +1254,7 @@
|
||||
"description": "DigitalOcean is a cloud infrastructure provider that offers simple, affordable, and developer-friendly virtual private servers, known as \"Droplets.\" It focuses on providing straightforward cloud computing services, including virtual machines, managed databases, object storage, and Kubernetes clusters. DigitalOcean is known for its user-friendly interface, transparent pricing, and extensive documentation, making it popular among developers, startups, and small to medium-sized businesses. The platform emphasizes simplicity and performance, offering features like one-click applications, team management, and a robust API for automation. While not as feature-rich as some larger cloud providers, DigitalOcean's streamlined approach and competitive pricing make it an attractive option for those seeking uncomplicated cloud infrastructure solutions.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "DigitalOcean Website",
|
||||
"title": "DigitalOcean",
|
||||
"url": "https://www.digitalocean.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1270,12 +1280,12 @@
|
||||
"description": "Alibaba Cloud is the cloud computing arm of Alibaba Group, offering a broad range of cloud services and solutions designed to support enterprise IT infrastructure and digital transformation. It provides scalable and flexible cloud computing resources, including virtual machines, storage, databases, and networking. Alibaba Cloud’s services also encompass big data analytics, artificial intelligence, machine learning, and security solutions. Known for its global data center network, it supports businesses with high availability, disaster recovery, and compliance needs. Alibaba Cloud is a key player in the cloud market, particularly in Asia, providing comprehensive tools for businesses to build, deploy, and manage applications and services in the cloud.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Alibaba Cloud Website",
|
||||
"title": "Alibaba Cloud",
|
||||
"url": "https://www.alibabacloud.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Alibaba Cloud Getting Started Guide",
|
||||
"title": "Getting Started with Alibaba Cloud",
|
||||
"url": "https://www.alibabacloud.com/getting-started",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1333,7 +1343,7 @@
|
||||
"description": "Contabo is a German web hosting and dedicated server provider known for offering affordable virtual private servers (VPS) and dedicated servers with high performance specifications. They provide a range of hosting solutions, including shared hosting, VPS, dedicated servers, and storage solutions, catering to both individual developers and businesses. Contabo is particularly popular among budget-conscious users for its competitive pricing on high-resource VPS plans. Their services include features like SSD storage, DDoS protection, and data centers in multiple locations. While not as well-known as some larger cloud providers, Contabo has gained a reputation in the hosting community for offering good value for money, especially for users requiring substantial computing resources at lower costs.\n\nVisit the following link to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Contabo - Official Website",
|
||||
"title": "Contabo",
|
||||
"url": "https://contabo.com/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1365,7 +1375,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "HOw DNS works (comic)",
|
||||
"title": "How DNS Works (comic)",
|
||||
"url": "https://howdns.works/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1557,7 +1567,7 @@
|
||||
"description": "DMARC (Domain-based Message Authentication, Reporting, and Conformance) is an email authentication protocol that builds upon SPF and DKIM to protect against email spoofing and phishing attacks. It allows domain owners to specify how email receivers should handle messages that fail authentication checks. DMARC provides a feedback mechanism for domain owners to receive reports on email authentication results, helping them monitor and improve their email security. By implementing DMARC policies, organizations can enhance their email deliverability, protect their brand reputation, and reduce the likelihood of their domain being used in fraudulent email campaigns. DMARC is widely adopted by major email providers and is considered a crucial component of modern email security strategies.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "DMARC Official Website",
|
||||
"title": "DMARC",
|
||||
"url": "https://dmarc.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1574,7 +1584,7 @@
|
||||
]
|
||||
},
|
||||
"WMuXqa4b5wyRuYAQKQJRj": {
|
||||
"title": "IMAPS",
|
||||
"title": "IMAP",
|
||||
"description": "IMAP (Internet Message Access Protocol) is a standard email protocol that allows email clients to access messages stored on a mail server. Unlike POP3, IMAP keeps emails on the server, enabling access from multiple devices while maintaining synchronization. It supports folder structures, message flagging, and partial message retrieval, making it efficient for managing large volumes of emails. IMAP allows users to search server-side, reducing bandwidth usage. It's designed for long-term mail storage on the server, ideal for users who need to access their email from various devices or locations. IMAP's synchronization capabilities and server-side management features make it the preferred protocol for most modern email systems, especially in mobile and multi-device environments.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
@@ -1740,12 +1750,12 @@
|
||||
"description": "Vercel is a provider of front-end cloud that provides the infrastructure to build, scale, and secure a faster, more personalized web. In other words, it is a cloud platform designed to simplify the deployment process for web applications, particularly those built with modern frameworks like React, Next, etc. where various projects can be deployed by connecting the GitHub repository in Vercel we can deploy the selected GitHub branch to the Vercel domains. Simultaneously, it provides custom domains to deploy code on live servers. These servers contain the `vercel.app` as the suffix in the domain.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Vercel",
|
||||
"url": "https://vercel.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Docs",
|
||||
"title": "Vercel Docs",
|
||||
"url": "https://vercel.com/docs",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1763,7 +1773,7 @@
|
||||
},
|
||||
"l8VAewSEXzoyqYFhoplJj": {
|
||||
"title": "Cloudflare",
|
||||
"description": "Cloudflare is a company that provides a range of services to help protect and accelerate websites and applications. At its core, Cloudflare is a content delivery network (CDN) and a reverse proxy cloud provider. This means that it acts as an intermediary between a website's origin server and its visitors, caching content and filtering out malicious traffic. Cloudflare was founded in July 2009 by Matthew Prince, Lee Holloway, and Michelle Zatlyn. The company was venture-capital funded and submitted its S-1 filing for IPO on the New York Stock Exchange in August 2019. It opened for public trading on September 13, 2019, at $15 per share.\n\nVisit the following resources to learn more:",
|
||||
"description": "Cloudflare is a internet company that provides a range of services to help protect and accelerate websites and applications. At its core, Cloudflare is a content delivery network (CDN) and a reverse proxy cloud provider. This means that it acts as an intermediary between a website's origin server and its visitors, caching content and filtering out malicious traffic. Cloudflare was founded in July 2009 by Matthew Prince, Lee Holloway, and Michelle Zatlyn. The company was venture-capital funded and submitted its S-1 filing for IPO on the New York Stock Exchange in August 2019. It opened for public trading on September 13, 2019, at $15 per share.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Cloudflare",
|
||||
@@ -1834,7 +1844,7 @@
|
||||
"description": "Netlify Functions are serverless functions that allow developers to run server-side code in a JAMstack environment without managing servers. They are built on AWS Lambda and automatically deploy alongside your Netlify site. These functions can handle tasks like API requests, form submissions, and database operations, enabling dynamic functionality in static sites. They support various languages including JavaScript, TypeScript, and Go. Netlify Functions integrate seamlessly with Netlify's deployment pipeline, offering easy development, testing, and production deployment.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Netlify Documentation",
|
||||
"url": "https://docs.netlify.com/platform/primitives/#functions",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1891,12 +1901,12 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "AWS CDK Website",
|
||||
"title": "AWS CDK",
|
||||
"url": "https://aws.amazon.com/cdk/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "AWS CDK Documentation",
|
||||
"url": "https://docs.aws.amazon.com/cdk/index.html",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1912,7 +1922,7 @@
|
||||
"description": "AWS CloudFormation is a infrastructure-as-code service that allows users to define and provision AWS infrastructure resources using templates. These templates, written in JSON or YAML, describe the desired AWS resources and their properties. CloudFormation automates the creation, update, and deletion of resources, ensuring consistent and repeatable deployments across multiple environments. It supports a wide range of AWS services and can manage complex interdependencies between resources. CloudFormation also provides features like change sets for previewing changes, nested stacks for modular designs, and drift detection to identify manual changes. This service enables teams to version control their infrastructure, implement best practices, and streamline the management of AWS resources throughout their lifecycle.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "AWS CloudFormation Website",
|
||||
"title": "AWS CloudFormation",
|
||||
"url": "https://aws.amazon.com/cloudformation/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1959,7 +1969,7 @@
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Terraform Roadmap",
|
||||
"title": "Visit Dedicated Terraform Roadmap",
|
||||
"url": "https://roadmap.sh/terraform",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2119,11 +2129,6 @@
|
||||
"url": "https://www.youtube.com/watch?v=Tz7FsunBbfQ",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Learn Git & GitHub",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Actions Documentation",
|
||||
"url": "https://docs.github.com/en/actions",
|
||||
@@ -2250,12 +2255,12 @@
|
||||
"description": "Drone is an open-source continuous integration (CI) platform built on container technology. It automates building, testing, and deploying code using a simple, YAML-based pipeline configuration stored alongside the source code. Drone executes each step of the CI/CD process in isolated Docker containers, ensuring consistency and reproducibility. It supports multiple version control systems, offers parallel execution of pipeline steps, and provides plugins for integrating with various tools and services. Drone's lightweight, scalable architecture makes it suitable for projects of all sizes, from small teams to large enterprises. Its focus on simplicity and containerization aligns well with modern DevOps practices and microservices architectures.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Drone Website",
|
||||
"title": "Drone",
|
||||
"url": "https://www.drone.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Drone Documentation",
|
||||
"url": "https://docs.drone.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2271,7 +2276,7 @@
|
||||
"description": "TeamCity is a continuous integration (CI) and continuous delivery (CD) server developed by JetBrains, designed to automate the build, test, and deployment processes in software development. It supports multiple languages and frameworks, offering a flexible and scalable environment for managing pipelines. TeamCity provides powerful features like version control integration, build chaining, parallel execution, and detailed reporting. It also offers a user-friendly web interface, customizable build configurations, and extensive plugin support, making it a popular choice for teams aiming to streamline their CI/CD workflows.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "TeamCity Documentation",
|
||||
"url": "https://www.jetbrains.com/help/teamcity/teamcity-documentation.html",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2380,7 +2385,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Vault - Official Website",
|
||||
"title": "HashiCorp Vault",
|
||||
"url": "https://www.vaultproject.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2448,7 +2453,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Zabbix Documentation",
|
||||
"url": "https://www.zabbix.com/manuals",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2490,7 +2495,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Datadog Documentation",
|
||||
"url": "https://docs.datadoghq.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2506,7 +2511,7 @@
|
||||
"description": "Grafana is an open-source analytics and interactive visualization web application. It connects to various data sources, including time-series databases, relational databases, and cloud services, to create customizable dashboards. Grafana excels at visualizing time-series data for infrastructure and application analytics, supporting a wide range of chart types and plugins. It features alerting capabilities, user authentication, and role-based access control. Grafana is commonly used for monitoring system metrics, application performance, and business analytics. Its flexibility and ability to combine data from multiple sources make it popular in DevOps environments for creating comprehensive monitoring solutions. Grafana's user-friendly interface and extensive customization options enable users to create visually appealing and informative dashboards for real-time data visualization and analysis.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Grafana Website",
|
||||
"title": "Grafana",
|
||||
"url": "https://grafana.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2553,7 +2558,7 @@
|
||||
"description": "The Elastic Stack, formerly known as ELK Stack, is a set of open-source tools for searching, analyzing, and visualizing data in real-time. It consists of four main components: Elasticsearch (a distributed search and analytics engine), Logstash (a data processing pipeline), Kibana (a data visualization and management tool), and Beats (lightweight data shippers). Together, these tools enable users to collect data from various sources, process and enrich it, store it in a searchable format, and create interactive visualizations and dashboards. The Elastic Stack is widely used for log analytics, application performance monitoring, security information and event management (SIEM), and business intelligence applications, offering scalability and flexibility for handling large volumes of diverse data.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Elastic Stack Website",
|
||||
"title": "Elastic Stack",
|
||||
"url": "https://www.elastic.co/elastic-stack/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2605,7 +2610,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Splunk Documentation",
|
||||
"url": "https://docs.splunk.com/Documentation",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2636,12 +2641,12 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Guides",
|
||||
"title": "Papertrail Guides",
|
||||
"url": "https://www.papertrail.com/solution/guides/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Blog",
|
||||
"title": "Papertrail Blog",
|
||||
"url": "https://www.papertrail.com/blog/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2666,6 +2671,11 @@
|
||||
"url": "https://kubernetes.io/docs/tutorials/kubernetes-basics/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Docker Swarm",
|
||||
"url": "https://docs.docker.com/engine/swarm/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Introduction to Kubernetes",
|
||||
"url": "https://www.youtube.com/watch?v=PH-2FfFD2PU",
|
||||
@@ -2810,7 +2820,7 @@
|
||||
},
|
||||
"ootuLJfRXarVvm3J1Ir11": {
|
||||
"title": "Nexus",
|
||||
"description": "The Nexus Repository Manager is a widely used repository manager software developed by Sonatype. It's designed to manage binary components such as Java libraries, Docker images, npm packages, NuGet packages, and more. Nexus Repository Manager allows organizations to store, manage, and distribute software components securely and efficiently.",
|
||||
"description": "The Nexus Repository Manager is a widely used repository manager software developed by Sonatype. It's designed to manage binary components such as Java libraries, Docker images, npm packages, NuGet packages, and more. Nexus Repository Manager allows organizations to store, manage, and distribute software components securely and efficiently.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Repository Management Basics",
|
||||
@@ -2897,7 +2907,7 @@
|
||||
"description": "FluxCD is a GitOps-based continuous delivery tool for Kubernetes. It automates the deployment of applications by using Git repositories as the source of truth for defining the desired state of a system. FluxCD continuously monitors these repositories and automatically applies changes to the cluster when differences are detected. It supports multi-tenancy, Helm releases, and provides features like automated image updates and notifications. FluxCD enables declarative, version-controlled infrastructure and application management, promoting consistency across environments and simplifying the deployment process. Its integration with Kubernetes makes it particularly useful for cloud-native applications, allowing teams to implement efficient, automated, and auditable deployment workflows.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Flux CD Docs",
|
||||
"title": "Flux CD",
|
||||
"url": "https://docs.fluxcd.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2918,12 +2928,12 @@
|
||||
"description": "A service mesh is a dedicated infrastructure layer that manages communication between microservices in a distributed application. It provides features like load balancing, service discovery, encryption, observability, and traffic management, allowing services to communicate securely and efficiently. By abstracting network-related concerns from the application code, a service mesh enhances reliability and security while simplifying the management of microservice interactions. Popular service mesh implementations include Istio, Linkerd, and Consul.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Whats a service mesh?",
|
||||
"title": "Whats a Service Mesh?",
|
||||
"url": "https://www.redhat.com/en/topics/microservices/what-is-a-service-mesh",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The latest news about service mesh (TNS)",
|
||||
"title": "The Latest News About Service Mesh (TNS)",
|
||||
"url": "https://thenewstack.io/category/service-mesh/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2933,7 +2943,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Istio & Service Mesh - simply explained in 15 mins",
|
||||
"title": "Istio & Service Mesh - Simply Explained in 15 mins",
|
||||
"url": "https://www.youtube.com/watch?v=16fgzklcF7Y",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -3016,14 +3026,14 @@
|
||||
"title": "Envoy",
|
||||
"description": "Originally created at Lyft, Envoy is a high-performance data plane designed for service mesh architectures. Lyft open sourced it and donated it to the CNCF, where it is now one of the CNCF’s graduated open source projects. Envoy is a self contained process that is designed to run alongside every application server. All of the Envoys form a transparent communication mesh in which each application sends and receives messages to and from localhost and is unaware of the network topology.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Envoy Website",
|
||||
"url": "https://www.envoyproxy.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "envoyproxy/envoy",
|
||||
"url": "https://github.com/envoyproxy/envoy",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Envoy",
|
||||
"url": "https://www.envoyproxy.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -3048,7 +3058,7 @@
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"title": "Cloud Design Patterns",
|
||||
"url": "https://learn.microsoft.com/en-us/azure/architecture/patterns/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -3133,12 +3143,12 @@
|
||||
"description": "Loki is a horizontally-scalable, highly-available, multi-tenant log aggregation system designed by Grafana Labs. It's purpose-built to be cost-effective and easy to operate, making it particularly well-suited for storing and querying logs from Kubernetes clusters. Loki indexes metadata about logs rather than the full text, which allows it to be more resource-efficient than traditional log management systems. It uses the same querying language as Prometheus (LogQL), making it easier for users familiar with Prometheus to adopt. Loki integrates seamlessly with Grafana for visualization and is often used alongside Prometheus and Grafana in cloud-native observability stacks. Its design focuses on simplicity, making it an attractive option for organizations looking for efficient log management in containerized environments.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Loki Website",
|
||||
"title": "Loki",
|
||||
"url": "https://grafana.com/oss/loki/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Loki Documentation",
|
||||
"url": "https://grafana.com/docs/loki/latest/?pg=oss-loki&plcmt=quick-links",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -3163,6 +3173,11 @@
|
||||
"url": "https://github.com/kubernetes/kubernetes",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Visit Dedicated Kubernetes Roadmap",
|
||||
"url": "https://roadmap.sh/kubernetes",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Kubernetes Website",
|
||||
"url": "https://kubernetes.io/",
|
||||
@@ -3252,12 +3267,12 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Jaeger Website",
|
||||
"title": "Jaeger",
|
||||
"url": "https://www.jaegertracing.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Jaeger Documentation",
|
||||
"url": "https://www.jaegertracing.io/docs/1.37/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -3265,10 +3280,10 @@
|
||||
},
|
||||
"pk76Us6z8LoX3f0mhnCyR": {
|
||||
"title": "New Relic",
|
||||
"description": "New Relic is a cloud-based observability platform that provides full-stack visibility into software applications and infrastructure. It offers real-time performance monitoring, analytics, and alerting across various environments, including web, mobile, and cloud applications. New Relic's suite includes tools for application performance monitoring (APM), infrastructure monitoring, log management, and digital customer experience tracking. It uses distributed tracing and AI-powered analytics to help developers and operations teams identify and resolve issues quickly. New Relic's platform supports a wide range of programming languages and integrates with many popular development and deployment tools, making it a comprehensive solution for modern software observability and performance optimization in DevOps environments. Visit the following resources to learn more:",
|
||||
"description": "New Relic is a cloud-based observability platform that provides full-stack visibility into software applications and infrastructure. It offers real-time performance monitoring, analytics, and alerting across various environments, including web, mobile, and cloud applications. New Relic's suite includes tools for application performance monitoring (APM), infrastructure monitoring, log management, and digital customer experience tracking. It uses distributed tracing and AI-powered analytics to help developers and operations teams identify and resolve issues quickly. New Relic's platform supports a wide range of programming languages and integrates with many popular development and deployment tools, making it a comprehensive solution for modern software observability and performance optimization in DevOps environments.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "New Relic Website",
|
||||
"title": "New Relic",
|
||||
"url": "https://newrelic.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -3294,7 +3309,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Datadog Documentation",
|
||||
"url": "https://docs.datadoghq.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -3315,7 +3330,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Prometheus Documentation",
|
||||
"url": "https://prometheus.io/docs/introduction/overview/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -3341,7 +3356,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "OpenTelemetry Documentation",
|
||||
"url": "https://opentelemetry.io/docs/",
|
||||
"type": "article"
|
||||
},
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
{
|
||||
"_hYN0gEi9BL24nptEtXWU": {
|
||||
"title": "What is Engineering Management?",
|
||||
"description": "",
|
||||
"links": []
|
||||
"description": "Engineering management is the integration of engineering principles with business practices to oversee and optimize complex engineering-driven enterprises. It involves planning, organizing, allocating resources, and directing activities that have a technological component.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Engineering Management Resources",
|
||||
"url": "https://github.com/engineering-management/awesome-engineering-management",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"oKbeLp4YB8rI1Q3vi0EnG": {
|
||||
"title": "EM vs Tech Lead vs IC",
|
||||
@@ -181,7 +187,7 @@
|
||||
},
|
||||
"ZyNbSBd8plAZ5lt5OEUYu": {
|
||||
"title": "Cross-functional Collaboration",
|
||||
"description": "",
|
||||
"description": "One key responsibility of Engineering Managers is to establish clear communication across organisational functions, as they often have greater context and understanding of high-level processes. The job of establishing working cross-functional collaboration often includes defining areas of responsibility, formalising the communication streams, aligning goals, and resolving conflicts between teams.\n\nOne of the common symptoms of poor cross-functional collaboration is when team members are blocked by other teams. To tackle this, teams need a culture of open communication and trust that surfaces problems as early as possible. After problem is identified at a team level, Engineering Manager steps in and collaborates with other managers to improve the situation or escalate it to higher levels when necessary.\n\nEffective cross-functional collaboration establishes clearer expectations from all organisation functions and improves predictability of all participants.\n\nAs an example of tooling for cross-functional collaboration, teams can have publicly available Service Level Agreements (SLAs) or well-documented external communication processes. These tools help external teams set clearer expectations when working with the team, reducing ambiguity and friction.",
|
||||
"links": []
|
||||
},
|
||||
"4v5yLKYVcMh0s7SQuf__C": {
|
||||
|
||||
@@ -170,6 +170,11 @@
|
||||
"title": "HTML",
|
||||
"description": "HTML (Hypertext Markup Language) is the standard markup language used to create web pages and web applications. It provides a structure for content on the World Wide Web, using a system of elements and attributes to define the layout and content of a document. HTML elements are represented by tags, which browsers interpret to render the visual and auditory elements of a web page. The language has evolved through several versions, with HTML5 being the current standard, introducing semantic elements, improved multimedia support, and enhanced form controls. HTML works in conjunction with CSS for styling and JavaScript for interactivity, forming the foundation of modern web development.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Responsive Web Design Certification - Co-Learn HTML & CSS with guided projects",
|
||||
"url": "https://www.freecodecamp.org/learn/2022/responsive-web-design/",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "W3Schools: Learn HTML",
|
||||
"url": "https://www.w3schools.com/html/html_intro.asp",
|
||||
@@ -321,6 +326,11 @@
|
||||
"url": "https://www.youtube.com/watch?v=G3e-cpL7ofc",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Responsive Web Design Certification - Co-Learn HTML & CSS with guided projects",
|
||||
"url": "https://www.freecodecamp.org/learn/2022/responsive-web-design/",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Web.dev by Google — Learn CSS",
|
||||
"url": "https://web.dev/learn/css/",
|
||||
@@ -520,15 +530,10 @@
|
||||
"description": "Repo hosting services provide platforms for storing, managing, and collaborating on software projects using version control systems, primarily Git. These services offer features like issue tracking, pull requests, code review tools, wikis, and continuous integration/continuous deployment (CI/CD) pipelines. Popular platforms include GitHub, GitLab, Bitbucket, and SourceForge, each with unique offerings. GitHub, owned by Microsoft, is the largest and most widely used, known for its open-source community. GitLab offers a complete DevOps platform with built-in CI/CD. Bitbucket, part of Atlassian's suite, integrates well with other Atlassian tools. These services facilitate team collaboration, code sharing, and project management, making them integral to modern software development workflows. They also often provide features like access control, branch protection, and integration with various development tools, enhancing the overall development process.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Learn Git & Github",
|
||||
"title": "Visit Dedicated Git & Github Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Codeberg Website",
|
||||
"url": "https://codeberg.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Website",
|
||||
"url": "https://github.com",
|
||||
@@ -539,6 +544,11 @@
|
||||
"url": "https://about.gitlab.com",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Codeberg Website",
|
||||
"url": "https://codeberg.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "BitBucket Website",
|
||||
"url": "https://bitbucket.com",
|
||||
@@ -551,7 +561,7 @@
|
||||
"description": "Version Control Systems (VCS) are tools that help developers track and manage changes to code over time. They allow multiple people to work on a project simultaneously, maintaining a history of modifications. Git is the most popular VCS, known for its distributed nature and branching model. Other systems include Subversion (SVN) and Mercurial. VCS enables features like branching for parallel development, merging to combine changes, and reverting to previous states. They facilitate collaboration through remote repositories, pull requests, and code reviews. VCS also provides backup and recovery capabilities, conflict resolution, and the ability to tag specific points in history. By maintaining a detailed record of changes and supporting non-linear development, VCS has become an essential tool in modern software development, enhancing productivity, code quality, and team collaboration.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Learn Git & Github",
|
||||
"title": "Visit Dedicated Git & Github Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -765,7 +775,12 @@
|
||||
},
|
||||
{
|
||||
"title": "NPM Website",
|
||||
"url": "https://www.npmjs.com/https://www.npmjs.com/",
|
||||
"url": "https://www.npmjs.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "NPM Documentation",
|
||||
"url": "https://docs.npmjs.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -779,7 +794,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "NPM tutorial for Beginners",
|
||||
"title": "NPM Tutorial for Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=2V1UUhBJ62Y",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -812,7 +827,7 @@
|
||||
},
|
||||
{
|
||||
"title": "Getting started with Angular",
|
||||
"url": "https://angular.io/start",
|
||||
"url": "https://angular.dev/tutorials/learn-angular",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -1091,6 +1106,11 @@
|
||||
"url": "https://sass-lang.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Online Sass Playground",
|
||||
"url": "https://sass-lang.com/playground/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Sass Tutorial for Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=_a5j7KoflTs",
|
||||
@@ -1234,10 +1254,15 @@
|
||||
"description": "Webpack is a popular open-source JavaScript module bundler that transforms, bundles, or packages resources for the web. It takes modules with dependencies and generates static assets representing those modules. Webpack can handle not just JavaScript, but also other assets like CSS, images, and fonts. It uses loaders to preprocess files and plugins to perform a wider range of tasks like bundle optimization. Webpack's key features include code splitting, lazy loading, and a rich ecosystem of extensions. It supports hot module replacement for faster development and tree shaking to eliminate unused code. While it has a steeper learning curve compared to some alternatives, Webpack's flexibility and powerful features make it a standard tool in many modern JavaScript development workflows, especially for complex applications.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Webpack Website",
|
||||
"title": "Webpack",
|
||||
"url": "https://webpack.js.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Getting Started with Webpack",
|
||||
"url": "https://webpack.js.org/guides/getting-started/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "A Complete Guide to Webpack 5",
|
||||
"url": "https://www.valentinog.com/blog/webpack",
|
||||
@@ -1282,12 +1307,12 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "Vite - The Build Tool for the Web",
|
||||
"url": "https://vitejs.dev",
|
||||
"url": "https://vite.dev",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Vite Documentation",
|
||||
"url": "https://vitejs.dev/guide/",
|
||||
"url": "https://vite.dev/guide/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
@@ -1592,11 +1617,6 @@
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Google Devs Content Security Policy (CSP)",
|
||||
"url": "https://developers.google.com/web/fundamentals/security/csp",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Web.dev - Content Security Policy (CSP)",
|
||||
"url": "https://web.dev/csp/",
|
||||
@@ -1755,7 +1775,7 @@
|
||||
"description": "TypeScript is a strongly-typed, object-oriented programming language that builds upon JavaScript by adding optional static typing and other features. Developed and maintained by Microsoft, it compiles to plain JavaScript, allowing it to run in any environment that supports JavaScript. TypeScript offers enhanced IDE support with better code completion, refactoring, and error detection during development. It introduces concepts like interfaces, generics, and decorators, enabling more robust software architecture. TypeScript is particularly valuable for large-scale applications, as it improves code maintainability and readability. Its type system helps catch errors early in the development process, reducing runtime errors. With its growing ecosystem and adoption in popular frameworks like Angular, TypeScript has become a standard tool in modern web development.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "TypeScript Roadmap",
|
||||
"title": "Visit Dedicated TypeScript Roadmap",
|
||||
"url": "https://roadmap.sh/typescript",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1874,19 +1894,24 @@
|
||||
"description": "Angular is a popular open-source web application framework developed and maintained by Google. It uses TypeScript, a statically typed superset of JavaScript, to build scalable and efficient single-page applications (SPAs). Angular follows a component-based architecture, where the user interface is composed of reusable, self-contained components. The framework provides features like two-way data binding, dependency injection, and a powerful template syntax, which simplify the development of complex web applications. Angular also includes a comprehensive set of tools for testing, routing, and state management, making it a full-fledged solution for front-end development. Its modular structure and emphasis on best practices make it particularly suitable for large-scale enterprise applications.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Angular Roadmap",
|
||||
"title": "Visit Dedicated Angular Roadmap",
|
||||
"url": "https://roadmap.sh/angular",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Angular Website",
|
||||
"url": "https://angular.dev",
|
||||
"title": "Getting started with Angular",
|
||||
"url": "https://angular.dev/tutorials/learn-angular",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about Angular",
|
||||
"url": "https://app.daily.dev/tags/angular?ref=roadmapsh",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Angular for Beginners Course",
|
||||
"url": "https://www.youtube.com/watch?v=3qBXWUpoPHo",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1989,12 +2014,12 @@
|
||||
"description": "SvelteKit is a framework for building web applications using Svelte, a component-based JavaScript framework. It provides a full-stack development experience, handling both server-side and client-side rendering. SvelteKit offers features like file-based routing, code-splitting, and server-side rendering out of the box. It supports both static site generation and server-side rendering, allowing developers to choose the most appropriate approach for each page. SvelteKit emphasizes simplicity and performance, leveraging Svelte's compile-time approach to generate highly optimized JavaScript. It includes built-in development tools, easy deployment options, and integrates well with various backend services. SvelteKit's efficient development experience and flexibility make it an attractive option for building modern, performant web applications.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Svelte Kit Website",
|
||||
"title": "Svelte Kit",
|
||||
"url": "https://kit.svelte.dev/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Svelte Kit Docs",
|
||||
"title": "Svelte Kit Docs",
|
||||
"url": "https://kit.svelte.dev/docs/introduction",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2124,7 +2149,7 @@
|
||||
"description": "VuePress is a static site generator powered by Vue.js, primarily designed for creating documentation websites. It generates pre-rendered static HTML for each page, resulting in fast loading times and SEO-friendly content. VuePress features a Vue-powered theming system, automatic code syntax highlighting, and a default theme optimized for technical documentation. It supports markdown content with Vue components, allowing for dynamic and interactive documentation. VuePress offers built-in search functionality, responsive layouts, and easy customization through plugins and themes. While primarily used for documentation, it's versatile enough for blogs and simple websites. VuePress's combination of simplicity, performance, and Vue.js integration makes it popular for creating modern, fast-loading documentation sites and technical blogs.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Vuepress",
|
||||
"url": "https://vuepress.vuejs.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2134,7 +2159,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Whats VuePress?",
|
||||
"title": "What is VuePress?",
|
||||
"url": "https://www.youtube.com/watch?v=iRhRdY7SQJg",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -2197,7 +2222,7 @@
|
||||
"description": "Eleventy (11ty) is a simple to use, easy to customize, highly performant and powerful static site generator with a helpful set of plugins (e.g. navigation, build-time image transformations, cache assets). Pages can be built and written with a variety of template languages (HTML, Markdown, JavaScript, Liquid, Nunjucks, Handlebars, Mustache, EJS, Haml, Pug or JS template literals). But it also offers the possibility to dynamically create pages from local data or external sources that are compiled at build time. It has zero client-side JavaScript dependencies.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Eleventy",
|
||||
"url": "https://www.11ty.dev/",
|
||||
"type": "article"
|
||||
},
|
||||
|
||||
@@ -135,13 +135,18 @@
|
||||
},
|
||||
"We2APJpOPTr-VNfowG0kI": {
|
||||
"title": "Git",
|
||||
"description": "[Git](https://git-scm.com/) is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.\n\nVisit the following resources to learn more:",
|
||||
"description": "Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Visit Dedicated Git & Github Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Git Documentation",
|
||||
"url": "https://git-scm.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Learn Git with Tutorials, News and Tips - Atlassian",
|
||||
"url": "https://www.atlassian.com/git",
|
||||
@@ -174,9 +179,9 @@
|
||||
"description": "GitHub is a provider of Internet hosting for software development and version control using Git. It offers the distributed version control and source code management functionality of Git, plus its own features.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "GitHub Website",
|
||||
"title": "GitHub",
|
||||
"url": "https://github.com",
|
||||
"type": "opensource"
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Documentation",
|
||||
@@ -225,7 +230,7 @@
|
||||
"description": "CSS Framework that provides atomic CSS classes to help you style components e.g. `flex`, `pt-4`, `text-center` and `rotate-90` that can be composed to build any design, directly in your markup.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Tailwind CSS Website",
|
||||
"title": "Tailwind CSS",
|
||||
"url": "https://tailwindcss.com",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -248,11 +253,6 @@
|
||||
"title": "Should You Use Tailwind CSS?",
|
||||
"url": "https://www.youtube.com/watch?v=hdGsFpZ0J2E",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Official Screencasts",
|
||||
"url": "https://www.youtube.com/c/TailwindLabs/videos",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -266,12 +266,12 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "React Website",
|
||||
"title": "React",
|
||||
"url": "https://react.dev/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Getting Started",
|
||||
"title": "Getting Started with React",
|
||||
"url": "https://react.dev/learn/tutorial-tic-tac-toe",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -384,7 +384,7 @@
|
||||
"description": "JWT stands for JSON Web Token is a token-based encryption open standard/methodology that is used to transfer information securely as a JSON object. Clients and Servers use JWT to securely share information, with the JWT containing encoded JSON objects and claims. JWTs are designed to be compact, safe to use within URLs, and ideal for SSO contexts.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "jwt.io Website",
|
||||
"title": "jwt.io",
|
||||
"url": "https://jwt.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -422,7 +422,7 @@
|
||||
},
|
||||
"Onfd7Sl8LG2sjh2aQY7gb": {
|
||||
"title": "Redis",
|
||||
"description": "Redis is an open source (BSD licensed), in-memory **data structure store** used as a database, cache, message broker, and streaming engine. Redis provides data structures such as [strings](https://redis.io/topics/data-types-intro#strings), [hashes](https://redis.io/topics/data-types-intro#hashes), [lists](https://redis.io/topics/data-types-intro#lists), [sets](https://redis.io/topics/data-types-intro#sets), [sorted sets](https://redis.io/topics/data-types-intro#sorted-sets) with range queries, [bitmaps](https://redis.io/topics/data-types-intro#bitmaps), [hyperloglogs](https://redis.io/topics/data-types-intro#hyperloglogs), [geospatial indexes](https://redis.io/commands/geoadd), and [streams](https://redis.io/topics/streams-intro). Redis has built-in [replication](https://redis.io/topics/replication), [Lua scripting](https://redis.io/commands/eval), [LRU eviction](https://redis.io/topics/lru-cache), [transactions](https://redis.io/topics/transactions), and different levels of [on-disk persistence](https://redis.io/topics/persistence), and provides high availability via [Redis Sentinel](https://redis.io/topics/sentinel) and automatic partitioning with [Redis Cluster](https://redis.io/topics/cluster-tutorial).\n\nVisit the following resources to learn more:",
|
||||
"description": "Redis is an open source (BSD licensed), in-memory data structure store used as a database, cache, message broker, and streaming engine. Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions, and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Visit Dedicated Redis Roadmap",
|
||||
@@ -470,6 +470,11 @@
|
||||
"url": "https://www.coursera.org/courses?query=unix",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Visit Dedicated Linux Roadmap",
|
||||
"url": "https://roadmap.sh/linux",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Linux Basics",
|
||||
"url": "https://dev.to/rudrakshi99/linux-basics-2onj",
|
||||
@@ -536,11 +541,6 @@
|
||||
"url": "https://youtu.be/TUTqYEZZUdc",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Sam Meech-Ward's AWS Videos",
|
||||
"url": "https://www.youtube.com/playlist?list=PL0X6fGhFFNTcU-_MCPe9dkH6sqmgfhy_M",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "DNS with AWS Route 53",
|
||||
"url": "https://www.youtube.com/watch?v=yRIY7BJohfo",
|
||||
@@ -550,18 +550,18 @@
|
||||
"title": "Upload Images to S3 from Node Back End",
|
||||
"url": "https://www.youtube.com/watch?v=NZElg91l_ms",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "S3 Bucket Hosting a Static Website",
|
||||
"url": "https://www.youtube.com/watch?v=RoY3ekCCxKc&list=PL0X6fGhFFNTcU-_MCPe9dkH6sqmgfhy_M",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
"6oBIxYj8WPcUHidQ99tus": {
|
||||
"title": "EC2",
|
||||
"description": "Amazon Elastic Compute Cloud (EC2) is a web service that provides resizable compute capacity in the form of virtual servers, known as instances. With EC2, you can quickly scale your infrastructure up or down as your computing requirements change. This service effectively reduces the time required to obtain and boot new server instances, allowing you to easily adjust capacity according to the needs of your application.",
|
||||
"description": "Amazon Elastic Compute Cloud (EC2) is a web service that provides resizable compute capacity in the form of virtual servers, known as instances. With EC2, you can quickly scale your infrastructure up or down as your computing requirements change. This service effectively reduces the time required to obtain and boot new server instances, allowing you to easily adjust capacity according to the needs of your application.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Amazon AWS EC2",
|
||||
"url": "https://aws.amazon.com/ec2/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Up and Running with AWS EC2",
|
||||
"url": "https://cs.fyi/guide/up-and-running-with-aws-ec2",
|
||||
@@ -586,8 +586,13 @@
|
||||
},
|
||||
"QtL-bLKtWIdH00K6k_PdC": {
|
||||
"title": "VPC",
|
||||
"description": "VPC stands for **Virtual Private Cloud** and is an essential service provided by AWS that allows you to create a private, isolated section within the AWS cloud, where you can define your own virtual network. It offers a more secure and controlled environment, enabling you to easily launch and manage your resources within your personal network.",
|
||||
"description": "VPC stands for **Virtual Private Cloud** and is an essential service provided by AWS that allows you to create a private, isolated section within the AWS cloud, where you can define your own virtual network. It offers a more secure and controlled environment, enabling you to easily launch and manage your resources within your personal network.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Amazon AWS VPC",
|
||||
"url": "https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Up and Running with AWS VPC",
|
||||
"url": "https://cs.fyi/guide/up-and-running-with-aws-vpc",
|
||||
@@ -607,8 +612,13 @@
|
||||
},
|
||||
"5zyYpu9cyuTFwQCjTbHpS": {
|
||||
"title": "Route53",
|
||||
"description": "[Route53](https://aws.amazon.com/route53/) is AWS's Domain Name System (DNS) service that plays a critical role in connecting user requests to your web application or other resources within your infrastructure. With Route53, you can easily manage domains, redirect traffic, and configure domain-related settings. It has several advantages, including high availability, low latency, and integration with other AWS resources.",
|
||||
"description": "Route53 is AWS's Domain Name System (DNS) service that plays a critical role in connecting user requests to your web application or other resources within your infrastructure. With Route53, you can easily manage domains, redirect traffic, and configure domain-related settings. It has several advantages, including high availability, low latency, and integration with other AWS resources.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Route53",
|
||||
"url": "https://aws.amazon.com/route53/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Amazon Route 53",
|
||||
"url": "https://www.youtube.com/watch?v=RGWgfhZByAI",
|
||||
@@ -628,8 +638,13 @@
|
||||
},
|
||||
"B-cphY7Imnv6JBMujVIF7": {
|
||||
"title": "SES",
|
||||
"description": "Amazon SES (Simple Email Service) is a scalable, flexible, and cost-effective cloud-based email service that is specifically designed for developers, marketers, and businesses to send and receive marketing, transactional, and notification emails. SES is useful, especially when you need to send a large volume of emails, as it offers high deliverability, reliability, and ease of use.",
|
||||
"description": "Amazon SES (Simple Email Service) is a scalable, flexible, and cost-effective cloud-based email service that is specifically designed for developers, marketers, and businesses to send and receive marketing, transactional, and notification emails. SES is useful, especially when you need to send a large volume of emails, as it offers high deliverability, reliability, and ease of use.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Amazon AWS SES",
|
||||
"url": "https://aws.amazon.com/ses/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Contact Form Submission With AWS SES",
|
||||
"url": "https://www.youtube.com/watch?v=HiHflLTqiwU",
|
||||
@@ -639,8 +654,13 @@
|
||||
},
|
||||
"n2Xp_ijJ2OS8xhE7xMWxk": {
|
||||
"title": "S3",
|
||||
"description": "S3 is a service that allows you to store files in the cloud. It's a simple service that you can use to store files and serve them to your users.",
|
||||
"description": "S3 is a service that allows you to store files in the cloud. It's a simple service that you can use to store files and serve them to your users.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Amazon AWS S3",
|
||||
"url": "https://aws.amazon.com/s3/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about AWS S3",
|
||||
"url": "https://app.daily.dev/tags/aws-s3?ref=roadmapsh",
|
||||
@@ -660,15 +680,15 @@
|
||||
},
|
||||
"y1SFX7uvWaCy4OYBnECLu": {
|
||||
"title": "Monit",
|
||||
"description": "When it comes to monitoring the health of your applications, there are several different options available. My favorite monitoring stack is Prometheus and Grafana, but it can be a bit overwhelming to set up and configure. If you're looking for a simpler solution, **Monit** is a great alternative that can be utilized to monitor and manage system resources such as services, processes, files, directories, devices, and network connections, making your application more reliable and resilient to issues like crashes, unresponsiveness, or resource exhaustion.\n\nSome of the key features of Monit are:\n\n* **Automatic Recovery:** Monit can automatically restart a service or process if it fails, making your application more resistant to unexpected issues.\n* **Alert Notifications:** Monit can send email notifications when a problem is detected or when a certain condition is met, keeping you informed about the health of your application.\n* **Event Logging:** All events detected by Monit are stored in a log for easy troubleshooting and analysis.\n* **Resource Limit Monitoring:** Monit can monitor the resource utilization (CPU, memory, network, etc.) of a process or service and take action if a specific limit is exceeded.\n* **Flexible Configuration:** Monit uses a simple, human-readable configuration syntax that allows you to tailor its behavior to your needs.\n* **Web Interface:** Monit provides a built-in web interface for remotely monitoring your application's status and manage services.\n\nHave a look at the following resources to learn more about Monit:",
|
||||
"description": "When it comes to monitoring the health of your applications, there are several different options available. My favorite monitoring stack is Prometheus and Grafana, but it can be a bit overwhelming to set up and configure. If you're looking for a simpler solution, **Monit** is a great alternative that can be utilized to monitor and manage system resources such as services, processes, files, directories, devices, and network connections, making your application more reliable and resilient to issues like crashes, unresponsiveness, or resource exhaustion.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Monit Website",
|
||||
"title": "Monit",
|
||||
"url": "https://mmonit.com/monit/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Monit documentation",
|
||||
"title": "Monit Documentation",
|
||||
"url": "https://mmonit.com/monit/documentation/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -733,18 +753,18 @@
|
||||
},
|
||||
"863KMXcFJzInvTp_-Ldmz": {
|
||||
"title": "GitHub Actions",
|
||||
"description": "GitHub Actions is a workflow automation tool provided by GitHub that can be used to automate various tasks in the app development process.",
|
||||
"description": "GitHub Actions is a workflow automation tool provided by GitHub that can be used to automate various tasks in the app development process.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Github Actions",
|
||||
"url": "https://github.com/features/actions",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Visit Dedicated Git & Github Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Github Actions",
|
||||
"url": "https://github.com/features/actions",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Github Actions Documentation",
|
||||
"url": "https://docs.github.com/en/actions",
|
||||
@@ -777,12 +797,12 @@
|
||||
"description": "Ansible is an open-source configuration management, application deployment and provisioning tool that uses its own declarative language in YAML. Ansible is agentless, meaning you only need remote connections via SSH or Windows Remote Management via Powershell in order to function\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Ansible Website",
|
||||
"title": "Ansible",
|
||||
"url": "https://www.ansible.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Ansible Documentation",
|
||||
"url": "https://docs.ansible.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -828,33 +848,13 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terraform Tutorials",
|
||||
"url": "https://learn.hashicorp.com/terraform",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terraform CDK Website",
|
||||
"title": "Terraform CDK",
|
||||
"url": "https://www.terraform.io/cdktf",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is the CDKTF?",
|
||||
"url": "https://www.terraform.io/cdktf/concepts/cdktf-architecture",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "CDKTF Getting Started Guide",
|
||||
"url": "https://learn.hashicorp.com/tutorials/terraform/cdktf-install?in=terraform/cdktf",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "CDKTF Examples",
|
||||
"url": "https://www.terraform.io/cdktf/examples",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to Scale Your Terraform Infrastructure",
|
||||
"url": "https://thenewstack.io/how-to-scale-your-terraform-infrastructure/",
|
||||
"title": "Terraform Tutorials",
|
||||
"url": "https://learn.hashicorp.com/terraform",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -599,16 +599,16 @@
|
||||
},
|
||||
"vWLKYK2KUzV1fO-vQunzW": {
|
||||
"title": "EPA",
|
||||
"description": "The **EPA**, also known as the _Environmental Protection Agency_, is not typically related to game development or the concept of intersection within this context. However, in game development, EPA might refer to an 'Event-driven Process chain Architecture' or some other game-specific acronym. In this domain, different terminologies and acronyms are often used to express complex architectures, designs, or functionalities. If you have encountered EPA in a game development context, it might be best to refer to the specific documentation or guide where it was described for a better understanding. Understanding the context is key to untangle the meaning of such abbreviations.\n\nVisit the following resources to learn more:",
|
||||
"description": "The **EPA** (Expanding Polytope Algorithm) is an iterative algorithm used for calculating the penetration depth between two shapes in collision detection. It is commonly used in physics engines and robotics. The algorithm takes the resulting simplex from a previously applied GJK algorithm, iteratively expanding the polytope towards the Minkowski Difference boundary until it finds the closest point to the origin. The vector from that point to the origin is the penetration vector and its magnitude is equal to the penetration depth between the two shapes.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Environmental Sustainability in Game Development",
|
||||
"url": "https://polydin.com/environmental-sustainability-in-game-development/",
|
||||
"title": "EPA: Collision response algorithm for 2D/3D - winter.dev",
|
||||
"url": "https://winter.dev/articles/epa-algorithm",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Gaming Sustainability - Microsoft Game Dev",
|
||||
"url": "https://learn.microsoft.com/en-us/gaming/sustainability/sustainability-overview",
|
||||
"title": "EPA (Expanding Polytope Algorithm) - dyn4j",
|
||||
"url": "https://dyn4j.org/2010/05/epa-expanding-polytope-algorithm/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1023,16 +1023,16 @@
|
||||
},
|
||||
"XteNExIZN3_g95_dPCopY": {
|
||||
"title": "Exitting / Exit Codes",
|
||||
"description": "`Exiting` is a way of terminating a Node.js process by using node.js process module.\n\nVisit the following resources to learn more:",
|
||||
"description": "Exiting is a way of terminating a Node.js process by using node.js process module.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Node.js Docs on exit",
|
||||
"url": "https://nodejs.org/docs/latest/api/process.html",
|
||||
"title": "Exit Documentation",
|
||||
"url": "https://nodejs.org/api/process.html#event-exit",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to Exit a Process in Node.js",
|
||||
"url": "https://www.knowledgehut.com/blog/web-development/node-js-process-exit",
|
||||
"url": "https://betterstack.com/community/questions/how-to-exit-in-node-js/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
|
||||
1409
public/roadmap-content/php.json
Normal file
1409
public/roadmap-content/php.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,18 @@
|
||||
{
|
||||
"lDIy56RyC1XM7IfORsSLD": {
|
||||
"title": "Introduction",
|
||||
"description": "PostgreSQL is a powerful, open-source Object-Relational Database Management System (ORDBMS) that is known for its robustness, extensibility, and SQL compliance. It was initially developed at the University of California, Berkeley, in the 1980s and has since become one of the most popular open-source databases in the world.",
|
||||
"description": "PostgreSQL is a powerful, open-source Object-Relational Database Management System (ORDBMS) that is known for its robustness, extensibility, and SQL compliance. It was initially developed at the University of California, Berkeley, in the 1980s and has since become one of the most popular open-source databases in the world.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL",
|
||||
"url": "https://www.postgresql.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL Documentation",
|
||||
"url": "https://www.postgresql.org/docs/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "History of POSTGRES to PostgreSQL",
|
||||
"url": "https://www.postgresql.org/docs/current/history.html",
|
||||
@@ -15,7 +25,22 @@
|
||||
"description": "Relational databases are a type of database management system (DBMS) that stores and organizes data in a structured format called tables. These tables are made up of rows, also known as records or tuples, and columns, which are also called attributes or fields. The term \"relational\" comes from the fact that these tables can be related to one another through keys and relationships.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Relational Databases: concept and history",
|
||||
"title": "Databases and SQL",
|
||||
"url": "https://www.edx.org/course/databases-5-sql",
|
||||
"type": "course"
|
||||
},
|
||||
{
|
||||
"title": "Relational Databases",
|
||||
"url": "https://www.ibm.com/cloud/learn/relational-databases",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Intro To Relational Databases",
|
||||
"url": "https://www.udacity.com/course/intro-to-relational-databases--ud197",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Relational Databases: Concept and History",
|
||||
"url": "https://www.ibm.com/topics/relational-databases",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -81,13 +106,35 @@
|
||||
},
|
||||
"-M9EFgiDSSAzj9ISk-aeh": {
|
||||
"title": "Basic RDBMS Concepts",
|
||||
"description": "Relational Database Management Systems (RDBMS) are a type of database management system which stores and organizes data in tables, making it easy to manipulate, query, and manage the information. They follow the relational model defined by E.F. Codd in 1970, which means that data is represented as tables with rows and columns.",
|
||||
"links": []
|
||||
"description": "Relational Database Management Systems (RDBMS) are a type of database management system which stores and organizes data in tables, making it easy to manipulate, query, and manage the information. They follow the relational model defined by E.F. Codd in 1970, which means that data is represented as tables with rows and columns.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Understanding Relational Database Management Systems",
|
||||
"url": "https://www.essentialsql.com/understanding-relational-databases-a-beginners-guide/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"RoYP1tYw5dvhmkVTo1HS-": {
|
||||
"title": "Object Model",
|
||||
"description": "PostgreSQL is an object-relational database management system (ORDBMS). That means it combines features of both relational (RDBMS) and object-oriented databases (OODBMS). The object model in PostgreSQL provides features like user-defined data types, inheritance, and polymorphism, which enhances its capabilities beyond a typical SQL-based RDBMS.",
|
||||
"links": []
|
||||
"description": "PostgreSQL is an object-relational database management system (ORDBMS). That means it combines features of both relational (RDBMS) and object-oriented databases (OODBMS). The object model in PostgreSQL provides features like user-defined data types, inheritance, and polymorphism, which enhances its capabilities beyond a typical SQL-based RDBMS.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Object Model",
|
||||
"url": "https://www.postgresql.org/docs/current/tutorial-concepts.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Understanding PostgreSQL: The Power of an Object-Relational",
|
||||
"url": "https://medium.com/@asadbukhari886/understanding-of-postgresql-the-power-of-an-object-relational-database-b6ae349c3f40",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL Server and Database Objects",
|
||||
"url": "https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-server-and-database-objects/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"xVocG4LuFdtphwoOxiJTa": {
|
||||
"title": "Queries",
|
||||
@@ -102,7 +149,7 @@
|
||||
},
|
||||
"4Pw7udOMIsiaKr7w9CRxc": {
|
||||
"title": "Data Types",
|
||||
"description": "PostgreSQL offers a rich and diverse set of data types, catering to a wide range of applications and ensuring data integrity and performance. These include standard numeric types such as integers, floating-point numbers, and serial types for auto-incrementing fields. Character types like VARCHAR and TEXT handle varying lengths of text, while DATE, TIME, and TIMESTAMP support a variety of temporal data requirements. PostgreSQL also supports a comprehensive set of Boolean, enumerated (ENUM), and composite types, enabling more complex data structures. Additionally, it excels with its support for JSON and JSONB data types, allowing for efficient storage and querying of semi-structured data. The inclusion of array types, geometric data types, and the PostGIS extension for geographic data further extends PostgreSQL's versatility, making it a powerful tool for a broad spectrum of data management needs.\n\nLearn more from the following resources:",
|
||||
"description": "PostgreSQL offers a rich and diverse set of data types, catering to a wide range of applications and ensuring data integrity and performance. These include standard numeric types such as integers, floating-point numbers, and serial types for auto-incrementing fields. Character types like `VARCHAR` and `TEXT` handle varying lengths of text, while DATE, TIME, and TIMESTAMP support a variety of temporal data requirements. PostgreSQL also supports a comprehensive set of Boolean, enumerated (ENUM), and composite types, enabling more complex data structures. Additionally, it excels with its support for JSON and JSONB data types, allowing for efficient storage and querying of semi-structured data. The inclusion of array types, geometric data types, and the PostGIS extension for geographic data further extends PostgreSQL's versatility, making it a powerful tool for a broad spectrum of data management needs.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Data Types",
|
||||
@@ -110,7 +157,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "An introduction to PostgreSQL data types",
|
||||
"title": "Introduction to PostgreSQL DataTypes",
|
||||
"url": "https://www.prisma.io/dataguide/postgresql/introduction-to-data-types",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -129,6 +176,11 @@
|
||||
"title": "Concepts",
|
||||
"url": "https://www.postgresql.org/docs/7.1/query-concepts.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL - Rows",
|
||||
"url": "https://www.postgresql.org/docs/current/functions-comparisons.html",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -164,13 +216,13 @@
|
||||
"description": "Schemas are an essential part of PostgreSQL's object model, and they help provide structure, organization, and namespacing for your database objects. A schema is a collection of database objects, such as tables, views, indexes, and functions, that are organized within a specific namespace.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is a schema in PostgreSQL",
|
||||
"url": "https://hasura.io/learn/database/postgresql/core-concepts/1-postgresql-schema/",
|
||||
"title": "Schemas",
|
||||
"url": "https://www.postgresql.org/docs/current/ddl-schemas.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Schemas",
|
||||
"url": "https://www.postgresql.org/docs/current/ddl-schemas.html",
|
||||
"title": "Schema in PostgreSQL",
|
||||
"url": "https://hasura.io/learn/database/postgresql/core-concepts/1-postgresql-schema/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -193,8 +245,19 @@
|
||||
},
|
||||
"mDVbjdVN0spY7dI_8k1YW": {
|
||||
"title": "Relational Model",
|
||||
"description": "The relational model is an approach to organizing and structuring data using tables, also referred to as \"relations\". It was first introduced by Edgar F. Codd in 1970 and has since become the foundation for most database management systems (DBMS), including PostgreSQL. This model organizes data into tables with rows and columns, where each row represents a single record and each column represents an attribute or field of the record.\n\nThe core concepts of the relational model include:\n\n* **Attributes:** An attribute is a column within a table that represents a specific characteristic or property of an entity, such as \"name\", \"age\", \"email\", etc.\n \n* **Tuples:** A tuple is a single row within a table that represents a specific instance of an entity with its corresponding attribute values.\n \n* **Relations:** A relation is a table that consists of a set of tuples with the same attributes. It represents the relationship between entities and their attributes.\n \n* **Primary Key:** A primary key is a unique identifier for each tuple within a table. It enforces the uniqueness of records and is used to establish relationships between tables.\n \n* **Foreign Key:** A foreign key is an attribute within a table that references the primary key of another table. It is used to establish and enforce connections between relations.\n \n* **Normalization:** Normalization is a process of organizing data in a way to minimize redundancy and improve data integrity. It involves decomposing complex tables into simpler tables, ensuring unique records, and properly defining foreign keys.\n \n* **Data Manipulation Language (DML):** DML is a subset of SQL used to perform operations on data stored within the relational database, such as INSERT, UPDATE, DELETE, and SELECT.\n \n* **Data Definition Language (DDL):** DDL is another subset of SQL used to define, modify, or delete database structures, such as CREATE, ALTER, and DROP.\n \n\nBy understanding and implementing the relational model, databases can achieve high-level data integrity, reduce data redundancy, and simplify the process of querying and manipulating data. PostgreSQL, as an RDBMS (Relational Database Management System), fully supports the relational model, enabling users to efficiently and effectively manage their data in a well-structured and organized manner.",
|
||||
"links": []
|
||||
"description": "The relational model is an approach to organizing and structuring data using tables, also referred to as \"relations\". It was first introduced by Edgar F. Codd in 1970 and has since become the foundation for most database management systems (DBMS), including PostgreSQL. This model organizes data into tables with rows and columns, where each row represents a single record and each column represents an attribute or field of the record.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is the Relational Model?",
|
||||
"url": "https://www.postgresql.org/docs/7.1/relmodel-oper.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The Relational Model",
|
||||
"url": "https://www.geeksforgeeks.org/relational-model-in-dbms/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"-LuxJvI5IaOx6NqzK0d8S": {
|
||||
"title": "Domains",
|
||||
@@ -217,7 +280,7 @@
|
||||
"description": "Attributes in the relational model are the columns of a table, representing the properties or characteristics of the entity described by the table. Each attribute has a domain, defining the possible values it can take, such as integer, text, or date. Attributes play a crucial role in defining the schema of a relation (table) and are used to store and manipulate data. They are fundamental in maintaining data integrity, enforcing constraints, and enabling the relational operations that form the basis of SQL queries.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is a relational Model?",
|
||||
"title": "What is a Relational Model?",
|
||||
"url": "https://www.guru99.com/relational-data-model-dbms.html",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -230,32 +293,32 @@
|
||||
},
|
||||
"vJhvgGwNV3JB-wWn_0gMb": {
|
||||
"title": "Tuples",
|
||||
"description": "In the relational model, a **tuple** is a fundamental concept that represents a single record or row in a table. In PostgreSQL, a tuple is composed of a set of attribute values, each corresponding to a specific column or field in the table. A tuple is defined as an ordered set of attribute values, meaning that each value in a tuple corresponds to a specific attribute or column in the table. The values can be of different data types, such as integers, strings, or dates, depending on the schema of the table.\n\nFor example, consider a `users` table with columns `id`, `name`, and `email`. A sample tuple in this table could be `(1, 'John Smith', 'john.smith@example.com')`, where each value corresponds to its respective column. PostgreSQL provides a variety of operations that can be performed on tuples, which can be classified into three main categories:\n\n* **Projection**: This operation involves selecting one or more attributes from a tuple and creating a new tuple with only the selected attributes. For example, projecting the `name` and `email` attributes from the previously mentioned tuple would result in `('John Smith', 'john.smith@example.com')`.\n \n* **Selection**: Selection involves filtering tuples based on a specific condition. For example, you may want to select all tuples from the `users` table where the `email` attribute ends with \"@example.com\".\n \n* **Join**: The join operation combines tuples from two or more tables based on a common attribute or condition. For example, if we have another table called `orders` with a `user_id` column, we could use a join operation to retrieve all records from both tables where the `users.id` attribute matches the `orders.user_id`.\n \n\nLearn more from the following resources:",
|
||||
"description": "In the relational model, a **tuple** is a fundamental concept that represents a single record or row in a table. In PostgreSQL, a tuple is composed of a set of attribute values, each corresponding to a specific column or field in the table. A tuple is defined as an ordered set of attribute values, meaning that each value in a tuple corresponds to a specific attribute or column in the table. The values can be of different data types, such as integers, strings, or dates, depending on the schema of the table.\n\nFor example, consider a `users` table with columns `id`, `name`, and `email`. A sample tuple in this table could be `(1, 'John Smith', 'john.smith@example.com')`, where each value corresponds to its respective column. PostgreSQL provides a variety of operations that can be performed on tuples.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Whats the difference between and tuple and a row?",
|
||||
"url": "https://stackoverflow.com/questions/19799282/whats-the-difference-between-a-tuple-and-a-row-in-postgres",
|
||||
"title": "How PostgreSQL Freezes Tuples",
|
||||
"url": "https://medium.com/@hnasr/how-postgres-freezes-tuples-4a9931261fc",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How PostgreSQL freezes tuples",
|
||||
"url": "https://medium.com/@hnasr/how-postgres-freezes-tuples-4a9931261fc",
|
||||
"title": "Whats the difference between and tuple and a row?",
|
||||
"url": "https://stackoverflow.com/questions/19799282/whats-the-difference-between-a-tuple-and-a-row-in-postgres",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2hM2IPAnNYq-LlEbcFp2Z": {
|
||||
"title": "Relations",
|
||||
"description": "In the relational model, a relation is essentially a table composed of rows and columns, where each row represents a unique record (or tuple) and each column represents an attribute of the data. The structure of a relation is defined by its schema, which specifies the relation's name and the names and data types of its attributes. Relations are governed by integrity constraints, such as domain constraints, key constraints, and referential integrity constraints, to ensure data accuracy and consistency. Operations like selection, projection, join, and others can be performed on relations to retrieve and manipulate data efficiently.",
|
||||
"description": "In the relational model, a relation is essentially a table composed of rows and columns, where each row represents a unique record (or tuple) and each column represents an attribute of the data. The structure of a relation is defined by its schema, which specifies the relation's name and the names and data types of its attributes. Relations are governed by integrity constraints, such as domain constraints, key constraints, and referential integrity constraints, to ensure data accuracy and consistency. Operations like selection, projection, join, and others can be performed on relations to retrieve and manipulate data efficiently.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Relationships",
|
||||
"url": "https://hasura.io/learn/database/postgresql/core-concepts/6-postgresql-relationships/",
|
||||
"title": "Domain Constraints",
|
||||
"url": "https://www.postgresql.org/docs/current/infoschema-domain-constraints.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "domain_contraints",
|
||||
"url": "https://www.postgresql.org/docs/current/infoschema-domain-constraints.html",
|
||||
"title": "Relationships",
|
||||
"url": "https://hasura.io/learn/database/postgresql/core-concepts/6-postgresql-relationships/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -265,12 +328,12 @@
|
||||
"description": "Constraints are an essential part of the relational model, as they define rules that the data within the database must follow. They ensure that the data is consistent, accurate, and reliable.\n\n**Primary Key** - A primary key constraint is a column or a set of columns that uniquely identifies each row in a table. There can only be one primary key per table, and its value must be unique and non-null for each row.\n\n**Foreign Key** - A foreign key constraint ensures that a column or columns in a table refer to an existing row in another table. It helps maintain referential integrity between tables.\n\n**Unique** - A unique constraint ensures that the values in a column or set of columns are unique across all rows in a table. In other words, it prevents duplicate entries in the specified column(s).\n\n**Check** - A check constraint verifies that the values entered into a column meet a specific condition. It helps to maintain data integrity by restricting the values that can be inserted into a column.\n\n**Not Null** - A NOT NULL constraint enforces that a column cannot contain a NULL value. This ensures that a value must be provided for the specified column when inserting or updating data in the table.\n\n**Exclusion** - An exclusion constraint is a more advanced form of constraint that allows you to specify conditions that should not exist when comparing multiple rows in a table. It helps maintain data integrity by preventing conflicts in data.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Contraints",
|
||||
"title": "Constraints",
|
||||
"url": "https://www.postgresql.org/docs/current/ddl-constraints.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL - Contraints",
|
||||
"title": "PostgreSQL - Constraints",
|
||||
"url": "https://www.tutorialspoint.com/postgresql/postgresql_constraints.htm",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -278,13 +341,30 @@
|
||||
},
|
||||
"91eOGK8mtJulWRlhKyv0F": {
|
||||
"title": "NULL",
|
||||
"description": "In the relational model used by PostgreSQL, null values represent missing or unknown information within a database. Unlike zero, empty strings, or other default values, null signifies the absence of a value and is treated uniquely in operations and queries. For example, any arithmetic operation involving a null results in a null, and comparisons with null using standard operators return unknown rather than true or false. To handle null values, PostgreSQL provides specific functions and constructs such as `IS NULL`, `IS NOT NULL`, and the `COALESCE` function, which returns the first non-null value in its arguments. Understanding and correctly handling null values is crucial for accurate data retrieval and integrity in relational databases.",
|
||||
"links": []
|
||||
"description": "In the relational model used by PostgreSQL, null values represent missing or unknown information within a database. Unlike zero, empty strings, or other default values, null signifies the absence of a value and is treated uniquely in operations and queries. For example, any arithmetic operation involving a null results in a null, and comparisons with null using standard operators return unknown rather than true or false. To handle null values, PostgreSQL provides specific functions and constructs such as `IS NULL`, `IS NOT NULL`, and the `COALESCE` function, which returns the first non-null value in its arguments. Understanding and correctly handling null values is crucial for accurate data retrieval and integrity in relational databases.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL - NULL",
|
||||
"url": "https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-NULL",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL - NULL Values",
|
||||
"url": "https://www.relationaldbdesign.com/database-analysis/module2/relational-database-null-values.php",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"_BSR2mo1lyXEFXbKYb1ZG": {
|
||||
"title": "High Level Database Concepts",
|
||||
"description": "High-level database concepts encompass fundamental principles that underpin the design, implementation, and management of database systems. These concepts form the foundation of effective database management, enabling the design of robust, efficient, and scalable systems.",
|
||||
"links": []
|
||||
"description": "High-level database concepts encompass fundamental principles that underpin the design, implementation, and management of database systems. These concepts form the foundation of effective database management, enabling the design of robust, efficient, and scalable systems.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Demystifying PostgreSQL: 10 Crucial Concepts and Files",
|
||||
"url": "https://medium.com/@RohitAjaygupta/demystifying-postgresql-10-crucial-concepts-and-files-explained-with-practical-examples-a5a70cd2b848",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"9u7DPbfybqmldisiePq0m": {
|
||||
"title": "ACID",
|
||||
@@ -309,7 +389,7 @@
|
||||
},
|
||||
"-_ADJsTVGAgXq7_-8bdIO": {
|
||||
"title": "MVCC",
|
||||
"description": "Multi-Version Concurrency Control (MVCC) is a technique used by PostgreSQL to allow multiple transactions to access the same data concurrently without conflicts or delays. It ensures that each transaction has a consistent snapshot of the database and can operate on its own version of the data.\n\nLearn more from the following resources:",
|
||||
"description": "Multi-Version Concurrency Control (MVCC) is a technique used by PostgreSQL to allow multiple transactions to access the same data concurrently without conflicts or delays. It ensures that each transaction has a consistent snapshot of the database and can operate on its own version of the data.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Intro to MVCC",
|
||||
@@ -317,7 +397,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Multiversion concurrency control - Wikipedia",
|
||||
"title": "Multi-Version Concurrency Control - Wikipedia",
|
||||
"url": "https://en.wikipedia.org/wiki/Multiversion_concurrency_control",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -367,10 +447,10 @@
|
||||
},
|
||||
"Qk14b9WyeCp9RV9WAwojt": {
|
||||
"title": "Query Processing",
|
||||
"description": "In this section, we will discuss the concept of query processing in PostgreSQL. Query processing is an important aspect of a database system, as it is responsible for managing data retrieval and modification using Structured Query Language (SQL) queries. Efficient query processing is crucial for ensuring optimal database performance.\n\nLearn more from the following resources:",
|
||||
"description": "Query processing is an important aspect of a database system, as it is responsible for managing data retrieval and modification using Structured Query Language (SQL) queries. Efficient query processing is crucial for ensuring optimal database performance.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Understand PostgreSQL query processing - Microsoft",
|
||||
"title": "Understand PostgreSQL Query Processing - Microsoft",
|
||||
"url": "https://learn.microsoft.com/en-us/training/modules/understand-postgresql-query-process/",
|
||||
"type": "course"
|
||||
},
|
||||
@@ -385,6 +465,11 @@
|
||||
"title": "Using Docker",
|
||||
"description": "Docker is an excellent tool for simplifying the installation and management of applications, including PostgreSQL. By using Docker, you can effectively isolate PostgreSQL from your system and avoid potential conflicts with other installations or configurations.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official PostgresSQL Docker Image",
|
||||
"url": "https://hub.docker.com/_/postgres",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to Use the Postgres Docker Official Image",
|
||||
"url": "https://www.docker.com/blog/how-to-use-the-postgres-docker-official-image/",
|
||||
@@ -399,7 +484,7 @@
|
||||
},
|
||||
"pEtQy1nuW98YUwrbfs7Np": {
|
||||
"title": "Package Managers",
|
||||
"description": "Package managers are essential tools that help you install, update, and manage software packages on your system. They keep track of dependencies, handle configuration files and ensure that the installation process is seamless for the end-user.\n\nLearn more from the following resources:",
|
||||
"description": "Package managers are essential tools that help you install, update, and manage software packages on your system. They keep track of dependencies, handle configuration files and ensure that the installation process is seamless for the end-user.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Install PostgreSQL with APT",
|
||||
@@ -438,6 +523,11 @@
|
||||
"title": "Deployment in Cloud",
|
||||
"description": "In this section, we will discuss deploying PostgreSQL in the cloud. Deploying your PostgreSQL database in the cloud offers significant advantages such as scalability, flexibility, high availability, and cost reduction. There are several cloud providers that offer PostgreSQL as a service, which means you can quickly set up and manage your databases without having to worry about underlying infrastructure, backups, and security measures.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "5 Ways to Host PostgreSQL Databases",
|
||||
"url": "https://www.prisma.io/dataguide/postgresql/5-ways-to-host-postgresql",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Postgres On Kubernetes",
|
||||
"url": "https://cloudnative-pg.io/",
|
||||
@@ -492,16 +582,27 @@
|
||||
"description": "`pg_ctlcluster` is a command-line utility provided by PostgreSQL to manage database clusters. It is especially helpful for users who have multiple PostgreSQL clusters running on the same system.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL documentation",
|
||||
"url": "https://www.postgresql.org/docs/current/pgctlcluster.html",
|
||||
"title": "pg_ctlcluster",
|
||||
"url": "https://manpages.ubuntu.com/manpages/focal/man1/pg_ctlcluster.1.html",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"FtPiBWMFhjakyXsmSL_CI": {
|
||||
"title": "Installation and Setup",
|
||||
"description": "",
|
||||
"links": []
|
||||
"description": "To install and set up PostgreSQL, begin by downloading the installer from the official PostgreSQL website for your operating system (Windows, macOS, or Linux). For Windows, run the installer and follow the prompts to configure components, set a password for the superuser (postgres), and choose the installation directory and port (default is 5432). On macOS, using Homebrew is the recommended method; simply run brew install postgresql in the terminal, then initialize the database with brew services start postgresql. For Linux, use the package manager (APT for Debian/Ubuntu or YUM for CentOS/RHEL) to install PostgreSQL, followed by initializing the database and starting the service. After installation, you can access PostgreSQL using the psql command-line tool to create databases and manage your data effectively.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Installing PostgreSQL",
|
||||
"url": "https://www.postgresql.org/download/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL - Installation",
|
||||
"url": "https://www.postgresql.org/docs/current/tutorial-install.html",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ANUgfkADLI_du7iRvnUdi": {
|
||||
"title": "Learn SQL",
|
||||
@@ -511,22 +612,27 @@
|
||||
"title": "Visit Dedicated SQL Roadmap",
|
||||
"url": "https://roadmap.sh/sql",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "SQL Tutorial - Essential SQL For The Beginners",
|
||||
"url": "https://www.sqltutorial.org/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"KMdF9efNGULualk5o1W0_": {
|
||||
"title": "For Schemas",
|
||||
"description": "A schema is a logical collection of database objects within a PostgreSQL database. It behaves like a namespace that allows you to group and isolate your database objects separately from other schemas. The primary goal of a schema is to organize your database structure, making it easier to manage and maintain.\n\nBy default, every PostgreSQL database has a `public` schema, which is the default search path for any unqualified table or other database object.\n\nLearn more from the following resources:",
|
||||
"description": "A schema is a logical collection of database objects within a PostgreSQL database. It behaves like a namespace that allows you to group and isolate your database objects separately from other schemas. The primary goal of a schema is to organize your database structure, making it easier to manage and maintain. By default, every PostgreSQL database has a `public` schema, which is the default search path for any unqualified table or other database object.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL Schema",
|
||||
"url": "https://hasura.io/learn/database/postgresql/core-concepts/1-postgresql-schema/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Schemas",
|
||||
"url": "https://www.postgresql.org/docs/current/ddl-schemas.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL Schema",
|
||||
"url": "https://hasura.io/learn/database/postgresql/core-concepts/1-postgresql-schema/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -598,7 +704,7 @@
|
||||
"description": "Filtering data is an essential feature in any database management system, and PostgreSQL is no exception. When we refer to filtering data, we're talking about selecting a particular subset of data that fulfills specific criteria or conditions. In PostgreSQL, we use the **WHERE** clause to filter data in a query based on specific conditions.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How to filter query results in PostgreSQL",
|
||||
"title": "How to Filter Query Results in PostgreSQL",
|
||||
"url": "https://www.prisma.io/dataguide/postgresql/reading-and-querying-data/filtering-data",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -640,7 +746,7 @@
|
||||
"description": "Joining tables is a fundamental operation in the world of databases. It allows you to combine information from multiple tables based on common columns. PostgreSQL provides various types of joins, such as Inner Join, Left Join, Right Join, and Full Outer Join.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Joins between tables",
|
||||
"title": "Joins Between Tables",
|
||||
"url": "https://www.postgresql.org/docs/current/tutorial-join.html",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -661,7 +767,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Copying data between tables in PostgreSQL",
|
||||
"title": "Copying Data Between Tables in PostgreSQL",
|
||||
"url": "https://www.atlassian.com/data/sql/copying-data-between-tables",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -795,8 +901,19 @@
|
||||
},
|
||||
"T819BZ-CZgUX_BY7Gna0J": {
|
||||
"title": "Configuring",
|
||||
"description": "Configuring PostgreSQL involves modifying several key configuration files to optimize performance, security, and functionality. The primary configuration files are postgresql.conf, pg\\_hba.conf, and pg\\_ident.conf, typically located in the PostgreSQL data directory. By properly configuring these files, you can tailor PostgreSQL to better fit your specific needs and environment.",
|
||||
"links": []
|
||||
"description": "Configuring PostgreSQL involves modifying several key configuration files to optimize performance, security, and functionality. The primary configuration files are postgresql.conf, pg\\_hba.conf, and pg\\_ident.conf, typically located in the PostgreSQL data directory. By properly configuring these files, you can tailor PostgreSQL to better fit your specific needs and environment.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Configuring PostgreSQL",
|
||||
"url": "https://www.postgresql.org/docs/current/runtime-config.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Install and Configure PostgreSQL",
|
||||
"url": "https://ubuntu.com/server/docs/install-and-configure-postgresql",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"yl3gxfQs4nOE0N7uGqR0d": {
|
||||
"title": "Resource Usage",
|
||||
@@ -890,7 +1007,7 @@
|
||||
},
|
||||
"3pLn1mhRnekG537ejHUYA": {
|
||||
"title": "Checkpoints / Background Writer",
|
||||
"description": "In PostgreSQL, checkpoints and the background writer are essential for maintaining data integrity and optimizing performance. Checkpoints periodically write all modified data (dirty pages) from the shared buffers to the disk, ensuring that the database can recover to a consistent state after a crash. This process is controlled by settings such as `checkpoint_timeout`, `checkpoint_completion_target`, and `max_wal_size`, balancing between write performance and recovery time. The background writer continuously flushes dirty pages to disk in the background, smoothing out the I/O workload and reducing the amount of work needed during checkpoints. This helps to maintain steady performance and avoid spikes in disk activity. Proper configuration of these mechanisms is crucial for ensuring efficient disk I/O management and overall database stability.\n\nCheckpoints periodically write all modified data (dirty pages) from the shared buffer cache to the disk, ensuring that the database can recover to a consistent state after a crash. The frequency of checkpoints is controlled by parameters like `checkpoint_timeout`, `checkpoint_completion_target`, and `checkpoint_segments`, balancing the trade-off between I/O load and recovery time.\n\nThe background writer, on the other hand, continuously flushes dirty pages to disk, smoothing out the I/O workload and reducing the amount of work needed during a checkpoint. Parameters such as `bgwriter_delay`, `bgwriter_lru_maxpages`, and `bgwriter_lru_multiplier` control its behavior, optimizing the balance between database performance and the frequency of disk writes. Proper configuration of both components ensures efficient disk I/O management, minimizes performance bottlenecks, and enhances overall system stability.\n\nLearn more from the following resources:",
|
||||
"description": "In PostgreSQL, checkpoints and the background writer are essential for maintaining data integrity and optimizing performance. Checkpoints periodically write all modified data (dirty pages) from the shared buffers to the disk, ensuring that the database can recover to a consistent state after a crash. This process is controlled by settings such as `checkpoint_timeout`, `checkpoint_completion_target`, and `max_wal_size`, balancing between write performance and recovery time. The background writer continuously flushes dirty pages to disk in the background, smoothing out the I/O workload and reducing the amount of work needed during checkpoints. This helps to maintain steady performance and avoid spikes in disk activity. Proper configuration of these mechanisms is crucial for ensuring efficient disk I/O management and overall database stability.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Checkpoints",
|
||||
@@ -914,7 +1031,7 @@
|
||||
"description": "When working with PostgreSQL, it is often useful to analyze the performance of your queries and system as a whole. This can help you optimize your database and spot potential bottlenecks. One way to achieve this is by reporting logging statistics. PostgreSQL provides configuration settings for generating essential logging statistics on query and system performance.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Error reporting and logging",
|
||||
"title": "Error Reporting and Logging",
|
||||
"url": "https://www.postgresql.org/docs/current/runtime-config-logging.html",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -930,7 +1047,7 @@
|
||||
"description": "PostgreSQL provides various extensions to enhance its features and functionalities. Extensions are optional packages that can be loaded into your PostgreSQL database to provide additional functionality like new data types or functions. Using extensions can be a powerful way to add new features to your PostgreSQL database and customize your database's functionality according to your needs.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL extensions",
|
||||
"title": "PostgreSQL Extensions",
|
||||
"url": "https://www.postgresql.org/download/products/6-postgresql-extensions/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -943,20 +1060,31 @@
|
||||
},
|
||||
"2Zg8R5gs9LMQOcOMZtoPk": {
|
||||
"title": "Security",
|
||||
"description": "Securing PostgreSQL involves multiple layers of considerations to protect data and ensure only authorized access.",
|
||||
"links": []
|
||||
"description": "Securing PostgreSQL involves multiple layers of considerations to protect data and ensure only authorized access.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL Database Security Best Practices",
|
||||
"url": "https://www.percona.com/blog/postgresql-database-security-best-practices/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Security - Azure Database for PostgreSQL",
|
||||
"url": "https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-security",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"S20aJB-VuSpXYyd0-0S8c": {
|
||||
"title": "Object Priviliges",
|
||||
"title": "Object Privileges",
|
||||
"description": "Object privileges in PostgreSQL are the permissions given to different user roles to access or modify database objects like tables, views, sequences, and functions. Ensuring proper object privileges is crucial for maintaining a secure and well-functioning database.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL roles and privileges explained",
|
||||
"title": "PostgreSQL Roles and Privileges Explained",
|
||||
"url": "https://www.aviator.co/blog/postgresql-roles-and-privileges-explained/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What are object privileges?",
|
||||
"title": "What are Object Privileges?",
|
||||
"url": "https://www.prisma.io/dataguide/postgresql/authentication-and-authorization/managing-privileges#what-are-postgresql-object-privileges",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -989,7 +1117,7 @@
|
||||
]
|
||||
},
|
||||
"t18XjeHP4uRyERdqhHpl5": {
|
||||
"title": "Default Priviliges",
|
||||
"title": "Default Privileges",
|
||||
"description": "PostgreSQL allows you to define object privileges for various types of database objects. These privileges determine if a user can access and manipulate objects like tables, views, sequences, or functions. In this section, we will focus on understanding default privileges in PostgreSQL.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
@@ -1006,8 +1134,19 @@
|
||||
},
|
||||
"09QX_zjCUajxUqcNZKy0x": {
|
||||
"title": "Advanced Topics",
|
||||
"description": "In addition to basic PostgreSQL security concepts, such as user authentication, privilege management, and encryption, there are several advanced topics that you should be aware of to enhance the security of your PostgreSQL databases.",
|
||||
"links": []
|
||||
"description": "In addition to basic PostgreSQL security concepts, such as user authentication, privilege management, and encryption, there are several advanced topics that you should be aware of to enhance the security of your PostgreSQL databases.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Best Practices for Postgres Security",
|
||||
"url": "https://www.timescale.com/learn/postgres-security-best-practices",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL - Encryption and Monitoring",
|
||||
"url": "https://www.enterprisedb.com/postgresql-best-practices-encryption-monitoring",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bokFf6VNrLcilI9Hid386": {
|
||||
"title": "Row-Level Security",
|
||||
@@ -1046,12 +1185,12 @@
|
||||
"description": "PostgreSQL supports various authentication models to control access, including trust (no password, for secure environments), password-based (md5 and scram-sha-256 for hashed passwords), GSSAPI and SSPI (Kerberos for secure single sign-on), LDAP (centralized user management), certificate-based (SSL certificates for strong authentication), PAM (leveraging OS-managed authentication), Ident (verifying OS user names), and RADIUS (centralized authentication via RADIUS servers). These methods are configured in the `pg_hba.conf` file, specifying the appropriate authentication method for different combinations of databases, users, and client addresses, ensuring flexible and secure access control.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Authentication methods",
|
||||
"title": "Authentication Methods",
|
||||
"url": "https://www.postgresql.org/docs/current/auth-methods.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "An introduction to authorization and authentication in PostgreSQL",
|
||||
"title": "An Introduction to Authorization and Authentication in PostgreSQL",
|
||||
"url": "https://www.prisma.io/dataguide/postgresql/authentication-and-authorization/intro-to-authn-and-authz",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1189,12 +1328,12 @@
|
||||
"description": "Operators in Kubernetes are software extensions that use custom resources to manage applications and their components. They encapsulate operational knowledge and automate complex tasks such as deployments, backups, and scaling. Using Custom Resource Definitions (CRDs) and custom controllers, Operators continuously monitor the state of the application and reconcile it with the desired state, ensuring the system is self-healing and resilient. Popular frameworks for building Operators include the Operator SDK, Kubebuilder, and Metacontroller, which simplify the process and enhance Kubernetes' capability to manage stateful and complex applications efficiently.",
|
||||
"links": [
|
||||
{
|
||||
"title": "Kubernetes Roadmap",
|
||||
"title": "Visit Dedicated Kubernetes Roadmap",
|
||||
"url": "https://roadmap.sh/kubernetes",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Kubernetes Website",
|
||||
"title": "Kubernetes",
|
||||
"url": "https://kubernetes.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1260,7 +1399,7 @@
|
||||
},
|
||||
"xk2G-HUS-dviNW3BAMmJv": {
|
||||
"title": "KeepAlived",
|
||||
"description": "Keepalived is a robust and widely-used open-source solution for load balancing and high availability. It helps to maintain a stable and perfect working environment even in the presence of failures such as server crashes or connectivity issues.\n\nKeepalived achieves this by utilizing the Linux Virtual Server (LVS) module and the Virtual Router Redundancy Protocol (VRRP).\n\nFor PostgreSQL database systems, Keepalived can be an advantageous addition to your infrastructure by offering fault tolerance and load balancing. With minimal configuration, it distributes read-only queries among multiple replicated PostgreSQL servers or divides transaction processing across various nodes – ensuring an efficient and resilient system.\n\nLearn more from the following resources:",
|
||||
"description": "Keepalived is a robust and widely-used open-source solution for load balancing and high availability. It helps to maintain a stable and perfect working environment even in the presence of failures such as server crashes or connectivity issues.\n\nKeepalived achieves this by utilizing the Linux Virtual Server (LVS) module and the Virtual Router Redundancy Protocol (VRRP). For PostgreSQL database systems, Keepalived can be an advantageous addition to your infrastructure by offering fault tolerance and load balancing. With minimal configuration, it distributes read-only queries among multiple replicated PostgreSQL servers or divides transaction processing across various nodes – ensuring an efficient and resilient system.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "acassen/keepalived",
|
||||
@@ -1268,9 +1407,14 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Keepalived Website",
|
||||
"title": "Keepalived",
|
||||
"url": "https://www.keepalived.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Keepalived: High Availability for Self-hosted Services",
|
||||
"url": "https://www.virtualizationhowto.com/2023/09/keepalived-high-availability-for-self-hosted-services/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1278,6 +1422,11 @@
|
||||
"title": "Etcd",
|
||||
"description": "Etcd is a distributed key-value store that provides an efficient and reliable means for storing crucial data across clustered environments. It has become popular as a fundamental component for storing configuration data and service discovery in distributed systems.\n\nEtcd can be utilized in conjunction with _connection poolers_ such as PgBouncer or HAProxy to improve PostgreSQL load balancing. By maintaining a list of active PostgreSQL servers' IP addresses and ports as keys in the store, connection poolers can fetch this information periodically to route client connections to the right servers. Additionally, transactional operations on the store can simplify the process of adding or removing nodes from the load balancer configuration while maintaining consistency.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL High Availability with Etcd",
|
||||
"url": "https://github.com/patroni/patroni",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "etcd vs PostgreSQL",
|
||||
"url": "https://api7.ai/blog/etcd-vs-postgresql",
|
||||
@@ -1316,12 +1465,12 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Zabbix Website",
|
||||
"title": "Zabbix",
|
||||
"url": "https://www.zabbix.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Using Zabbix to monitor your home network",
|
||||
"title": "Using Zabbix to Monitor your Home Network",
|
||||
"url": "https://jswheeler.medium.com/using-zabbix-to-monitor-your-home-network-71ed2b1181ae",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1527,7 +1676,7 @@
|
||||
},
|
||||
"3V1PPIeB0i9qNUsT8-4O-": {
|
||||
"title": "PgBouncer Alternatives",
|
||||
"description": "Pgpool-II\n---------\n\nPgpool-II is another widely-used connection pooler for PostgreSQL. It provides several advanced features, such as load balancing, replication, and limiting connections.\n\n* **Load Balancing** - Pgpool-II can distribute read queries among multiple PostgreSQL servers to balance the read load, helping to improve overall performance.\n* **Replication** - In addition to connection pooling, Pgpool-II can act as a replication tool for creating real-time data backups.\n* **Limiting Connections** - You can set connection limits for clients to control the maximum number of allowed connections for specific users or databases.\n\nHAProxy\n-------\n\nHAProxy is a high-performance and highly-available load balancer for TCP and HTTP-based applications, including PostgreSQL. It is particularly well-suited for distributing connections across multiple PostgreSQL servers for high availability and load balancing.\n\n* **Connection Distribution** - HAProxy uses load balancing algorithms to ensure connections are evenly distributed across the available servers, which can help prevent connection overloading.\n* **Health Checking** - HAProxy can perform periodic health checks on your PostgreSQL servers, which can help to ensure that client connections are redirected to healthy servers.\n* **SSL Support** - HAProxy provides SSL/TLS support, enabling secure connections between clients and PostgreSQL servers.\n\nOdyssey\n-------\n\nOdyssey is an open-source, multithreaded connection pooler for PostgreSQL developed by Yandex. It is designed for high-performance and large-scale deployments and supports features like transparent SSL, load balancing, and advanced routing.\n\n* **High Performance** - Odyssey uses a multithreaded architecture to process its connections, which can help significantly increase its performance compared to single-threaded connection poolers.\n* **Advanced Routing** - Odyssey allows you to configure routing rules and load balancing based on client, server, user, and even specific SQL queries.\n* **Transparent SSL** - Odyssey supports transparent SSL connections between clients and PostgreSQL servers, ensuring secure communication.\n\nLearn more from the following resources:",
|
||||
"description": "Pgpool-II, HAProxy, and Odyssey are prominent tools for enhancing PostgreSQL performance and availability. **Pgpool-II** is a versatile connection pooler offering load balancing, replication, and connection limits to optimize performance. **HAProxy** excels as a load balancer for distributing connections across PostgreSQL servers, featuring health checks and SSL/TLS support for secure, high-availability setups. **Odyssey**, developed by Yandex, is a multithreaded connection pooler designed for high-performance deployments, providing advanced routing, transparent SSL, and load balancing capabilities tailored for large-scale systems.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "yandex/odyssey",
|
||||
@@ -1596,7 +1745,7 @@
|
||||
},
|
||||
"TZvZ_jNjWnM535ZktyhQN": {
|
||||
"title": "Patroni Alternatives",
|
||||
"description": "While Patroni is a popular choice for managing PostgreSQL clusters, there are several other tools and frameworks available that you might consider as alternatives to Patroni. Each of these has its unique set of features and benefits, and some may be better suited to your specific requirements or use-cases.\n\nStolon - Stolon is a cloud-native PostgreSQL manager that automatically ensures high availability and, if required, can seamlessly scale instances. It was developed by the team at Sorint.lab and is written in Go. Some of the main features that differentiate Stolon from other solutions are:\n\nPgpool-II - Pgpool-II is an advanced and powerful PostgreSQL management and load balancing solution, developed by the Pgpool Global Development Group. Pgpool-II not only provides high availability and connection pooling, but also offers a myriad of other features, such as:\n\nRepmgr - Repmgr is an open-source replication management tool for PostgreSQL that has been fully integrated and supported by 2ndQuadrant. It simplifies administration and daily management, providing a robust and easy-to-use solution. The main features of Repmgr include:\n\nPAF (PostgreSQL Automatic Failover) - PAF is an HA (high-availability) resource agent for the Pacemaker and Corosync cluster manager, designed for the PostgreSQL's built-in streaming replication. It was developed by the team at Dalibo and is quite lightweight compared to other alternatives. Key features of PAF include:\n\nLearn more from the following resources:",
|
||||
"description": "While Patroni is a popular choice for managing PostgreSQL clusters, there are several other tools and frameworks available that you might consider as alternatives to Patroni. Each of these has its unique set of features and benefits, and some may be better suited to your specific requirements or use-cases.\n\nSeveral alternatives to Patroni exist for PostgreSQL cluster management, each with unique features catering to specific needs. **Stolon**, a cloud-native manager by Sorint.lab, ensures high availability and seamless scaling. **Pgpool-II**, by the Pgpool Global Development Group, offers load balancing, connection pooling, and high availability. **Repmgr**, developed by 2ndQuadrant, simplifies replication and cluster administration. **PAF (PostgreSQL Automatic Failover)**, created by Dalibo, provides lightweight failover management using Pacemaker and Corosync. These tools present diverse options for managing PostgreSQL clusters effectively.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "dalibo/PAF",
|
||||
@@ -1609,13 +1758,13 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "pgPool Website",
|
||||
"url": "https://www.pgpool.net/mediawiki/index.php/Main_Page",
|
||||
"title": "RepMgr",
|
||||
"url": "https://repmgr.org/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "RepMgr Website",
|
||||
"url": "https://repmgr.org/",
|
||||
"title": "pgPool",
|
||||
"url": "https://www.pgpool.net/mediawiki/index.php/Main_Page",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -1638,15 +1787,31 @@
|
||||
},
|
||||
"e5s7-JRqNy-OhfnjTScZI": {
|
||||
"title": "Learn to Automate",
|
||||
"description": "When working with PostgreSQL, automating repetitive and time-consuming tasks is crucial for increasing efficiency and reliability in your database operations.",
|
||||
"links": []
|
||||
"description": "When working with PostgreSQL, automating repetitive and time-consuming tasks is crucial for increasing efficiency and reliability in your database operations.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL - Automation",
|
||||
"url": "https://www.postgresql.org/docs/current/maintenance.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Autoscaling Azure PostgreSQL Server with Automation Tasks",
|
||||
"url": "https://techcommunity.microsoft.com/blog/adforpostgresql/autoscaling-azure-postgresql-server-with-automation-tasks/3911718",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"-clI2RmfhK8F8beHULaIB": {
|
||||
"title": "Shell Scripts",
|
||||
"description": "Shell scripts are a powerful tool used to automate repetitive tasks and perform complex operations. They are essentially text files containing a sequence of commands to be executed by the shell (such as Bash or Zsh). By leveraging shell scripts with tools such as `cron`, you can efficiently automate tasks related to PostgreSQL and streamline your database administration processes.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Shell scripting tutorial",
|
||||
"title": "Shell Script Cheatsheet",
|
||||
"url": "https://cheatsheets.zip/bash",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Shell Scripting Tutorial",
|
||||
"url": "https://www.tutorialspoint.com/unix/shell_scripting.htm",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1678,7 +1843,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Ansible Website",
|
||||
"title": "Ansible",
|
||||
"url": "https://www.ansible.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1726,12 +1891,12 @@
|
||||
"description": "Puppet is an open-source software configuration management tool that enables system administrators to automate the provisioning, configuration, and management of a server infrastructure. It helps minimize human errors, ensures consistency across multiple systems, and simplifies the process of managing PostgreSQL installations.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Puppet documentation",
|
||||
"title": "Puppet Documentation",
|
||||
"url": "https://puppet.com/docs/puppet/latest/index.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Puppet PostgreSQL module documentation",
|
||||
"title": "Puppet PostgreSQL Module Documentation",
|
||||
"url": "https://forge.puppet.com/modules/puppetlabs/postgresql/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1779,13 +1944,13 @@
|
||||
"description": "Bulk load process data involves transferring large volumes of data from external files into the PostgreSQL database. This is an efficient way to insert massive amounts of data into your tables quickly, and it's ideal for initial data population or data migration tasks. Leveraging the `COPY` command or `pg_bulkload` utility in combination with best practices should help you load large datasets swiftly and securely.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "7 Best Practice Tips for PostgreSQL Bulk Data Loading",
|
||||
"url": "https://www.enterprisedb.com/blog/7-best-practice-tips-postgresql-bulk-data-loading",
|
||||
"title": "Populating a Database",
|
||||
"url": "https://www.postgresql.org/docs/current/populate.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Populating a Database",
|
||||
"url": "https://www.postgresql.org/docs/current/populate.html",
|
||||
"title": "7 Best Practice Tips for PostgreSQL Bulk Data Loading",
|
||||
"url": "https://www.enterprisedb.com/blog/7-best-practice-tips-postgresql-bulk-data-loading",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -1800,7 +1965,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to use table partitioning to scale PostgreSQL",
|
||||
"title": "How to use Table Partitioning to Scale PostgreSQL",
|
||||
"url": "https://www.enterprisedb.com/postgres-tutorials/how-use-table-partitioning-scale-postgresql",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -2129,12 +2294,12 @@
|
||||
"description": "Recursive CTEs are a powerful feature in SQL that allow you to build complex hierarchical queries, retrieve data stored in hierarchical structures or even perform graph traversal. In simple terms, a recursive CTE is a CTE that refers to itself in its own definition, creating a loop that iterates through the data until a termination condition is met.\n\nNote that recursive CTEs can be complex, and it's important to ensure a proper termination condition to avoid infinite recursion. Also, be careful with the use of `UNION ALL` or `UNION`, as it may impact the results and the performance of your query.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL Recursive Query",
|
||||
"title": "PostgreSQL - Recursive Query",
|
||||
"url": "https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-recursive-query/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL recursive query explained",
|
||||
"title": "PostgreSQL Recursive Query Explained",
|
||||
"url": "https://elvisciotti.medium.com/postgresql-recursive-query-the-simplest-example-explained-f9b85e0a371b",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -2161,7 +2326,7 @@
|
||||
"description": "`top` is a command-line utility that comes pre-installed on most Unix-based operating systems such as Linux, macOS, and BSD. It provides a dynamic, real-time view of the processes running on a system, displaying valuable information like process ID, user, CPU usage, memory usage, and more.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How to use the top command in Linux",
|
||||
"title": "How to Use the top Command in Linux",
|
||||
"url": "https://phoenixnap.com/kb/top-command-in-linux",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2336,7 +2501,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Awk command in Linux/Unix",
|
||||
"title": "Awk Command in Linux/Unix",
|
||||
"url": "https://www.digitalocean.com/community/tutorials/awk-command-linux-unix",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2478,7 +2643,7 @@
|
||||
},
|
||||
"UZ1vRFRjiQAVu6BygqwEL": {
|
||||
"title": "explain.dalibo.com",
|
||||
"description": "[explain.dalibo.com](http://explain.dalibo.com) is a free service that allows you to analyze the execution plan of your queries. It is based on the [explain.depesz.com](explain.depesz.com) service.\n\nLearn more from the following resources:",
|
||||
"description": "[explain.dalibo.com](http://explain.dalibo.com) is a free service that allows you to analyze the execution plan of your queries. It is based on the [explain.depesz.com](http://explain.depesz.com) service.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "explain.dalibo.com",
|
||||
@@ -2558,8 +2723,14 @@
|
||||
},
|
||||
"G9DB1ZQjgXaHxJ4Lm6xGx": {
|
||||
"title": "SQL Query Patterns / Anti-patterns",
|
||||
"description": "Schema query patterns in PostgreSQL optimize data retrieval and manipulation by using indexes on frequently queried columns to speed up SELECT queries, optimizing joins with indexed foreign keys and appropriate join types, and leveraging table partitioning to limit data scans. Common Table Expressions (CTEs) break down complex queries for better readability and maintainability, while window functions allow advanced analytics within queries. Query caching and prepared statements reduce access times and execution overhead, respectively, and materialized views precompute and store complex query results for faster access. These patterns collectively enhance the efficiency, performance, and reliability of PostgreSQL queries.",
|
||||
"links": []
|
||||
"description": "Schema query patterns in PostgreSQL optimize data retrieval and manipulation by using indexes on frequently queried columns to speed up SELECT queries, optimizing joins with indexed foreign keys and appropriate join types, and leveraging table partitioning to limit data scans. Common Table Expressions (CTEs) break down complex queries for better readability and maintainability, while window functions allow advanced analytics within queries. Query caching and prepared statements reduce access times and execution overhead, respectively, and materialized views precompute and store complex query results for faster access. These patterns collectively enhance the efficiency, performance, and reliability of PostgreSQL queries.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "PostgreSQL - Query Patterns",
|
||||
"url": "https://www.postgresql.org/docs/current/functions-matching.html",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Dhhyg23dBMyAKCFwZmu71": {
|
||||
"title": "Indexes and their Usecases",
|
||||
@@ -2635,13 +2806,13 @@
|
||||
"description": "Generalized Inverted Index (GIN) is a powerful indexing method in PostgreSQL that can be used for complex data types such as arrays, text search, and more. GIN provides better search capabilities for non-traditional data types, while also offering efficient and flexible querying.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Generalized Inverted Indexes",
|
||||
"url": "https://www.cockroachlabs.com/docs/stable/inverted-indexes",
|
||||
"title": "GIN Introduction",
|
||||
"url": "https://www.postgresql.org/docs/current/gin-intro.html",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GIN Introduction",
|
||||
"url": "https://www.postgresql.org/docs/current/gin-intro.html",
|
||||
"title": "Generalized Inverted Indexes",
|
||||
"url": "https://www.cockroachlabs.com/docs/stable/inverted-indexes",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -2669,13 +2840,60 @@
|
||||
},
|
||||
"8H7hJhGKxr1nrjkHv9Xao": {
|
||||
"title": "Mailing Lists",
|
||||
"description": "Mailing lists are an essential part of PostgreSQL's development community. They provide a platform for collaboration, discussion, and problem-solving. By participating in these lists, you can contribute to the development of PostgreSQL, share your knowledge with others, and stay informed about the latest updates, improvements, and conferences.\n\nHere are some prominent mailing lists in PostgreSQL's development community:\n\n* **pgsql-hackers**: This is the primary mailing list for PostgreSQL's core development. It is intended for discussions around new features, patches, performance improvements, and bug fixes. To subscribe, visit [pgsql-hackers Subscription](https://www.postgresql.org/list/pgsql-hackers/).\n \n* **pgsql-announce**: This mailing list is for official announcements regarding new PostgreSQL releases, security updates, and other important events. To stay updated, you can subscribe at [pgsql-announce Subscription](https://www.postgresql.org/list/pgsql-announce/).\n \n* **pgsql-general**: The pgsql-general mailing list is for general discussions related to PostgreSQL, including usage, administration, configuration, and SQL queries. Subscribe at [pgsql-general Subscription](https://www.postgresql.org/list/pgsql-general/).\n \n* **pgsql-novice**: This mailing list is specifically designed for PostgreSQL beginners who need help or advice. If you're new to PostgreSQL, consider joining this community by subscribing at [pgsql-novice Subscription](https://www.postgresql.org/list/pgsql-novice/).\n \n* **pgsql-docs**: If you're interested in contributing to PostgreSQL's documentation or want to discuss its content, subscribe to the pgsql-docs mailing list at [pgsql-docs Subscription](https://www.postgresql.org/list/pgsql-docs/).\n \n* **Regional and language-specific mailing lists**: PostgreSQL also offers several regional and language-specific mailing lists to help users communicate in their native languages. Find a suitable mailing list on the [PostgreSQL Mailing Lists page](https://www.postgresql.org/list/).\n \n\nHow to Contribute\n-----------------\n\nTo get started with mailing lists, follow these steps:\n\n* **Subscribe**: Choose a mailing list that suits your interests and click on the respective subscription link to sign up.\n \n* **Introduce yourself**: It's a good idea to send a brief introduction email to the mailing list, describing your skills and interests related to PostgreSQL.\n \n* **Read the archives**: Familiarize yourself with previous discussions by reading the mailing list archives. You can find them on the [PostgreSQL Mailing Lists page](https://www.postgresql.org/list/).\n \n* **Participate**: Once you're comfortable with the mailing list's topics and etiquette, start participating in ongoing discussions or initiate new threads.\n \n\nRemember to follow the [mailing list's etiquette](https://www.postgresql.org/community/lists/etiquette/) to ensure a positive and productive experience for all community members.",
|
||||
"links": []
|
||||
"description": "Mailing lists are an essential part of PostgreSQL's development community. They provide a platform for collaboration, discussion, and problem-solving. By participating in these lists, you can contribute to the development of PostgreSQL, share your knowledge with others, and stay informed about the latest updates, improvements, and conferences.\n\nPostgreSQL's development community offers a variety of mailing lists for discussions, announcements, and contributions. Key lists include **pgsql-hackers** for core development and feature discussions, **pgsql-announce** for official announcements, **pgsql-general** for general usage and administration queries, **pgsql-novice** for beginners seeking advice, and **pgsql-docs** for documentation-related contributions. Regional and language-specific lists are also available. To engage, subscribe to a mailing list that matches your interests, introduce yourself, read the archives for context, and participate in discussions. For guidelines, follow the Mailing List Etiquette.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Mailing List Etiquette",
|
||||
"url": "https://www.postgresql.org/community/lists/etiquette/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "pgsql-hackers Subscription",
|
||||
"url": "https://www.postgresql.org/list/pgsql-hackers/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "pgsql-announce Subscription",
|
||||
"url": "https://www.postgresql.org/list/pgsql-announce/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "pgsql-general Subscription",
|
||||
"url": "https://www.postgresql.org/list/pgsql-general/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "pgsql-novice Subscription",
|
||||
"url": "https://www.postgresql.org/list/pgsql-novice/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "pgsql-docs Subscription",
|
||||
"url": "https://www.postgresql.org/list/pgsql-docs/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "PostgreSQL Mailing Lists page",
|
||||
"url": "https://www.postgresql.org/list/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Jy0G0ZnHPOM8hba_PbwuA": {
|
||||
"title": "Reviewing Patches",
|
||||
"description": "One of the most valuable contributions to PostgreSQL is reviewing and testing patches submitted by other developers. This process ensures that every proposed change undergoes quality control, helps new contributors get involved and learn about PostgreSQL, and maintains the overall stability and reliability of the project.\n\n### Why is reviewing patches important?\n\n* Improves code quality by identifying bugs, security issues, and performance problems\n* Helps maintain consistency and adherence to project standards and best practices\n* Provides valuable feedback for developers working on new features and enhancements\n* Helps new contributors learn about PostgreSQL internals and progressively grow their expertise\n\n### How can I participate in reviewing patches?\n\n* Subscribe to the [pgsql-hackers mailing list](https://www.postgresql.org/list/pgsql-hackers/) where patch discussions and reviews take place.\n* Browse the [commitfest schedule](https://commitfest.postgresql.org/) to stay informed about upcoming events and deadlines.\n* Choose a patch from the commitfest that interests you or that you feel confident to review.\n* Analyze the patch to ensure:\n * Correctness: Does the patch work as intended and solve the problem it addresses?\n * Performance: Does the patch avoid introducing performance regressions or trade-offs?\n * Code quality: Is the code clean, modular, and maintainable? Does it adhere to PostgreSQL coding conventions?\n * Documentation: Are the changes properly documented, and do they provide the necessary context for other developers?\n * Test coverage: Are there appropriate tests covering the new code or changes?\n* Provide feedback on the patch, either by replying to the relevant mailing list thread or by commenting directly on the patch submission in the commitfest app. Be constructive and specific in your comments, and offer suggestions for improvement when possible.\n* Follow up on any discussion around your review and participate in ongoing improvements and iterations of the patch.\n\nRemember, reviewing patches is a collaborative process that relies on the input of many individuals. Your contributions are essential in maintaining the high quality and stability of the PostgreSQL project.",
|
||||
"links": []
|
||||
"description": "Reviewing patches is a vital contribution to PostgreSQL, ensuring quality control, maintaining project standards, and helping new contributors understand the system's internals. By identifying bugs, improving performance, and ensuring proper documentation and test coverage, reviewers uphold PostgreSQL's reliability and stability. To participate, subscribe to the _pgsql-hackers mailing list_, explore patches in the _commitfest schedule_, and provide constructive feedback on correctness, performance, and code quality. Engaging in this collaborative process is an impactful way to support the PostgreSQL community.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "pgsql-hackers Mailing List",
|
||||
"url": "https://www.postgresql.org/list/pgsql-hackers/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Commitfest Schedule",
|
||||
"url": "https://commitfest.postgresql.org/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"eQzMU_KyQmHJQ6gzyk0-1": {
|
||||
"title": "Writing Patches",
|
||||
|
||||
@@ -399,8 +399,19 @@
|
||||
},
|
||||
"gS3ofDrqDRKbecIskIyGi": {
|
||||
"title": "Product Roadmap",
|
||||
"description": "The product roadmap is a strategic document that provides a detailed overview of the product's direction and vision. It outlines the product's plans, both tactical and strategic - including the specific steps necessary to achieve the company's goals and vision. As a Product Manager, you are expected to guide the creation of the product roadmap, communicating the product’s evolution to the team, stakeholders, and customers. This tool serves as an essential reference point helping to align all stakeholders with the key priorities and vision of the product, and acts as a guide for decisions around product development.",
|
||||
"links": []
|
||||
"description": "The product roadmap is a strategic document that provides a detailed overview of the product's direction and vision. It outlines the product's plans, both tactical and strategic - including the specific steps necessary to achieve the company's goals and vision. As a Product Manager, you are expected to guide the creation of the product roadmap, communicating the product’s evolution to the team, stakeholders, and customers. This tool serves as an essential reference point helping to align all stakeholders with the key priorities and vision of the product, and acts as a guide for decisions around product development.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is a Product Roadmap? - Product Plan",
|
||||
"url": "https://www.productplan.com/learn/what-is-a-product-roadmap/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "What is a Product Roadmap? - Vibhor Chandel",
|
||||
"url": "https://www.youtube.com/watch?v=BJR70jnpHog&ab_channel=VibhorChandel",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
"eiqV86PWizZPWsyqoBU5k": {
|
||||
"title": "Creating a Roadmap",
|
||||
|
||||
@@ -179,6 +179,21 @@
|
||||
"title": "Tuples Documentation",
|
||||
"url": "https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "When and How to Use Tuples",
|
||||
"url": "https://thenewstack.io/python-for-beginners-when-and-how-to-use-tuples/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Python's tuple Data Type: A Deep Dive With Examples",
|
||||
"url": "https://realpython.com/python-tuple/#getting-started-with-pythons-tuple-data-type",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "why are Tuples even a thing?",
|
||||
"url": "https://www.youtube.com/watch?v=fR_D_KIAYrE",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -205,7 +220,7 @@
|
||||
},
|
||||
"bc9CL_HMT-R6nXO1eR-gP": {
|
||||
"title": "Dictionaries",
|
||||
"description": "In Python, a dictionary is a built-in data type that allows you to store key-value pairs. Each key in the dictionary is unique, and each key is associated with a value. Dictionaries are unordered collections, meaning the order of items is not guaranteed.\n\nLearn more from the following resources:",
|
||||
"description": "In Python, a dictionary is a built-in data type that allows you to store key-value pairs. Each key in the dictionary is unique, and each key is associated with a value. Starting from Python 3.7, dictionaries maintain the order of items as they were added.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Dictionaries in Python",
|
||||
@@ -216,6 +231,11 @@
|
||||
"title": "W3 Schools - Dictionaries",
|
||||
"url": "https://www.w3schools.com/python/python_dictionaries.asp",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Dictionaries in Python",
|
||||
"url": "https://realpython.com/python-dicts/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -533,6 +553,11 @@
|
||||
"title": "Modules in Python",
|
||||
"url": "https://www.programiz.com/python-programming/modules",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Python Modules and Packages",
|
||||
"url": "https://realpython.com/python-modules-packages/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -596,6 +621,11 @@
|
||||
"title": "Python Iterators",
|
||||
"url": "https://www.programiz.com/python-programming/iterator",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Iterators and Iterables in Python",
|
||||
"url": "https://realpython.com/python-iterators-iterables/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -839,6 +869,11 @@
|
||||
"title": "Python Paradigms",
|
||||
"url": "https://opensource.com/article/19/10/python-programming-paradigms",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Learn Functional Programming - Python Course",
|
||||
"url": "https://www.youtube.com/watch?v=5QZYGU0C2OA",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1317,7 +1352,7 @@
|
||||
"description": "Sphinx is a tool that makes it easy to create intelligent and beautiful documentation, written by Georg Brandl and licensed under the BSD license.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Shpinx Website",
|
||||
"title": "Sphinx Website",
|
||||
"url": "https://www.sphinx-doc.org/en/master/",
|
||||
"type": "article"
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "https://www.youtube.com/watch?v=DR22zNNetp0&t=1s",
|
||||
"title": "Test Oracle in Software Testing",
|
||||
"url": "https://www.youtube.com/watch?v=DR22zNNetp0&t=1s",
|
||||
"type": "article"
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -62,7 +62,7 @@
|
||||
"description": "qTest is a test management tool used for Project Management, Bug Tracking, and Test Management. It follows the centralized test management concept that helps to communicate easily and assists in rapid development of task across QA team and other stakeholders.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "QTest tutorial",
|
||||
"title": "QTest Tutorial",
|
||||
"url": "https://www.tutorialspoint.com/qtest/qtest_introduction.htm",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -78,7 +78,7 @@
|
||||
"description": "TestRail is a web-based test case management tool. It is used by testers, developers and team leads to manage, track, and organize software testing efforts. TestRail allows team members to enter test cases, organize test suites, execute test runs, and track their results, all from a modern and easy to use web interface.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "TestRail Website",
|
||||
"title": "TestRail",
|
||||
"url": "https://www.gurock.com/testrail/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -94,7 +94,7 @@
|
||||
"description": "TestLink is most widely used web based open source test management tool. It synchronizes both requirements specification and test specification together. Tester can create test project and document test cases using this tool. With TestLink you can create an account for multiple users and assign different user roles.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "TestLink Website",
|
||||
"title": "TestLink",
|
||||
"url": "https://testlink.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -118,7 +118,7 @@
|
||||
},
|
||||
"JInFH3JRvAxjvpIFKjUiP": {
|
||||
"title": "What is Quality Assurance?",
|
||||
"description": "Quality is extremely hard to define, and it is simply stated: “Fit for use or purpose.” It is all about meeting the needs and expectations of customers concerning the functionality, design, reliability, durability, & price of the product.\n\nWhat is Assurance\n-----------------\n\nAssurance is nothing but a positive declaration of a product or service, which gives confidence. It is certain of a product or a service which it will work well. It provides a guarantee that the product will work without any problems as per the expectations or requirements.\n\nQuality Assurance in Software Testing\n-------------------------------------\n\nQuality Assurance in Software Testing is defined as a procedure to ensure the quality of software products or services provided to the customers by an organization. Quality assurance focuses on improving the [software development process](https://www.guru99.com/software-development-life-cycle-tutorial.html) and making it efficient and effective per the quality standards defined for software products. Quality Assurance is popularly known as QA Testing.\n\nVisit the following resources to learn more:",
|
||||
"description": "Quality is extremely hard to define, and it is simply stated: “Fit for use or purpose.” It is all about meeting the needs and expectations of customers concerning the functionality, design, reliability, durability, & price of the product.\n\nWhat is Assurance\n-----------------\n\nAssurance is nothing but a positive declaration of a product or service, which gives confidence. It is certain of a product or a service which it will work well. It provides a guarantee that the product will work without any problems as per the expectations or requirements.\n\nQuality Assurance in Software Testing\n-------------------------------------\n\nQuality Assurance in Software Testing is defined as a procedure to ensure the quality of software products or services provided to the customers by an organization. Quality assurance focuses on improving the software development process and making it efficient and effective per the quality standards defined for software products. Quality Assurance is popularly known as QA Testing.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is Quality Assurance(QA)? Process, Methods, Examples",
|
||||
@@ -268,7 +268,7 @@
|
||||
"description": "Jira is a software application used for issue tracking and project management. The tool, developed by the Australian software company Atlassian, has become widely used by agile development teams to track bugs, stories, epics, and other tasks.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Atlassian Website",
|
||||
"title": "Atlassian",
|
||||
"url": "https://www.atlassian.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -299,7 +299,7 @@
|
||||
"description": "Assembla is an extensive suite of applications for software development, enabling distributed agile teams. It allows development teams to manage, initiate and maintain agile projects, applications and websites.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Assembla Website",
|
||||
"title": "Assembla",
|
||||
"url": "https://get.assembla.com/projects/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -315,7 +315,7 @@
|
||||
"description": "YouTrack is a project management software developed by JetBrains. It’s in the form of a plugin that can be attached to the JetBrains IDEs such as Intellij Idea, and helps create and assign tasks to a development team as well as track the progress of working.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "YouTrack Website",
|
||||
"title": "YouTrack",
|
||||
"url": "https://www.jetbrains.com/youtrack/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -331,7 +331,7 @@
|
||||
"description": "Trello is a popular, simple, and easy-to-use collaboration tool that enables you to organize projects and everything related to them into boards. With Trello, you can find all kinds of information, such as:\n\n* What’s being worked on?\n* Who’s working on what?\n* What progress the project is making\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Trello Website",
|
||||
"title": "Trello",
|
||||
"url": "https://trello.com/en",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -539,8 +539,14 @@
|
||||
},
|
||||
"Lve3xpC1FU91TQqoDOYv7": {
|
||||
"title": "Sanity Testing",
|
||||
"description": "Sanity testing is a kind of Software Testing performed after receiving a software build, with minor changes in code, or functionality, to ascertain that the bugs have been fixed and no further issues are introduced due to these changes. The goal is to determine that the proposed functionality works roughly as expected. If sanity test fails, the build is rejected to save the time and costs involved in a more rigorous testing.",
|
||||
"links": []
|
||||
"description": "Sanity testing is a kind of Software Testing performed after receiving a software build, with minor changes in code, or functionality, to ascertain that the bugs have been fixed and no further issues are introduced due to these changes. The goal is to determine that the proposed functionality works roughly as expected. If sanity test fails, the build is rejected to save the time and costs involved in a more rigorous testing.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is Sanity Testing?",
|
||||
"url": "https://www.browserstack.com/guide/sanity-testing#:~:text=Sanity%20Testing%20or%20Surface%20Level,working%20properly%20without%20any%20bugs.",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"XCeXiKvBblmDArfbWjDvw": {
|
||||
"title": "Regression Testing",
|
||||
@@ -690,7 +696,7 @@
|
||||
"description": "Kanban is a very popular framework for development in the agile software development methodology. It provides a transparent way of visualizing the tasks and work capacity of a team. It mainly uses physical and digital boards to allow the team members to visualize the current state of the project they are working on.\n\nA kanban board is an agile project management tool designed to help visualize work, limit work-in-progress, and maximize efficiency.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Kanban - A brief introduction",
|
||||
"title": "Kanban - A Brief Introduction",
|
||||
"url": "https://www.atlassian.com/agile/kanban",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -845,7 +851,7 @@
|
||||
"description": "HTML stands for HyperText Markup Language. It is used on the front and gives structure to the webpage, which you can style using CSS and make interactive using JavaScript.\n\nCSS or Cascading Style Sheets is the language used to style the front end of any website. CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript.\n\nJavaScript allows you to add interactivity to your pages. You may have seen common examples on the websites: sliders, click interactions, popups, and so on.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "W3Schools: Learn HTML",
|
||||
"title": "W3Schools - Learn HTML",
|
||||
"url": "https://www.w3schools.com/html/html_intro.asp",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -871,7 +877,7 @@
|
||||
"description": "Every modern web browser includes a powerful suite of developer tools. These tools do a range of things, from inspecting currently-loaded HTML, CSS and JavaScript to showing which assets the page has requested and how long they took to load. This article explains how to use the basic functions of your browser's devtools.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What are browser developer tools?",
|
||||
"title": "What are Browser Developer Tools?",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -892,7 +898,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Getting started",
|
||||
"title": "Getting Started with AJAX",
|
||||
"url": "https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX/Getting_Started",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -907,6 +913,11 @@
|
||||
"title": "Caching",
|
||||
"description": "Caching ensures that the resources downloaded once are reused instead of doing a fresh fetch again. It is useful for increasing subsequent page load speed by reusing cached images, fonts, and other static assets. Caching should not be typically done on dynamic content. For example list of posts or comments. As part of the testing strategy, both caching and cache invalidation (not getting stale dynamic content) needs to be tested.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is Caching and How it Works | AWS",
|
||||
"url": "https://aws.amazon.com/caching/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Caching - Simply Explained",
|
||||
"url": "https://www.youtube.com/watch?v=6FyXURRVmR0",
|
||||
@@ -971,7 +982,7 @@
|
||||
"description": "Selenium IDE is an open source web automation testing tool from the Selenium Suite used primarily for QA purposes. It functions as a Firefox extension and does not require any programming knowledge and test cases can be created simply by interacting with the browser.\n\nSelenium itself is an open-source, automated testing tool used to test web applications across various browsers. It's primarily built in Java and supports several browsers and programming languages. Selenium IDE was developed to speed up the creation of automation scripts. It’s a rapid prototyping tool and can be used by engineers with no programming knowledge whatsoever. Because of its simplicity, Selenium IDE is best used as a prototyping tool and not a complete solution for developing and maintaining complex test suites.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Selenium IDE Website",
|
||||
"title": "Selenium IDE",
|
||||
"url": "https://www.selenium.dev/selenium-ide/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -992,7 +1003,7 @@
|
||||
"description": "Ghost Inspector is a codeless automated testing tool that allows you to easily create and run automated browser tests for websites and web applications. These tests carry out actions in a web browser the same way a real user would to ensure that everything is working properly.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Ghost Inspector Website",
|
||||
"title": "Ghost Inspector",
|
||||
"url": "https://ghostinspector.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1024,7 +1035,7 @@
|
||||
"description": "WebdriverIO is a progressive automation framework built to automate modern web and mobile applications. It simplifies the interaction with your app and provides a set of plugins that help you create a scalable, robust and stable test suite.\n\nWebdriverIO leverages the power of the WebDriver protocol that is developed and supported by all browser vendors and guarantees a true cross-browser testing experience. While other automation tools require you to download modified browser that aren't used by actual users or emulate user behavior by injecting JavaScript, WebdriverIO relies on a common agreed standard for automation that is properly tested and ensures compatibility for decades to come.\n\nDuring the development of this automation standard the web has changed a lot and many of the requirements that developers have today to test their web application can not be fulfilled using WebDriver anymore. While some of the core contributors of this project help support the next generation of the WebDriver protocol, WebdriverIO provides an alternative automation solution based on the Chrome DevTools protocol. This allows the user to seamlessly switch between conventional commands based on WebDriver and powerful browser interactions through Puppeteer.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "WebdriverIO Website",
|
||||
"title": "WebdriverIO",
|
||||
"url": "https://webdriver.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1050,7 +1061,7 @@
|
||||
"description": "Playwright Test was created specifically to accommodate the needs of end-to-end testing. Playwright supports all modern rendering engines including Chromium, WebKit, and Firefox. Test on Windows, Linux, and macOS, locally or on CI, headless or headed with native mobile emulation of Google Chrome for Android and Mobile Safari.Playwright leverages the DevTools protocol to write powerful, stable automated tests.Playwright can actually see into and control the browser rather than relying on a middle translation layer, it allows for the simulation of more insightful and relevant user scenarios.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website: Playwright",
|
||||
"title": "Playwright",
|
||||
"url": "https://playwright.dev/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1071,7 +1082,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "QA Wolf Official Docs",
|
||||
"title": "QA Wolf Docs",
|
||||
"url": "https://app.qawolf.com/docs/why-qa-wolf",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1097,20 +1108,25 @@
|
||||
"description": "Cypress framework is a JavaScript-based end-to-end testing framework built on top of Mocha – a feature-rich JavaScript test framework running on and in the browser, making asynchronous testing simple and convenient. It also uses a BDD/TDD assertion library and a browser to pair with any JavaScript testing framework.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Cypress",
|
||||
"url": "https://www.cypress.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Cypress Documentation",
|
||||
"url": "https://docs.cypress.io/guides/overview/why-cypress#Other",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How it works",
|
||||
"title": "How it Works",
|
||||
"url": "https://www.cypress.io/how-it-works",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Cypress - End to End Testing Framework",
|
||||
"url": "https://dev.to/bushraalam/cypress-end-to-end-testing-framework-3naa",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about Cypress",
|
||||
"url": "https://app.daily.dev/tags/cypress?ref=roadmapsh",
|
||||
@@ -1120,6 +1136,11 @@
|
||||
"title": "Cypress End-to-End Testing",
|
||||
"url": "https://www.youtube.com/watch?v=7N63cMKosIE",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Cypress Tips & Tricks",
|
||||
"url": "https://www.youtube.com/watch?v=PZ2OsLBts1E&list=PLP9o9QNnQuAYYRpJzDNWpeuOVTwxmIxcI",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1128,12 +1149,12 @@
|
||||
"description": "Jasmine is a very popular JavaScript BDD (behavior-driven development) framework for unit testing JavaScript applications. It provides utilities that can be used to run automated tests for both synchronous and asynchronous code. It does not depend on any other JavaScript frameworks. It does not require a DOM.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Jasmines Official Website",
|
||||
"title": "Jasmines",
|
||||
"url": "https://jasmine.github.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Easy and Practical example of Angular testing with Jasmine",
|
||||
"title": "Easy and Practical Example of Angular Testing with Jasmine",
|
||||
"url": "https://semaphoreci.com/community/tutorials/testing-components-in-angular-2-with-jasmine",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1186,7 +1207,7 @@
|
||||
"description": "Selenium is an open-source tool that automates web browsers. It provides a single interface that lets you write test scripts in programming languages like Ruby, Java, NodeJS, PHP, Perl, Python, and C#, among others.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Seleniums Official Website",
|
||||
"title": "Selenium",
|
||||
"url": "https://www.selenium.dev/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1207,12 +1228,12 @@
|
||||
"description": "Jest is a delightful JavaScript Testing Framework with a focus on simplicity. It works with projects using: Babel, TypeScript, Node, React, Angular, Vue and more!\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Jest",
|
||||
"url": "https://jestjs.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Jest Documentation",
|
||||
"url": "https://jestjs.io/docs/getting-started",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1249,7 +1270,7 @@
|
||||
"description": "Front-end automation is a way to characterize automation that streamlines tasks focused on interactivity, websites, and attended processes. Robotic process automation, or RPA, is considered automation on the front end, or from the user-interface (UI) level. Benefits of front-end automation include quick task building with no programming knowledge, no required changes to existing programs or applications, and those individuals who know the keystrokes can easily build the automation task.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "How we do automated testing on our frontend",
|
||||
"title": "How We do Automated Testing on our Frontend",
|
||||
"url": "https://dev.to/davidz/how-we-do-automated-testing-on-our-frontend-b10",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1265,7 +1286,7 @@
|
||||
"description": "Backend Testing is a testing method that checks the server side or database of web applications or software. Backend testing aims to test the application layer or database layer to ensure that the web application or software is free from database defects like deadlock, data corruption, or data loss.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "What is backend testing?",
|
||||
"title": "What is Backend Testing?",
|
||||
"url": "https://testinggenez.com/what-is-backend-testing-and-types/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1286,15 +1307,20 @@
|
||||
"description": "Cypress framework is a JavaScript-based end-to-end testing framework built on top of Mocha – a feature-rich JavaScript test framework running on and in the browser, making asynchronous testing simple and convenient. It also uses a BDD/TDD assertion library and a browser to pair with any JavaScript testing framework.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Cypress",
|
||||
"url": "https://www.cypress.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Cypress Documentation",
|
||||
"url": "https://docs.cypress.io/guides/overview/why-cypress#Other",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How it Works",
|
||||
"url": "https://www.cypress.io/how-it-works",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Cypress - End to End Testing Framework",
|
||||
"url": "https://dev.to/bushraalam/cypress-end-to-end-testing-framework-3naa",
|
||||
@@ -1311,7 +1337,7 @@
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Cypress Tips & Trics",
|
||||
"title": "Cypress Tips & Tricks",
|
||||
"url": "https://www.youtube.com/watch?v=PZ2OsLBts1E&list=PLP9o9QNnQuAYYRpJzDNWpeuOVTwxmIxcI",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -1343,7 +1369,7 @@
|
||||
"description": "SoapUI is the world's leading Functional Testing tool for SOAP and REST testing. With its easy-to-use graphical interface, and enterprise-class features, SoapUI allows you to easily and rapidly create and execute automated functional, regression, and load tests.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "SoapUI Official Website",
|
||||
"title": "SoapUI",
|
||||
"url": "https://www.soapui.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1364,7 +1390,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "karate website",
|
||||
"title": "Karate Framework",
|
||||
"url": "https://www.karatelabs.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1380,17 +1406,17 @@
|
||||
"description": "Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster. It is an API client that makes it easy for developers to create, share, test, and document APIs. With this open-source solution, users can create and save simple and complex HTTP/s requests and read their responses.\n\nNewman is a command-line Collection Runner for Postman. It enables you to run and test a Postman Collection directly from the command line. It's built with extensibility to integrate it with your continuous integration servers and build systems.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Postman website",
|
||||
"title": "Postman",
|
||||
"url": "https://www.postman.com",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Learn postman",
|
||||
"title": "Learn Postman",
|
||||
"url": "https://learning.postman.com/docs/getting-started/introduction/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Newman cli usage",
|
||||
"title": "Newman CLI",
|
||||
"url": "https://learning.postman.com/docs/running-collections/using-newman-cli/command-line-integration-with-newman/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1400,7 +1426,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "API testing with postman",
|
||||
"title": "API Testing with Postman",
|
||||
"url": "https://www.youtube.com/watch?v=VywxIQ2ZXw4",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -1453,7 +1479,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Espresso Documentation",
|
||||
"url": "https://developer.android.com/training/testing/espresso#kotlin",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1469,7 +1495,7 @@
|
||||
"description": "Detox is a JavaScript mobile testing framework that is built into the application and the test execution starts with app launch. This makes test execution really fast and robust as no external additional tools are needed to orchestrate and synchronize during the test execution.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Detox Website",
|
||||
"title": "Detox",
|
||||
"url": "https://wix.github.io/Detox/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1495,19 +1521,19 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Appium Website",
|
||||
"title": "Appium",
|
||||
"url": "https://appium.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Appium Documentation",
|
||||
"url": "https://appium.io/docs/en/2.0/intro/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Appium Tutorial for Mobile Application Testing",
|
||||
"url": "https://www.browserstack.com/guide/appium-tutorial-for-testing",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Appium Website",
|
||||
"url": "https://appium.io/docs/en/2.0/intro/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1516,7 +1542,7 @@
|
||||
"description": "Mobile app testing, and more specifically, app UI testing involves checking how the interface behaves when user actions are performed and then compares results with expected outcomes. Here, testers try to replicate exactly how a user would interact with the application and validate the state of the UI. XCUITest allows them to write test cases for these purposes using two fundamental concepts.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "XCUITest Documentation",
|
||||
"url": "https://developer.apple.com/documentation/xctest/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1537,7 +1563,7 @@
|
||||
"description": "In software QA, accessibility testing is the practice of confirming that an application is usable for as many people as possible, including people with disabilities such as vision impairment, hearing problems and cognitive conditions.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Accessibility testing -Javapoint",
|
||||
"title": "Accessibility Testing - Javatpoint",
|
||||
"url": "https://www.javatpoint.com/accessibility-testing",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1553,7 +1579,7 @@
|
||||
"description": "Wave is a suite of evaluation tools that helps authors make their web content more accessible to individuals with disabilities. WAVE can identify many accessibility and Web Content Accessibility Guideline (WCAG) errors, but also facilitates human evaluation of web content.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Wave Website",
|
||||
"title": "Wave",
|
||||
"url": "https://wave.webaim.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1585,7 +1611,7 @@
|
||||
"description": "These are a set of tools built into the browser to aid frontend developers diagnose and solve various issues in their applications — such as JavaScript and logical bugs, CSS styling issues or even just making quick temporary alterations to the DOM.\n\nTo enter the dev tools, right click and click **Inspect** (or press `ctrl+shift+c`/`cmd+opt+c`) to enter the Elements panel. Here you can debug CSS and HTML issues. If you want to see logged messages or interact with javascript, enter the **Console** tab from the tabs above (or press `ctrl+shift+j`/`cmd+opt+j` to enter it directly). Another very useful feature in the Chrome dev tools is the Lighthouse (for checking performance) — more on this later.\n\nNOTE: This isn't a chrome-specific feature, and most browsers (Chromium based or otherwise) will have their own, largely-similar set of devtools.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Docs",
|
||||
"title": "Chrome Dev Tools",
|
||||
"url": "https://developer.chrome.com/docs/devtools/overview/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1606,7 +1632,7 @@
|
||||
"description": "Lighthouse is an open-source, automated tool for improving the quality of web pages. You can run it against any web page, public or requiring authentication. It has audits for performance, accessibility, progressive web apps, SEO, and more. You can run Lighthouse in Chrome DevTools, from the command line, or as a Node module. You give Lighthouse a URL to audit, run a series of audits against the page, and then generate a report on how well the page did. From there, use the failing audits as indicators on how to improve the page. Each audit has a reference doc explaining why the audit is important and how to fix it.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Lighthouse Website",
|
||||
"title": "Lighthouse Source",
|
||||
"url": "https://github.com/GoogleChrome/lighthouse/",
|
||||
"type": "opensource"
|
||||
},
|
||||
@@ -1622,7 +1648,7 @@
|
||||
"description": "WebPageTest is a web performance tool providing deep diagnostic information about how a page performs under a variety of conditions.\n\nEach test can be run from different locations around the world, on real browsers, over any number of customizable network conditions.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "WebPageTest Website",
|
||||
"title": "WebPageTest",
|
||||
"url": "https://www.webpagetest.org/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1630,10 +1656,10 @@
|
||||
},
|
||||
"J1Yx1VcO20Lc3r3PdGpUW": {
|
||||
"title": "Gatling",
|
||||
"description": "Gatling is a highly capable load testing tool. It is designed for ease of use, maintainability and high performance.\n\nOut of the box, Gatling comes with excellent support of the HTTP protocol that makes it a tool of choice for load testing any HTTP server. As the core engine is actually protocol agnostic, it is perfectly possible to implement support for other protocols. For example, Gatling currently also ships JMS support.\n\nGatling’s architecture is asynchronous as long as the underlying protocol, such as HTTP, can be implemented in a non blocking way. This kind of architecture lets us implement virtual users as messages instead of dedicated threads, making them very resource cheap. Thus, running thousands of concurrent virtual users is not an issue.\n\nVisit the following resources to learn more:",
|
||||
"description": "Gatling is a highly capable load testing tool. It is designed for ease of use, maintainability and high performance. Out of the box, Gatling comes with excellent support of the HTTP protocol that makes it a tool of choice for load testing any HTTP server. As the core engine is actually protocol agnostic, it is perfectly possible to implement support for other protocols. For example, Gatling currently also ships JMS support.\n\nGatling’s architecture is asynchronous as long as the underlying protocol, such as HTTP, can be implemented in a non blocking way. This kind of architecture lets us implement virtual users as messages instead of dedicated threads, making them very resource cheap. Thus, running thousands of concurrent virtual users is not an issue.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Gatling Website",
|
||||
"title": "Gatling",
|
||||
"url": "https://gatling.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1649,7 +1675,7 @@
|
||||
"description": "Grafana k6 is an open-source load testing tool that makes performance testing easy and productive for engineering teams. k6 is free, developer-centric, and extensible.\n\nUsing k6, you can test the reliability and performance of your systems and catch performance regressions and problems earlier. k6 will help you to build resilient and performant applications that scale.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "k6 Website",
|
||||
"title": "Grafana k6 Website",
|
||||
"url": "https://k6.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1665,7 +1691,7 @@
|
||||
"description": "Artillery is a modern, powerful & easy-to-use performance testing toolkit. Use it to ship scalable applications that stay performant & resilient under high load.\n\nArtillery prioritizes developer productivity and happiness, and follows the \"batteries-included\" philosophy.\n\nFeatures\n--------\n\n* Emulate complex user behavior with scenarios\n* Load testing and smoke testing\n* Batteries included\n* Extensible & hackable\n* Integrations and add-ons\n* Designed for cross-team collaboration\n* Planet-scale testing\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Artillery Website",
|
||||
"title": "Artillery",
|
||||
"url": "https://www.artillery.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1681,7 +1707,7 @@
|
||||
"description": "Vegeta is a versatile HTTP load testing tool built out of a need to drill HTTP services with a constant request rate. It can be used both as a command line utility and a library.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Vegeta Website",
|
||||
"title": "Vegeta",
|
||||
"url": "https://github.com/tsenart/vegeta",
|
||||
"type": "opensource"
|
||||
}
|
||||
@@ -1692,7 +1718,7 @@
|
||||
"description": "Apache JMeter is an Apache project that can be used as a load testing tool for analyzing and measuring the performance of a variety of services, with a focus on web applications.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Apache JMeter Website",
|
||||
"title": "Apache JMeter",
|
||||
"url": "https://jmeter.apache.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1713,7 +1739,7 @@
|
||||
"description": "Locust is an easy-to-use, scriptable and scalable performance testing tool. You define the behavior of your users in regular Python code instead of being stuck in a UI or restrictive domain-specific language. This makes Locust infinitely expandable and very developer friendly. Given below are some of the features of Locust.\n\n* Write test scenarios in plain old Python\n* Distributed and scalable - supports hundreds of thousands of concurrent users\n* Web-based UI\n* Can test any system\n* Hackable\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Locust Website",
|
||||
"title": "Locust",
|
||||
"url": "https://locust.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1742,7 +1768,7 @@
|
||||
},
|
||||
"75-XdVA4BL6UrcvpC9grx": {
|
||||
"title": "Authentication / Authorization",
|
||||
"description": "`Authentication` is the process of verifying that an individual, entity or website is whom it claims to be. Authentication in the context of web applications is commonly performed by submitting a username or ID and one or more items of private information that only a given user should know.\n\n`Authorization` may be defined as \"the process of verifying that a requested action or service is approved for a specific entity\" (NIST). `Authorization` is distinct from authentication which is the process of verifying an entity's identity. When designing and developing a software solution, it is important to keep these distinctions in mind. A user who has been authenticated (perhaps by providing a username and password) is often not authorized to access every resource and perform every action that is technically possible through a system.\n\nFor example, a web app may have both regular users and admins, with the admins being able to perform actions the average user is not privileged to do so, even though they have been authenticated. Additionally, authentication is not always required for accessing resources; an unauthenticated user may be authorized to access certain public resources, such as an image or login page, or even an entire web app.\n\nVisit the following resources to learn more:",
|
||||
"description": "`Authentication` is the process of verifying that an individual, entity or website is whom it claims to be. Authentication in the context of web applications is commonly performed by submitting a username or ID and one or more items of private information that only a given user should know.\n\n`Authorization` may be defined as \"the process of verifying that a requested action or service is approved for a specific entity\" (NIST). `Authorization` is distinct from authentication which is the process of verifying an entity's identity. When designing and developing a software solution, it is important to keep these distinctions in mind. A user who has been authenticated (perhaps by providing a username and password) is often not authorized to access every resource and perform every action that is technically possible through a system.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "OWASP Website",
|
||||
@@ -1774,7 +1800,7 @@
|
||||
},
|
||||
"YV6ST78AH4J0i2Rw9zhZj": {
|
||||
"title": "Secrets Management",
|
||||
"description": "Secrets Management is a systematic way of in managing, storing, securing, and retrieving credentials for any systems, database, and other services.\n\nCredentials such as passwords, SSH keys, certificates, API keys, backup codes, and more.\n\nVisit the following resources to learn more:",
|
||||
"description": "Secrets Management is a systematic way of in managing, storing, securing, and retrieving credentials for any systems, database, and other services. Credentials such as passwords, SSH keys, certificates, API keys, backup codes, and more.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "AWS Secrets Management Website",
|
||||
@@ -1867,9 +1893,9 @@
|
||||
"description": "Gmail-tester is a simple Node.js Gmail client which checks/returns email message(s) straight from any Gmail-powered account (both private and company).\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Gmail-tester Website",
|
||||
"title": "Gmail-tester Package",
|
||||
"url": "https://www.npmjs.com/package/gmail-tester",
|
||||
"type": "article"
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Using the gmail-tester + Puppeteer to poll Gmail inbox",
|
||||
@@ -1930,7 +1956,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Allure Official Docs",
|
||||
"title": "Allure Docs",
|
||||
"url": "https://docs.qameta.io/allure-report/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1949,20 +1975,26 @@
|
||||
},
|
||||
"pJvijtG-a0vOq16EFu3Gr": {
|
||||
"title": "Monitoring & Logs",
|
||||
"description": "DevOps monitoring entails overseeing the entire development process from planning, development, integration and testing, deployment, and operations. It involves a complete and real-time view of the status of applications, services, and infrastructure in the production environment. Features such as real-time streaming, historical replay, and visualizations are critical components of application and service monitoring.",
|
||||
"links": []
|
||||
"description": "DevOps monitoring entails overseeing the entire development process from planning, development, integration and testing, deployment, and operations. It involves a complete and real-time view of the status of applications, services, and infrastructure in the production environment. Features such as real-time streaming, historical replay, and visualizations are critical components of application and service monitoring.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Two Pillars of Modern QA - Errors and Logs",
|
||||
"url": "https://medium.com/@mohsenny/the-two-pillars-of-modern-qa-from-error-prevention-to-post-release-monitoring-4c11cc99fe14",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"8CztIu0BOPZZRZsqR9asW": {
|
||||
"title": "Grafana",
|
||||
"description": "Grafana is the open-source platform for monitoring and observability. It allows you to query, visualize, alert on and understand your metrics no matter where they are stored.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Grafana Website",
|
||||
"title": "Grafana",
|
||||
"url": "https://grafana.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Grafana Official Documentation",
|
||||
"title": "Grafana Documentation",
|
||||
"url": "https://grafana.com/docs/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1988,7 +2020,7 @@
|
||||
"description": "New Relic is an observability platform that helps you build better software. You can bring in data from any digital source so that you can fully understand your system and how to improve it.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "New Relic Website",
|
||||
"title": "New Relic",
|
||||
"url": "https://newrelic.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2009,7 +2041,7 @@
|
||||
"description": "A Simple Tool for Monitoring Complex APIs. Verify that the structure and content of your API calls meets your expectations. Powerful and flexible assertions give you total control over defining a successful API call.\n\nCreate simple monitors with dynamic data for even the most complex use cases. More than simple string matching, build API validations without any code and use them across local dev, staging and production environments.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Runscope Website",
|
||||
"title": "Runscope",
|
||||
"url": "https://www.runscope.com",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -2020,9 +2052,14 @@
|
||||
"description": "Sentry tracks your software performance, measuring metrics like throughput and latency, and displaying the impact of errors across multiple systems. Sentry captures distributed traces consisting of transactions and spans, which measure individual services and individual operations within those services.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Sentry Website",
|
||||
"title": "Sentry",
|
||||
"url": "https://sentry.io",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Sentry Documentation",
|
||||
"url": "https://docs.sentry.io/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -2031,7 +2068,7 @@
|
||||
"description": "Kibana is a free and open user interface that lets you visualize your Elasticsearch data and navigate the Elastic Stack. Do anything from tracking query load to understanding the way requests flow through your apps.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Elastic Kibana Website",
|
||||
"title": "Elastic Kibana",
|
||||
"url": "https://www.elastic.co/kibana/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2052,12 +2089,12 @@
|
||||
"description": "Datadog is a monitoring and analytics platform for large-scale applications. It encompasses infrastructure monitoring, application performance monitoring, log management, and user-experience monitoring. Datadog aggregates data across your entire stack with 400+ integrations for troubleshooting, alerting, and graphing.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Datadog Website",
|
||||
"title": "Datadog",
|
||||
"url": "https://www.datadoghq.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Datadog Documentation",
|
||||
"url": "https://docs.datadoghq.com/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -2107,8 +2144,13 @@
|
||||
},
|
||||
"WrqKdOTRUiOnc1aIhTZeB": {
|
||||
"title": "Git",
|
||||
"description": "[Git](https://git-scm.com/) is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.\n\nVisit the following resources to learn more:",
|
||||
"description": "Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Git",
|
||||
"url": "https://git-scm.com/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Learn Git with Tutorials, News and Tips - Atlassian",
|
||||
"url": "https://www.atlassian.com/git",
|
||||
@@ -2141,20 +2183,20 @@
|
||||
"description": "GitHub is a provider of Internet hosting for software development and version control using Git. It offers the distributed version control and source code management functionality of Git, plus its own features.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "GitHub Website",
|
||||
"title": "Visit Dedicated Github Roadmap",
|
||||
"url": "https://roadmap.sh/git-github",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitHub",
|
||||
"url": "https://github.com",
|
||||
"type": "opensource"
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Documentation",
|
||||
"url": "https://docs.github.com/en/get-started/quickstart",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to Use Git in a Professional Dev Team",
|
||||
"url": "https://ooloo.io/project/github-flow",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about GitHub",
|
||||
"url": "https://app.daily.dev/tags/github?ref=roadmapsh",
|
||||
@@ -2184,10 +2226,10 @@
|
||||
},
|
||||
"4xlbvY7NS3cemSZsEQAkD": {
|
||||
"title": "Bitbucket",
|
||||
"description": "Bitbucket is a Git based hosting and source code repository service that is Atlassian's alternative to other products like GitHub, GitLab etc\n\nBitbucket offers hosting options via Bitbucket Cloud (Atlassian's servers), Bitbucket Server (customer's on-premise) or Bitbucket Data Centre (number of servers in customers on-premise or cloud environment)\n\nVisit the following resources to learn more:",
|
||||
"description": "Bitbucket is a Git based hosting and source code repository service that is Atlassian's alternative to other products like GitHub, GitLab etc.\n\nBitbucket offers hosting options via Bitbucket Cloud (Atlassian's servers), Bitbucket Server (customer's on-premise) or Bitbucket Data Centre (number of servers in customers on-premise or cloud environment)\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Bitbucket Website",
|
||||
"title": "Bitbucket",
|
||||
"url": "https://bitbucket.org/product",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2212,7 +2254,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Bitbucket tutorial | How to use Bitbucket Cloud",
|
||||
"title": "How to Use Bitbucket Cloud",
|
||||
"url": "https://www.youtube.com/watch?v=M44nEyd_5To",
|
||||
"type": "video"
|
||||
},
|
||||
@@ -2228,9 +2270,9 @@
|
||||
"description": "GitLab is a provider of internet hosting for software development and version control using Git. It offers the distributed version control and source code management functionality of Git, plus its own features.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "GitLab Website",
|
||||
"title": "GitLab",
|
||||
"url": "https://gitlab.com/",
|
||||
"type": "opensource"
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitLab Documentation",
|
||||
@@ -2275,7 +2317,7 @@
|
||||
"description": "CircleCI is a CI/CD service that can be integrated with GitHub, BitBucket and GitLab repositories. The service that can be used as a SaaS offering or self-managed using your own resources.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "CircleCI Website",
|
||||
"title": "CircleCI",
|
||||
"url": "https://circleci.com/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2298,15 +2340,15 @@
|
||||
},
|
||||
"3oDyxhhbCCqxuCh1sT9VC": {
|
||||
"title": "Drone",
|
||||
"description": "Drone is a CI/CD service offering by [Harness](https://harness.io/). Each build runs on an isolated Docker container, and Drone integrates with many popular source code management repositories like GitHub, BitBucket and GitLab\n\nVisit the following resources to learn more:",
|
||||
"description": "Drone is a CI/CD service offering by Harness. Each build runs on an isolated Docker container, and Drone integrates with many popular source code management repositories like GitHub, BitBucket and GitLab\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Drone Website",
|
||||
"title": "Drone",
|
||||
"url": "https://www.drone.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Drone Documentation",
|
||||
"url": "https://docs.drone.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2322,7 +2364,7 @@
|
||||
"description": "Jenkins is an open-source CI/CD automation server. Jenkins is primarily used for building projects, running tests, static code analysis and deployments.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Jenkins Website",
|
||||
"title": "Jenkins",
|
||||
"url": "https://www.jenkins.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2374,9 +2416,9 @@
|
||||
"description": "GitLab offers a CI/CD service that can be used as a SaaS offering or self-managed using your own resources. You can use GitLab CI with any GitLab hosted repository, or any BitBucket Cloud or GitHub repository in the GitLab Premium self-managed, GitLab Premium SaaS and higher tiers.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "GitLab Website",
|
||||
"title": "GitLab",
|
||||
"url": "https://gitlab.com/",
|
||||
"type": "opensource"
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "GitLab Documentation",
|
||||
@@ -2410,12 +2452,12 @@
|
||||
"description": "Bamboo is a CI/CD service provided by Atlassian. Bamboo is primarily used for automating builds, tests and releases in a single workflow.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Bamboo Website",
|
||||
"title": "Bamboo",
|
||||
"url": "https://www.atlassian.com/software/bamboo",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Bamboo Documentation",
|
||||
"url": "https://confluence.atlassian.com/bamboo/bamboo-documentation-289276551.html",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2431,12 +2473,12 @@
|
||||
"description": "TeamCity is a CI/CD service provided by JetBrains. TeamCity can be used as a SaaS offering or self-managed using your own resources.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "TeamCity Website",
|
||||
"title": "TeamCity",
|
||||
"url": "https://www.jetbrains.com/teamcity/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "TeamCity Documentation ",
|
||||
"url": "https://www.jetbrains.com/help/teamcity/teamcity-documentation.html",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2457,12 +2499,12 @@
|
||||
"description": "Azure DevOps is developed by Microsoft as a full scale application lifecycle management and CI/CD service. Azure DevOps provides developer services for allowing teams to plan work, collaborate on code development, and build and deploy applications.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Azure DevOps Website",
|
||||
"title": "Azure DevOps",
|
||||
"url": "https://azure.microsoft.com/en-us/services/devops/#overview",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Azure Documentation",
|
||||
"url": "https://docs.microsoft.com/en-us/azure/devops/?view=azure-devops&viewFallbackFrom=vsts",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2525,7 +2567,7 @@
|
||||
"description": "Zombie.js allows you to run Unit or Integration tests without a real web browser. Instead, it uses a simulated browser where it stores the HTML code and runs the JavaScript you may have in your HTML page. This means that an HTML page doesn’t need to be displayed, saving precious time that would otherwise be occupied rendering it.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Zombie.js Website",
|
||||
"title": "Zombie.js",
|
||||
"url": "http://zombie.js.org/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2546,7 +2588,7 @@
|
||||
"description": "Puppeteer is a Node library that provides a high-level API to control headless Chrome or Chromium browsers over the DevTools Protocol. It can also be configured to use full (non-headless) Chrome or Chromium.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Puppeteer Website",
|
||||
"title": "Puppeteer",
|
||||
"url": "https://pptr.dev/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -2578,15 +2620,25 @@
|
||||
"description": "Cypress framework is a JavaScript-based end-to-end testing framework built on top of Mocha – a feature-rich JavaScript test framework running on and in the browser, making asynchronous testing simple and convenient. It also uses a BDD/TDD assertion library and a browser to pair with any JavaScript testing framework.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Official Website",
|
||||
"title": "Cypress",
|
||||
"url": "https://www.cypress.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Official Documentation",
|
||||
"title": "Cypress Documentation",
|
||||
"url": "https://docs.cypress.io/guides/overview/why-cypress#Other",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How it Works",
|
||||
"url": "https://www.cypress.io/how-it-works",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Cypress - End to End Testing Framework",
|
||||
"url": "https://dev.to/bushraalam/cypress-end-to-end-testing-framework-3naa",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about Cypress",
|
||||
"url": "https://app.daily.dev/tags/cypress?ref=roadmapsh",
|
||||
@@ -2596,6 +2648,11 @@
|
||||
"title": "Cypress End-to-End Testing",
|
||||
"url": "https://www.youtube.com/watch?v=7N63cMKosIE",
|
||||
"type": "video"
|
||||
},
|
||||
{
|
||||
"title": "Cypress Tips & Tricks",
|
||||
"url": "https://www.youtube.com/watch?v=PZ2OsLBts1E&list=PLP9o9QNnQuAYYRpJzDNWpeuOVTwxmIxcI",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -2631,7 +2688,7 @@
|
||||
"description": "HtmlUnit is a \"GUI-Less browser for Java programs\". It models HTML documents and provides an API that allows you to invoke pages, fill out forms, click links, etc... just like you do in your \"normal\" browser. It has fairly good JavaScript support (which is constantly improving) and is able to work even with quite complex AJAX libraries, simulating Chrome, Firefox or Internet Explorer depending on the configuration used.\n\nHtmlUnit is not a generic unit testing framework. It is specifically a way to simulate a browser for testing purposes and is intended to be used within another testing framework such as JUnit or TestNG.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "HtmlUnit Website",
|
||||
"title": "HtmlUnit",
|
||||
"url": "https://htmlunit.sourceforge.io/",
|
||||
"type": "article"
|
||||
},
|
||||
|
||||
@@ -534,7 +534,7 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "RPOP Documentation",
|
||||
"url": "https://redis.io/docs/latest/commands/rpush/",
|
||||
"url": "https://redis.io/docs/latest/commands/rpop/",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -954,8 +954,19 @@
|
||||
},
|
||||
"jrgaoDnt_RxTu79hk4hCD": {
|
||||
"title": "Atomicity in Redis",
|
||||
"description": "Atomicity in Redis refers to the property that ensures a set of operations is executed as a single, indivisible unit. This means that either all the operations are executed successfully or none of them are. Atomicity is crucial in Redis to maintain consistency, especially when multiple operations need to be performed together.\n\nLearn more from the following resources:\n\n* [@official@Atomicity with Lua](https://redis.io/learn/develop/java/spring/rate-limiting/fixed-window/reactive-lua) -[@article@Atomicity in Redis operations](https://lucaspin.medium.com/atomicity-in-redis-operations-a1d7bc9f4a90)",
|
||||
"links": []
|
||||
"description": "Atomicity in Redis refers to the property that ensures a set of operations is executed as a single, indivisible unit. This means that either all the operations are executed successfully or none of them are. Atomicity is crucial in Redis to maintain consistency, especially when multiple operations need to be performed together.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Atomicity with Lua",
|
||||
"url": "https://redis.io/learn/develop/java/spring/rate-limiting/fixed-window/reactive-lua",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Atomicity in Redis operations",
|
||||
"url": "https://lucaspin.medium.com/atomicity-in-redis-operations-a1d7bc9f4a90",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"LHlwjN3WHYUBUafzzwsWQ": {
|
||||
"title": "Pipelining",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -638,15 +638,15 @@
|
||||
"title": "CHECK",
|
||||
"description": "A `CHECK` constraint in SQL is used to enforce data integrity by specifying a condition that must be true for each row in a table. It allows you to define custom rules or restrictions on the values that can be inserted or updated in one or more columns. `CHECK` constraints help maintain data quality by preventing invalid or inconsistent data from being added to the database, ensuring that only data meeting specified criteria is accepted.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "CHECK - PostgreSQL",
|
||||
"url": "https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-check/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "SQL CHECK Constraint",
|
||||
"url": "https://www.w3schools.com/sql/sql_check.asp",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "CHECK Constraint",
|
||||
"url": "https://www.youtube.com/watch?v=EeG2boJCXbc",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
2082
public/roadmap-content/system-design.json
Normal file
2082
public/roadmap-content/system-design.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,29 @@
|
||||
{
|
||||
"h6qRrUe-bn25s0UkxU600": {
|
||||
"title": "Introduction",
|
||||
"description": "Terraform is a powerful tool designed by HashiCorp that helps you set up, manage, and update infrastructure safely and efficiently across various cloud providers. Think of it as a way to define your cloud resources—like servers, storage, and networks—using a simple code format. This makes it easier to automate, share, and manage your infrastructure, ensuring that everything is consistent and can be quickly reproduced or modified as needed.",
|
||||
"links": []
|
||||
"description": "Terraform is a powerful tool designed by HashiCorp that helps you set up, manage, and update infrastructure safely and efficiently across various cloud providers. Think of it as a way to define your cloud resources—like servers, storage, and networks—using a simple code format. This makes it easier to automate, share, and manage your infrastructure, ensuring that everything is consistent and can be quickly reproduced or modified as needed.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform Website",
|
||||
"url": "https://www.terraform.io/",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terraform Documentation",
|
||||
"url": "https://developer.hashicorp.com/terraform",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Explore top posts about Terraform",
|
||||
"url": "https://app.daily.dev/tags/terraform?ref=roadmapsh",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terraform for Beginners",
|
||||
"url": "https://www.youtube.com/watch?v=SLB_c_ayRMo",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
},
|
||||
"CU9V3iRdssamsG-xMouXT": {
|
||||
"title": "What is Terraform?",
|
||||
@@ -30,7 +51,7 @@
|
||||
"description": "Using Terraform offers numerous benefits. It allows you to define your infrastructure as code (IaC), making it human-readable, versioned, and shareable. Its multi-cloud support means you can manage resources consistently across various cloud providers and on-premises environments. By automating infrastructure provisioning and management, Terraform reduces manual errors and speeds up deployments. Version control integration ensures you can track changes, roll back when needed, and collaborate effectively with team members. Terraform's use of templates and modules ensures configuration consistency and reusability across projects and environments, while its state management capabilities keep track of existing resources for efficient updates.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Use Cases",
|
||||
"title": "Use Cases of Terraform",
|
||||
"url": "https://developer.hashicorp.com/terraform/intro/use-cases#use-cases",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -48,10 +69,15 @@
|
||||
},
|
||||
"AYtBLFU1nowEq-EVlXrEZ": {
|
||||
"title": "Installing Terraform",
|
||||
"description": "Follow the instructions given in the following URL to install terraform:",
|
||||
"description": "To install Terraform, you need to download the appropriate package for your operating system from the official Terraform website. After downloading, unzip the package and move the executable to a directory included in your system's PATH. This allows you to run Terraform commands from the terminal. For more detailed installation instructions, refer to the links below.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Installing Terraform",
|
||||
"title": "Install Terraform",
|
||||
"url": "https://developer.hashicorp.com/terraform/install",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Installing Terraform CLI",
|
||||
"url": "https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -90,8 +116,13 @@
|
||||
},
|
||||
"GlIXmCuvR_C81RMeMM1Kz": {
|
||||
"title": "Project Initialization",
|
||||
"description": "Project initialization in Terraform involves setting up the necessary configuration files and directory structure for managing infrastructure as code. The `terraform init` command is crucial in this process, as it initializes the working directory, downloads the required provider plugins, and sets up the backend configuration for storing state files. This command ensures that the project is correctly configured and ready for subsequent Terraform commands, laying the foundation for efficient and organized infrastructure management.\n\nLearn more from the following resources:\n\n\\-[@official@Init Command](https://developer.hashicorp.com/terraform/cli/commands/init)",
|
||||
"description": "Project initialization in Terraform involves setting up the necessary configuration files and directory structure for managing infrastructure as code. The `terraform init` command is crucial in this process, as it initializes the working directory, downloads the required provider plugins, and sets up the backend configuration for storing state files. This command ensures that the project is correctly configured and ready for subsequent Terraform commands, laying the foundation for efficient and organized infrastructure management.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Init Command",
|
||||
"url": "https://developer.hashicorp.com/terraform/cli/commands/init",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Initialize Terraform Configuration",
|
||||
"url": "https://developer.hashicorp.com/terraform/tutorials/cli/init",
|
||||
@@ -188,7 +219,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "https://developer.hashicorp.com/terraform/language",
|
||||
"title": "Terraform Language Documentation",
|
||||
"url": "https://developer.hashicorp.com/terraform/language",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -218,7 +249,18 @@
|
||||
"Hma2IgatFME8STHPwpeMG": {
|
||||
"title": "What is HCL?",
|
||||
"description": "HCL, or HashiCorp Configuration Language, is a human-readable language for DevOps tools. It is used to code infrastructure management and service orchestration in a clear and manageable way. Several HashiCorp products, including Terraform, use HCL as their primary configuration language. Terraform uses HCL to provision and manage cloud resources efficiently. Its clear syntax and structure are instrumental in creating resource modules and configurations that align with the Terraform Roadmap's goals for providing a seamless, user-friendly platform for infrastructure as code.",
|
||||
"links": []
|
||||
"links": [
|
||||
{
|
||||
"title": "hashicorp/hcl",
|
||||
"url": "https://github.com/hashicorp/hcl",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Syntax - Configuration Language | Terraform",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/syntax/configuration",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"LaD0H7XhoEEaXbcwjxAbw": {
|
||||
"title": "Basic Syntax",
|
||||
@@ -233,7 +275,7 @@
|
||||
},
|
||||
"BYydmFc2e-YPCC4MCWmh2": {
|
||||
"title": "Resources",
|
||||
"description": "Resources represent components of your infrastructure such as Virtual Machines, Storage Buckets, Databases or Virtual Private Clouds. Access to provider resources comes after successful project initalization after declaring your desired providers.\n\nLearn more from the following resources:",
|
||||
"description": "Resources represent components of your infrastructure such as Virtual Machines, Storage Buckets, Databases or Virtual Private Clouds. Access to provider resources comes after successful project initialization after declaring your desired providers.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Resource Blocks",
|
||||
@@ -323,7 +365,7 @@
|
||||
},
|
||||
"gcdg_GhAacIWzv19ITTE_": {
|
||||
"title": "for_each",
|
||||
"description": "The for\\_each meta-argument in Terraform enables you to create multiple instances of a resource based on a set or map. Unlike count, which uses a simple integer, for\\_each allows for more granular and dynamic resource creation, as each instance is associated with a specific key-value pair from the given set or map. This meta-argument is particularly useful for creating resources with unique configurations derived from the keys and values of the set or map. By leveraging for\\_each, you can manage collections of resources more efficiently, ensuring each instance can be individually referenced and customized based on its specific key.\n\nNote: You cannot declare for\\_each and count in the same resource.\n\nLearn more from the following resources:",
|
||||
"description": "The for\\_each meta-argument in Terraform enables you to create multiple instances of a resource based on a set or map. Unlike count, which uses a simple integer, for\\_each allows for more granular and dynamic resource creation, as each instance is associated with a specific key-value pair from the given set or map. This meta-argument is particularly useful for creating resources with unique configurations derived from the keys and values of the set or map. By leveraging for\\_each, you can manage collections of resources more efficiently, ensuring each instance can be individually referenced and customized based on its specific key.\n\nNote: You cannot declare `for_each` and `count` in the same resource.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform Docs - for_each",
|
||||
@@ -447,7 +489,7 @@
|
||||
"description": "Terraform variable type constraints specify allowed data types for input variables. They include primitive types (string, number, bool), complex types (list, set, map, object), and any for unspecified types. Constraints can enforce specific structures, nested types, or value ranges. They're defined in the variable block's type argument, helping catch errors early and ensuring correct variable usage throughout configurations.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Variable Type Contraints",
|
||||
"title": "Variable Type Constraints",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/expressions/type-constraints",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -460,7 +502,7 @@
|
||||
},
|
||||
"fm8oUyNvfdGWTgLsYANUr": {
|
||||
"title": "Environment Variables",
|
||||
"description": "Environment variables can be used to customize various aspects of Terraform. You can set these variables to change the default behaviour of terraform such as increase verbosity, update log file path, set workspace, etc. Envrionment variables are optional and terraform does not need them by default.\n\nLearn more from the following resources:",
|
||||
"description": "Environment variables can be used to customize various aspects of Terraform. You can set these variables to change the default behaviour of terraform such as increase verbosity, update log file path, set workspace, etc. Environment variables are optional and terraform does not need them by default.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Environment Variables",
|
||||
@@ -540,10 +582,10 @@
|
||||
{
|
||||
"title": "Hashicorp Output Tutorial",
|
||||
"url": "https://developer.hashicorp.com/terraform/tutorials/configuration-language/outputs",
|
||||
"type": "course"
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Declaring an output value",
|
||||
"title": "Declaring an Output Value",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/values/outputs#declaring-an-output-value",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -585,7 +627,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Using Precondition and Postcondition Blocks in Terraform",
|
||||
"title": "Using Precondition and Post-condition Blocks in Terraform",
|
||||
"url": "https://www.youtube.com/watch?v=55ZLu8tSnvk",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -643,7 +685,7 @@
|
||||
"description": "The validate command helps you make sure your Terraform code is syntactically correct before you deploy. This helps you to prevent misconfiguration due to missing attributes or incorrect dependencies, saving time, improving efficiency, and reducing cost.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform Validate practical examples",
|
||||
"title": "Terraform Validate Examples",
|
||||
"url": "https://www.env0.com/blog/terraform-validate-command-practical-examples-and-best-practices",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -651,7 +693,7 @@
|
||||
},
|
||||
"YftsQYpcqJqBKPjy5tWOq": {
|
||||
"title": "TFLint",
|
||||
"description": "TFLint is a third-party, extensible linter for Terraform code. It performs static analysis of Terraform configurations to detect potential errors, enforce best practices, and maintain code consistency. Key features include: Checking for potential errors that terraform validate might miss, enforcing naming conventions and code style rules, identifying deprecated syntax or resource types and, providing cloud provider-specific checks\n\nTFLint is configurable via .tflint.hcl files and supports custom rules. It can be integrated into CI/CD pipelines for automated code quality checks. While not an official Terraform tool, TFLint is widely used in the Terraform community to complement built-in validation tools and improve overall code quality and reliability in infrastructure-as-code projects.\n\nLearn more from the following resources:",
|
||||
"description": "TFLint is a third-party, extensible linter for Terraform code. It performs static analysis of Terraform configurations to detect potential errors, enforce best practices, and maintain code consistency. Key features include: Checking for potential errors that terraform validate might miss, enforcing naming conventions and code style rules, identifying deprecated syntax or resource types and, providing cloud provider-specific checks.\n\nTFLint is configurable via .tflint.hcl files and supports custom rules. It can be integrated into CI/CD pipelines for automated code quality checks. While not an official Terraform tool, TFLint is widely used in the Terraform community to complement built-in validation tools and improve overall code quality and reliability in infrastructure-as-code projects.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "TFLint Documentation",
|
||||
@@ -709,7 +751,7 @@
|
||||
},
|
||||
"LDpj-LY_SOXzno04D-Y25": {
|
||||
"title": "terraform apply",
|
||||
"description": "`terraform apply` is the command used to implement the changes defined in your Terraform configuration files. It creates, updates, or deletes the specified infrastructure resources to match the desired state. Before making changes, it shows a plan similar to terraform plan and prompts for confirmation, unless the -auto-approve flag is used. Apply updates the state file to reflect the current infrastructure state, enabling Terraform to track and manage resources over time. It handles dependencies between resources, creating them in the correct order.\n\nLearn more from the following resoureces:",
|
||||
"description": "`terraform apply` is the command used to implement the changes defined in your Terraform configuration files. It creates, updates, or deletes the specified infrastructure resources to match the desired state. Before making changes, it shows a plan similar to terraform plan and prompts for confirmation, unless the -auto-approve flag is used. Apply updates the state file to reflect the current infrastructure state, enabling Terraform to track and manage resources over time. It handles dependencies between resources, creating them in the correct order.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Apply Terraform configuration",
|
||||
@@ -730,8 +772,19 @@
|
||||
},
|
||||
"KXlLlaR0_S7gE_ZB1hNEd": {
|
||||
"title": "Inspect / Modify State",
|
||||
"description": "Terraform provides tools to inspect and modify state, enabling management of tracked resources without altering the actual infrastructure. These capabilities allow users to view the current state in human-readable format, list all resources in the state, and obtain detailed information on specific resources. For state modification, Terraform offers methods to move resources within the state or to different state files, remove resources from state without deleting the actual resource, and update the state to match real-world infrastructure. These tools are crucial for reconciling discrepancies between Terraform's state and actual infrastructure, and for managing resources across different Terraform configurations or workspaces. However, state modifications should be performed cautiously, as improper changes can lead to inconsistencies between the state and the actual infrastructure.",
|
||||
"links": []
|
||||
"description": "Terraform provides tools to inspect and modify state, enabling management of tracked resources without altering the actual infrastructure. These capabilities allow users to view the current state in human-readable format, list all resources in the state, and obtain detailed information on specific resources. For state modification, Terraform offers methods to move resources within the state or to different state files, remove resources from state without deleting the actual resource, and update the state to match real-world infrastructure. These tools are crucial for reconciling discrepancies between Terraform's state and actual infrastructure, and for managing resources across different Terraform configurations or workspaces. However, state modifications should be performed cautiously, as improper changes can lead to inconsistencies between the state and the actual infrastructure.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Inspecting State",
|
||||
"url": "https://developer.hashicorp.com/terraform/cli/state/inspect",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "How to Manage Terraform State: A Step-by-Step Guide",
|
||||
"url": "https://meriemterki.medium.com/how-to-manage-terraform-state-a-step-by-step-guide-b615bd6ee0de",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"vAFFgKSthyj_3Lxt-Z6pg": {
|
||||
"title": "graph",
|
||||
@@ -764,7 +817,7 @@
|
||||
"description": "The terraform list command is used to display a list of resources within the Terraform state. It provides a quick overview of all the resources currently being managed by Terraform in your configuration. This command is particularly useful when working with large or complex infrastructures, allowing developers to quickly see what resources are under Terraform's control. The output includes the resource type and name for each managed resource, making it easy to identify specific elements of your infrastructure. It's often used in conjunction with other state manipulation commands to verify the contents of the state or to identify resources for further inspection or modification.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform state list",
|
||||
"title": "Terraform State List",
|
||||
"url": "https://developer.hashicorp.com/terraform/cli/commands/state/list",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -883,7 +936,7 @@
|
||||
},
|
||||
"L7wAMGi_yU-Bbc9fXlmxZ": {
|
||||
"title": "Import Existing Resources",
|
||||
"description": "terraform state import is a command used to bring existing resources under Terraform management. It allows you to add resources that were created outside of Terraform (e.g., manually or by other tools) into your Terraform state. The command takes two main arguments: the Terraform resource address and the real-world resource identifier. When executed, it adds the resource to the state file without modifying the actual infrastructure. This is useful for adopting Terraform in environments with existing resources, or for recovering from scenarios where state and reality have diverged. After importing, you need to write the corresponding configuration in your Terraform files to match the imported resource.\n\nIn Terraform v1.5.0 and later you can also create `import` blocks in any Terraform configuration file.\n\nLearn more from the following resources:",
|
||||
"description": "Terraform state import is a command used to bring existing resources under Terraform management. It allows you to add resources that were created outside of Terraform (e.g., manually or by other tools) into your Terraform state. The command takes two main arguments: the Terraform resource address and the real-world resource identifier. When executed, it adds the resource to the state file without modifying the actual infrastructure. This is useful for adopting Terraform in environments with existing resources, or for recovering from scenarios where state and reality have diverged. After importing, you need to write the corresponding configuration in your Terraform files to match the imported resource.\n\nIn Terraform v1.5.0 and later you can also create `import` blocks in any Terraform configuration file.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform import command",
|
||||
@@ -978,7 +1031,7 @@
|
||||
},
|
||||
"jvHtSRLuCXJrGIiesgbE-": {
|
||||
"title": "-replace option in apply",
|
||||
"description": "The -replace flag in Terraform is used with the apply or plan command to force the replacement of a specific resource by tainting the resources. This flag instructs Terraform to delete and recreate the specified resource instead of updating it in place. It's useful when you need to regenerate a resource completely, such as when certain attributes can't be modified after creation. The flag is typically used when Terraform can't automatically detect that a resource needs replacement, or when you want to force a replacement for testing or troubleshooting purposes. While powerful, this flag should be used cautiously, especially with stateful resources, as it can lead to data loss. It's often employed in scenarios where in-place updates are not sufficient to achieve the desired configuration state of a resource.\n\nLearn more from the following resources:",
|
||||
"description": "The `-replace` flag in Terraform is used with the apply or plan command to force the replacement of a specific resource by tainting the resources. This flag instructs Terraform to delete and recreate the specified resource instead of updating it in place. It's useful when you need to regenerate a resource completely, such as when certain attributes can't be modified after creation. The flag is typically used when Terraform can't automatically detect that a resource needs replacement, or when you want to force a replacement for testing or troubleshooting purposes. While powerful, this flag should be used cautiously, especially with stateful resources, as it can lead to data loss. It's often employed in scenarios where in-place updates are not sufficient to achieve the desired configuration state of a resource.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Forcing Re-creation of Resources",
|
||||
@@ -1002,7 +1055,7 @@
|
||||
"description": "The terraform show command displays a human-readable view of the current state or a saved plan file. When used without arguments, it presents the current state of the managed infrastructure, including all resources and their attributes. If given a path to a saved plan file, it shows the changes that would be made by applying that plan. This command is useful for inspecting the current state of your infrastructure, verifying the details of specific resources, or reviewing planned changes before applying them. It provides a comprehensive overview of your Terraform-managed resources, making it valuable for debugging, auditing, and understanding the current state of your infrastructure. The output includes sensitive information if present, so care should be taken when sharing or displaying the results in unsecured environments.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terrform show",
|
||||
"title": "Terraform show",
|
||||
"url": "https://developer.hashicorp.com/terraform/cli/commands/show",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1039,12 +1092,12 @@
|
||||
"description": "The terraform state mv command is used to move resources within a Terraform state or between separate state files. It allows for reorganizing the state without modifying the actual infrastructure. This command is useful when refactoring Terraform configurations, moving resources between modules, or splitting a large state file into smaller ones. It takes two arguments: the source and destination addresses of the resource. The command updates all references to the moved resource, ensuring that future operations correctly target the resource at its new location. This functionality is particularly valuable when restructuring complex projects or adapting to changing organizational needs. However, it should be used cautiously, as incorrect moves can lead to state inconsistencies.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform state mv",
|
||||
"title": "Terraform State mv",
|
||||
"url": "https://developer.hashicorp.com/terraform/cli/commands/state/mv",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Moving resoureces",
|
||||
"title": "Moving Resources",
|
||||
"url": "https://developer.hashicorp.com/terraform/cli/state/move",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1057,8 +1110,24 @@
|
||||
},
|
||||
"R2AORYmc1NgGTqLZY5Fu-": {
|
||||
"title": "Modules",
|
||||
"description": "Terraform modules are reusable components that encapsulate a set of resources, their configurations, and their interconnections. They allow for organizing Terraform code into logical, self-contained units that can be shared and reused across different projects or within the same project. Modules promote code reusability, maintainability, and consistency in infrastructure deployments. They can accept input variables, produce output values, and be nested within other modules. By using modules, teams can create standardized infrastructure components, enforce best practices, and simplify complex configurations. Modules can be sourced from local directories, version control systems, or public registries like the Terraform Registry. Effective use of modules can significantly reduce code duplication, improve infrastructure management, and enable the creation of scalable, maintainable Terraform configurations.",
|
||||
"links": []
|
||||
"description": "Terraform modules are reusable components that encapsulate a set of resources, their configurations, and their interconnections. They allow for organizing Terraform code into logical, self-contained units that can be shared and reused across different projects or within the same project. Modules promote code reusability, maintainability, and consistency in infrastructure deployments. They can accept input variables, produce output values, and be nested within other modules. By using modules, teams can create standardized infrastructure components, enforce best practices, and simplify complex configurations. Modules can be sourced from local directories, version control systems, or public registries like the Terraform Registry. Effective use of modules can significantly reduce code duplication, improve infrastructure management, and enable the creation of scalable, maintainable Terraform configurations.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Modules Overview - Configuration Language | Terraform",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/modules",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terraform Modules",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/modules",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Modules - Terraform Registry",
|
||||
"url": "https://registry.terraform.io/browse/modules",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"6W4_akHG9YtvN6dpbZnG-": {
|
||||
"title": "Root vs Child Modules",
|
||||
@@ -1128,7 +1197,7 @@
|
||||
"description": "Module inputs and outputs in Terraform facilitate the flow of data into and out of modules, enabling customization and data sharing. Inputs are defined using variable blocks within a module and allow the module's behavior to be customized when it's used. They can have default values and type constraints.\n\nWhen calling a module, inputs are provided as arguments. Outputs, defined using output blocks, expose specific values from the module's resources, making them available to the calling module. This allows for data to be passed between modules or to be used in other parts of the configuration. Outputs can include computed values, resource attributes, or any Terraform expression. Properly designed inputs and outputs are crucial for creating flexible, reusable modules that can be easily integrated into various configurations.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Accessing module output values",
|
||||
"title": "Accessing Module Output Values",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/modules/syntax#accessing-module-output-values",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1139,7 +1208,7 @@
|
||||
"description": "Terraform module best practices focus on creating reusable, maintainable, and scalable infrastructure components.\n\n* Modules should have a single, clear purpose and be designed with flexibility in mind, using input variables for customization.\n* Outputs should be carefully chosen to provide necessary information without over-exposing internal details.\n* Version your modules and use semantic versioning to manage changes.\n* Keep modules small and focused, adhering to the single responsibility principle.\n* Document your modules thoroughly, including usage examples and input/output descriptions.\n* Use consistent naming conventions and structure across modules.\n* Test modules in isolation and as part of larger systems.\n* Avoid hard-coding values that might change across environments.\n* Consider using nested modules for complex structures, but be mindful of over-nesting.\n* Regularly review and refactor modules to incorporate improvements and maintain best practices.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Module best practices",
|
||||
"title": "Module Best Practices",
|
||||
"url": "https://developer.hashicorp.com/terraform/tutorials/modules/module#module-best-practices",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1157,15 +1226,21 @@
|
||||
},
|
||||
"6vs1VvjeILgAPLL6g7dfy": {
|
||||
"title": "Provisioners",
|
||||
"description": "Provisioners in Terraform are used to execute scripts or other actions on local or remote machines as part of resource creation or destruction. They allow for configuration management tasks that go beyond Terraform's declarative model. Provisioners can run scripts, upload files, or execute other tools on resources after they're created. Common types include local-exec (runs commands on the machine running Terraform) and remote-exec (runs commands on a remote resource). While powerful, provisioners should be used sparingly as they can make Terraform runs less predictable and idempotent. They're often seen as a last resort when native Terraform resources or provider capabilities are insufficient. Best practices suggest using dedicated configuration management tools like Ansible or Chef instead of heavy reliance on provisioners. When used, provisioners should be designed to be idempotent and handle potential failures gracefully.",
|
||||
"links": []
|
||||
"description": "Provisioners in Terraform are used to execute scripts or other actions on local or remote machines as part of resource creation or destruction. They allow for configuration management tasks that go beyond Terraform's declarative model. Provisioners can run scripts, upload files, or execute other tools on resources after they're created. Common types include local-exec (runs commands on the machine running Terraform) and remote-exec (runs commands on a remote resource). While powerful, provisioners should be used sparingly as they can make Terraform runs less predictable and idempotent. They're often seen as a last resort when native Terraform resources or provider capabilities are insufficient. Best practices suggest using dedicated configuration management tools like Ansible or Chef instead of heavy reliance on provisioners. When used, provisioners should be designed to be idempotent and handle potential failures gracefully.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Provisioners - Terraform",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/resources/provisioners/syntax",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"CmmoshFC1dKE4y3SMN2bl": {
|
||||
"title": "When to Use?",
|
||||
"description": "Provisioners in Terraform should be used judiciously, primarily when other declarative options are insufficient. They're appropriate for tasks that can't be accomplished through Terraform's resource configurations or data sources. Common scenarios include running initialization scripts on newly created servers, installing software not covered by provider-specific resources, or performing one-time setup tasks. Provisioners are useful for bootstrapping configuration management tools or handling complex, stateful operations that Terraform can't manage directly. However, they should be considered a last resort due to their potential to make Terraform runs less predictable and harder to manage. Whenever possible, prefer using cloud-init scripts, custom images, or separate configuration management tools. When provisioners are necessary, design them to be idempotent and resilient to failures to maintain Terraform's desired state consistency.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "My thoughts on why you should use Terraform Provisioners as a final option",
|
||||
"title": "Why You should Use Terraform Provisioners as a Final Option",
|
||||
"url": "https://thomasthornton.cloud/2023/05/11/my-thoughts-on-why-you-should-use-terraform-provisioners-as-a-final-option/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1181,12 +1256,12 @@
|
||||
"description": "Creation and destroy-time provisioners in Terraform are used to execute actions at specific points in a resource's lifecycle. Creation-time provisioners run after a resource is created, while destroy-time provisioners run before a resource is destroyed. Creation-time provisioners are useful for tasks like initializing a newly created server, installing software, or configuring applications. Destroy-time provisioners are typically used for cleanup tasks, such as deregistering a server from a load balancer before deletion. Both types can be specified within a resource block.\n\nCreation-time provisioners that fail will cause the resource creation to fail, potentially leaving resources in an incomplete state. Destroy-time provisioners that fail don't prevent resource destruction but may leave external resources in an inconsistent state. Due to their potential impact on Terraform's ability to manage state consistently, both types should be used cautiously and designed to be idempotent and fault-tolerant.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Creation time provisioners",
|
||||
"title": "Creation Time Provisioners",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/resources/provisioners/syntax#creation-time-provisioners",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Destroy time provisioners",
|
||||
"title": "Destroy Time Provisioners",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/resources/provisioners/syntax#destroy-time-provisioners",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1202,12 +1277,12 @@
|
||||
"description": "The Terraform file provisioner is used to copy files or directories from the machine running Terraform to a newly created resource. It's useful for tasks like uploading configuration files, scripts, or other necessary data to remote systems. The file provisioner can copy a single file or recursively copy directories. It supports both source and content arguments, allowing for either file-based or inline content transfers. This provisioner is often used in conjunction with remote-exec provisioners to execute uploaded scripts. While convenient for simple file transfers, it's important to consider security implications, especially when dealing with sensitive data. For more complex or large-scale file management tasks, dedicated configuration management tools are often preferred. The file provisioner is best used for small, straightforward file transfers needed to bootstrap or configure newly created resources.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform file provisioner",
|
||||
"title": "Terraform File Provisioner",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/resources/provisioners/file",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "The file provisioner",
|
||||
"title": "The File Provisioner",
|
||||
"url": "https://learning-ocean.com/tutorials/terraform/terraform-file-provisioner/",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1260,12 +1335,12 @@
|
||||
"description": "Terraform custom provisioners allow developers to extend Terraform's provisioning capabilities beyond the built-in options. These are created using Go programming language and the Terraform plugin SDK. Custom provisioners can perform specialized tasks tailored to specific infrastructure needs or organizational requirements. They follow the same lifecycle as built-in provisioners, executing during resource creation or destruction.\n\nDeveloping custom provisioners requires a deep understanding of Terraform's architecture and Go programming. They're useful for integrating Terraform with proprietary systems or implementing complex, organization-specific provisioning logic. However, custom provisioners should be approached cautiously, as they increase maintenance overhead and can complicate Terraform upgrades. In many cases, it's preferable to use existing provisioners or separate configuration management tools unless there's a compelling need for custom functionality.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform provisioners",
|
||||
"title": "Terraform Provisioners",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/resources/provisioners/syntax",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terraform provisioners - Why you should avoid them",
|
||||
"title": "Terraform Provisioners - Why you should avoid them",
|
||||
"url": "https://spacelift.io/blog/terraform-provisioners",
|
||||
"type": "article"
|
||||
}
|
||||
@@ -1336,7 +1411,7 @@
|
||||
},
|
||||
"Os6AOXp1CVI_Bh3NYnX17": {
|
||||
"title": "state replace-provider",
|
||||
"description": "The `terraform state replace-provider` command in Terraform is used to update the provider information in the state file without altering the actual infrastructure. This command is particularly useful when migrating from one provider to another, or when updating to a new major version of a provider that involves a change in the provider's namespace. It allows users to change the provider associated with resources in the state file, effectively telling Terraform to use a different provider for managing these resources in future operations. This command is crucial for maintaining state consistency during provider transitions or upgrades, especially in large-scale infrastructures. While it doesn't modify the actual resources, it updates Terraform's understanding of which provider should be used to manage them, facilitating smooth provider migrations without requiring resource recreation.\n\nLearn more from the following resources:",
|
||||
"description": "The terraform `state replace-provider` command in Terraform is used to update the provider information in the state file without altering the actual infrastructure. This command is particularly useful when migrating from one provider to another, or when updating to a new major version of a provider that involves a change in the provider's namespace. It allows users to change the provider associated with resources in the state file, effectively telling Terraform to use a different provider for managing these resources in future operations. This command is crucial for maintaining state consistency during provider transitions or upgrades, especially in large-scale infrastructures. While it doesn't modify the actual resources, it updates Terraform's understanding of which provider should be used to manage them, facilitating smooth provider migrations without requiring resource recreation.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Command - state replace-provider",
|
||||
@@ -1347,7 +1422,7 @@
|
||||
},
|
||||
"Trpi2ZlnXZVYJCibE2bQ8": {
|
||||
"title": "state force-unlock",
|
||||
"description": "The `terraform state force-unlock` command in Terraform is used to manually release a stuck state lock. State locking is a mechanism that prevents concurrent operations on the same state, but occasionally a lock may not be properly released due to crashes or network issues. This command allows administrators to forcibly remove the lock, enabling further Terraform operations to proceed. It should be used with extreme caution, as it can lead to state corruption if multiple users are attempting to modify the state simultaneously. Before using force-unlock, it's crucial to ensure that no other Terraform operations are genuinely in progress. This command is typically a last resort for resolving locking issues and should only be employed when certain that the lock is erroneously held and no conflicting operations are ongoing.\n\nLearn more from the following resources:",
|
||||
"description": "The terraform `state force-unlock` command in Terraform is used to manually release a stuck state lock. State locking is a mechanism that prevents concurrent operations on the same state, but occasionally a lock may not be properly released due to crashes or network issues. This command allows administrators to forcibly remove the lock, enabling further Terraform operations to proceed. It should be used with extreme caution, as it can lead to state corruption if multiple users are attempting to modify the state simultaneously. Before using force-unlock, it's crucial to ensure that no other Terraform operations are genuinely in progress. This command is typically a last resort for resolving locking issues and should only be employed when certain that the lock is erroneously held and no conflicting operations are ongoing.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Command: force-unlock",
|
||||
@@ -1401,6 +1476,11 @@
|
||||
"url": "https://github.com/hashicorp/setup-terraform",
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Actions",
|
||||
"url": "https://docs.github.com/en/actions",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Automate Terraform with GitHub Actions",
|
||||
"url": "https://developer.hashicorp.com/terraform/tutorials/automation/github-actions",
|
||||
@@ -1423,7 +1503,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Deploy infrastructure with Terraform and CircleCI",
|
||||
"title": "Deploy Infrastructure with Terraform and CircleCI",
|
||||
"url": "https://developer.hashicorp.com/terraform/tutorials/automation/circle-ci",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1486,13 +1566,13 @@
|
||||
"description": "Terraform unit testing focuses on verifying the behavior of individual modules or components in isolation. It typically involves creating small, focused test cases that validate the expected outputs and resource configurations of a module given specific inputs. Tools like Terratest, a Go library, are commonly used for writing and running these tests. Unit tests for Terraform might check if resources are correctly defined, if count and for\\_each meta-arguments work as expected, or if output values are calculated correctly. These tests often use mock data or minimal real infrastructure to simulate various scenarios. While they don't guarantee the actual creation of resources, unit tests are valuable for quickly catching logic errors, ensuring module interfaces work as intended, and maintaining code quality as modules evolve.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform unit tests",
|
||||
"url": "https://www.hashicorp.com/blog/testing-hashicorp-terraform#unit-tests",
|
||||
"title": "Integration or Unit Testing",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/tests#integration-or-unit-testing",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Integration or unit testing",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/tests#integration-or-unit-testing",
|
||||
"title": "Terraform Unit Tests",
|
||||
"url": "https://www.hashicorp.com/blog/testing-hashicorp-terraform#unit-tests",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -1523,7 +1603,7 @@
|
||||
"description": "Terraform integration testing involves verifying that Terraform configurations work correctly with actual cloud resources and services. These tests create real infrastructure components, interact with them, and then destroy them, ensuring that resources are properly provisioned and configured in a live environment. Integration tests typically use frameworks like Terratest or custom scripts to automate the process of applying Terraform configurations, validating the resulting infrastructure, and cleaning up afterwards. They check for correct resource creation, proper configuration of interdependent resources, and overall system behavior. While more time-consuming and potentially costly than unit tests, integration tests provide high confidence in the reliability of Terraform code in real-world scenarios. They're crucial for catching issues that may only appear when interacting with actual cloud services, such as API limitations or unexpected service behaviors.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Integration or unit testing",
|
||||
"title": "Integration Testing or Unit Testing",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/tests#integration-or-unit-testing",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1565,17 +1645,17 @@
|
||||
"description": "Testing Terraform modules involves validating their functionality, reusability, and correctness in isolation and as part of larger systems. This process typically includes unit testing to verify individual module behavior, integration testing to ensure proper interaction with other components, and sometimes end-to-end testing for complex modules. Tests often use tools like Terratest or custom scripts to automate the creation of resources, verification of outputs, and cleanup. Key aspects include testing various input combinations, verifying resource attributes and outputs, and ensuring idempotency. Module testing also involves checking for proper handling of edge cases and error conditions. While it requires initial setup effort, thorough module testing enhances reliability, facilitates refactoring, and improves overall infrastructure code quality.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Write Terraform tests",
|
||||
"title": "Write Terraform Tests",
|
||||
"url": "https://developer.hashicorp.com/terraform/tutorials/configuration-language/test",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terraform test",
|
||||
"title": "Terraform Test",
|
||||
"url": "https://developer.hashicorp.com/terraform/language/tests",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terraform module testing",
|
||||
"title": "Terraform Module Testing",
|
||||
"url": "https://www.youtube.com/watch?v=1LInIWM_2UQ",
|
||||
"type": "video"
|
||||
}
|
||||
@@ -1674,6 +1754,11 @@
|
||||
"title": "Secret Management",
|
||||
"description": "Terraform secret management is a critical aspect of secure infrastructure-as-code practices, focusing on the protection of sensitive information like API keys, passwords, and access tokens. Instead of storing secrets directly in Terraform files, best practices advocate for using external secret management systems such as HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault. These systems allow Terraform to retrieve secrets securely during execution, significantly reducing the risk of exposure. For local development, tools like git-crypt or SOPS provide encryption for sensitive files, while Terraform's built-in encrypted state storage options safeguard secrets in state files. By marking variables as sensitive, accidental logging of secret values can be prevented. In CI/CD pipelines, it's crucial to inject secrets securely at runtime and avoid committing them to version control systems. Regular rotation of secrets and access audits further enhance security.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Inject Secrets with Vault",
|
||||
"url": "https://developer.hashicorp.com/terraform/tutorials/secrets",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terraform Secrets - How to manage them",
|
||||
"url": "https://spacelift.io/blog/terraform-secrets",
|
||||
@@ -1683,11 +1768,6 @@
|
||||
"title": "A comprehensive guide to managing secrets in your Terraform code",
|
||||
"url": "https://blog.gruntwork.io/a-comprehensive-guide-to-managing-secrets-in-your-terraform-code-1d586955ace1",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Inject secrets with Vault",
|
||||
"url": "https://developer.hashicorp.com/terraform/tutorials/secrets",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1756,8 +1836,19 @@
|
||||
},
|
||||
"3MnZK2V5KhBhw67SyUVPk": {
|
||||
"title": "Security",
|
||||
"description": "Terraform security encompasses practices and tools to ensure the safe and compliant management of infrastructure-as-code. Key aspects include securing Terraform state files, which often contain sensitive information, by using encrypted remote backends. Access control is crucial, implementing least privilege principles for both human users and service accounts. Sensitive data management involves using vault systems or cloud-native secret managers rather than hardcoding credentials. Code review processes should include security checks, and automated scanning tools can be integrated to detect misconfigurations or policy violations. Implementing compliance-as-code with tools like Terraform Sentinel ensures adherence to organizational policies. Version control and proper git hygiene help maintain audit trails.",
|
||||
"links": []
|
||||
"description": "Terraform security encompasses practices and tools to ensure the safe and compliant management of infrastructure-as-code. Key aspects include securing Terraform state files, which often contain sensitive information, by using encrypted remote backends. Access control is crucial, implementing least privilege principles for both human users and service accounts. Sensitive data management involves using vault systems or cloud-native secret managers rather than hardcoding credentials. Code review processes should include security checks, and automated scanning tools can be integrated to detect misconfigurations or policy violations. Implementing compliance-as-code with tools like Terraform Sentinel ensures adherence to organizational policies. Version control and proper git hygiene help maintain audit trails.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Terraform Security",
|
||||
"url": "https://www.terraform.io/cloud-docs/architectural-details/security-model",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "12 Terraform Security Best Practices",
|
||||
"url": "https://spacelift.io/blog/terraform-security",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"NSWG79dEygyl6pb54wLrE": {
|
||||
"title": "Terrascan",
|
||||
@@ -1790,7 +1881,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "Checkov Website",
|
||||
"title": "Checkov",
|
||||
"url": "https://www.checkov.io/",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1822,7 +1913,7 @@
|
||||
"description": "HashiCorp Cloud Platform (HCP) offers several enterprise-grade features designed to enhance large-scale infrastructure management:\n\n1. Centralized workflow management for Terraform operations\n2. Advanced role-based access control (RBAC) for fine-grained permissions\n3. Policy as Code with Sentinel for governance and compliance\n4. Private network connectivity for secure access to cloud resources\n5. Audit logging for comprehensive tracking of all platform activities\n6. Integrated secrets management with Vault\n7. Service networking capabilities through Consul\n8. Multi-cloud and hybrid cloud support\n9. Scalable remote state management\n10. Cost estimation and optimization tools\n11. Customizable policy libraries for security and compliance\n12. Single sign-on (SSO) and identity federation\n13. API-driven automation for infrastructure provisioning\n14. Collaborative features for team-based infrastructure development\n15. Continuous compliance monitoring and reporting\n\nThese features collectively provide a robust, secure, and scalable environment for enterprise-level infrastructure management and DevOps practices.\n\nLearn more from the following resources:",
|
||||
"links": [
|
||||
{
|
||||
"title": "HCP Website",
|
||||
"title": "HashiCorp Cloud Platform",
|
||||
"url": "https://www.hashicorp.com/cloud",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1848,7 +1939,7 @@
|
||||
"type": "opensource"
|
||||
},
|
||||
{
|
||||
"title": "hcp auth login",
|
||||
"title": "HCP Authentication",
|
||||
"url": "https://developer.hashicorp.com/hcp/docs/cli/commands/auth/login",
|
||||
"type": "article"
|
||||
},
|
||||
@@ -1911,7 +2002,7 @@
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Terrafrom Registry - Run Tasks",
|
||||
"title": "Terraform Registry - Run Tasks",
|
||||
"url": "https://registry.terraform.io/browse/run-tasks",
|
||||
"type": "article"
|
||||
},
|
||||
|
||||
@@ -471,7 +471,7 @@
|
||||
},
|
||||
"RWYXEZMODUrqwRWf_Lqi9": {
|
||||
"title": "Intersection Types",
|
||||
"description": "An intersection type creates a new type by combining multiple existing types. The new type has all features of the existing types.\n\nTo combine types, you use the `&` operator as follows:\n\n type typeAB = typeA & typeB;\n \n\nThe `typeAB` will have all properties from both typeA and typeB.\n\nNote that the union type uses the `|` operator that defines a variable which can hold a value of either `typeA` or `typeB`\n\nLearn more from the following links:",
|
||||
"description": "An intersection type creates a new type by combining multiple existing types. The new type has all features of the existing types.\n\nTo combine types, you use the `&` operator as follows:\n\n type typeAB = typeA & typeB;\n \n\nThe `typeAB` will have all properties from both typeA and typeB.\n\nNote that the union type uses the `|` operator that defines a variable which can hold `typeA` value, or `typeB` value, or both altogether.\n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Intersection Types in TypeScript",
|
||||
@@ -1051,7 +1051,7 @@
|
||||
]
|
||||
},
|
||||
"16TT8R4N-9tCfWmPetqMP": {
|
||||
"title": "Namespace Agumentation",
|
||||
"title": "Namespace Augmentation",
|
||||
"description": "In TypeScript, namespace augmentation is a way to extend or modify existing namespaces. This is useful when you want to add new functionality to existing namespaces or to fix missing or incorrect declarations in third-party libraries.\n\nHere's an example of how you can use namespace augmentation in TypeScript:\n\n // myModule.d.ts\n declare namespace MyModule {\n export interface MyModule {\n newFunction(): void;\n }\n }\n \n // main.ts\n /// <reference path=\"myModule.d.ts\" />\n namespace MyModule {\n export class MyModule {\n public newFunction() {\n console.log('I am a new function in MyModule!');\n }\n }\n }\n \n const obj = new MyModule.MyModule();\n obj.newFunction(); // Output: \"I am a new function in MyModule!\"\n \n\nIn this example, we use namespace augmentation to add a new function \"newFunction\" to the \"MyModule\" namespace. This is done in the declaration file `myModule.d.ts` by declaring a new interface \"MyModule\" within the \"MyModule\" namespace and adding the \"newFunction\" function to it.\n\nLearn more from the following links:",
|
||||
"links": [
|
||||
{
|
||||
|
||||
@@ -199,9 +199,9 @@
|
||||
"description": "In the UX design process, understanding and working with existing user behavior is crucial. One key aspect of this is the concept of \"replace the routine\". This involves observing and analyzing the current habits and routines of your users, and then designing your product around it.\n\nReplacing the routine in UX design is about finding more efficient, delightful, and engaging ways for users to complete their tasks. You should not look to force a completely new set of behaviors upon your users but instead improve their experience by offering a better alternative to their existing habits.\n\nConsider the following points when replacing the routine:\n\n* **Understand the user's context**: Study the users’ life cycle and create personas to better comprehend their . This helps you identify their preferences, pain points, and habits, which in turn enables the creation of a meaningful and effective design.\n \n* **Identify the existing routine**: Analyze the current habits and routines of your users. What are the steps they are used to taking in order to complete the task? This information will be vital in designing a product that smoothly replaces their existing routine with an improved one.\n \n* **Design an improved routine**: Create a new user flow that achieves the same goal but in a manner that is more efficient, simpler, and more intuitive for the user. This new routine should leverage the knowledge you have gained about your users and their preferences.\n \n* **Test the new routine**: The importance of usability testing cannot be overstated. Validate your design by having real users test it out, and gather feedback to identify any areas that can be further optimized. Ensure that the new routine actually improves upon the existing one and doesn't create any new confusion.\n \n* **Iterate and refine**: UX design is an ongoing process. Continuously refine and optimize the new routine based on the user feedback and changing user behavior trends.\n \n\nBy adopting the \"replace the routine\" approach in your UX design, you can provide your users with a better experience that aligns with their existing behaviors, while also introducing new efficiencies and possibilities. Doing so increases user satisfaction, promotes adoption, and ultimately leads to happier, loyal users.",
|
||||
"links": []
|
||||
},
|
||||
"0MbrHG-VDrdZqQ0jWtiDo": {
|
||||
"title": "Use Consciousness to Intefere",
|
||||
"description": "In UX design, understanding the existing behavior of users is essential to create a seamless and efficient user experience. One way to obtain this understanding is through the concept of \"use consciousness to interfere.\" This method involves taking a conscious and deliberate approach to observing and analyzing user behavior, in order to identify problems or areas of improvement, and then designing solutions based on these insights.\n\nHere's a brief summary of how to use consciousness to interfere in UX design:\n\n* **Observation**: Start by observing users in their natural environment, using your product or interacting with similar products. This will give you valuable insight into their habits, preferences, and challenges.\n \n* **Analysis**: Next, analyze the data you've collected from your observations. Identify patterns, problems, and opportunities for improvement. This might involve breaking down tasks into smaller components, examining specific user flows, or comparing different user groups.\n \n* **Empathy**: Develop a deep empathy for your users, understanding their needs, problems, and motivations. This will help you prioritize features and improvements, and design solutions that genuinely address their needs.\n \n* **Experimentation**: Generate multiple ideas and possible solutions based on your analysis and empathic understanding of users. Test these ideas through rapid prototyping and user testing to get feedback and iterate on your designs.\n \n* **Measure Impact**: Continuously measure the impact of your design changes by monitoring user behavior and key performance indicators (KPIs). This will help you understand the effectiveness of your interventions and inform future design decisions.\n \n\nBy using consciousness to interfere in the UX design process, you gain a deeper understanding of user behavior, enabling you to create more intuitive, engaging, and effective user experiences.",
|
||||
"use-consciousness-to-interfere@0MbrHG-VDrdZqQ0jWtiDo.md": {
|
||||
"title": "Use Consciousness to Interfere",
|
||||
"description": "",
|
||||
"links": []
|
||||
},
|
||||
"d1dXGCHmMF2EFpL5yKVJA": {
|
||||
@@ -387,8 +387,14 @@
|
||||
},
|
||||
"90_M5qABC1vZ1nsXVyqFJ": {
|
||||
"title": "Good Layout Rules",
|
||||
"description": "In the world of UX design, a good layout is crucial to ensure your prototype is intuitive and user-friendly. By following these good layout rules, you can ensure your designs are efficient, attractive, and easy to navigate for users.\n\nConsistency\n-----------\n\nBeing consistent with your design is vital in creating an easy-to-navigate interface. Utilize the same color schemes, typography, and other design elements consistently throughout your prototype to make it visually cohesive and user-friendly.\n\nAlignment and Spacing\n---------------------\n\nEnsure all the elements on your prototype are aligned and spaced properly. This helps create a well-structured and clean look, while also making it easy for users to navigate and understand your design.\n\nVisual Hierarchy\n----------------\n\nEstablish clear visual hierarchy by using size, color, contrast, and white space effectively. This helps users identify important elements on the screen quickly and understand the flow of your design easily.\n\nGrouping of Elements\n--------------------\n\nGroup related elements together, such as navigation menus or form input fields. This helps users recognize the purpose and function of each section more quickly and intuitively.\n\nBalance and Proportion\n----------------------\n\nCreate a balanced and proportional look by distributing elements on the screen evenly. This can be achieved through the use of grids or other layout techniques that help maintain a sense of harmony and order in your design.\n\nAccessibility\n-------------\n\nEnsure your design is accessible to all users by considering factors such as text size, contrast, and color combinations. Aim to create an inclusive prototype that caters to people of different abilities and preferences.\n\nResponsiveness and Flexibility\n------------------------------\n\nMake sure your prototype can adapt to different screen sizes and devices, ensuring a seamless user experience across various platforms. This is particularly important when designing for web and mobile applications.\n\nIterating and Testing\n---------------------\n\nAs you develop your design, continually test and iterate on your layout based on user feedback and data. This process will help refine your design and ensure it meets the needs and expectations of your users.\n\nBy incorporating these good layout rules into your prototyping process, you'll be well on your way to creating a user-friendly and effective design that meets the goals and objectives of your project.",
|
||||
"links": []
|
||||
"description": "In the world of UX design, a good layout is crucial to ensure your prototype is intuitive and user-friendly. By following these good layout rules, you can ensure your designs are efficient, attractive, and easy to navigate for users.\n\nConsistency\n-----------\n\nBeing consistent with your design is vital in creating an easy-to-navigate interface. Utilize the same color schemes, typography, and other design elements consistently throughout your prototype to make it visually cohesive and user-friendly.\n\nAlignment and Spacing\n---------------------\n\nEnsure all the elements on your prototype are aligned and spaced properly. This helps create a well-structured and clean look, while also making it easy for users to navigate and understand your design.\n\nVisual Hierarchy\n----------------\n\nEstablish clear visual hierarchy by using size, color, contrast, and white space effectively. This helps users identify important elements on the screen quickly and understand the flow of your design easily.\n\nGrouping of Elements\n--------------------\n\nGroup related elements together, such as navigation menus or form input fields. This helps users recognize the purpose and function of each section more quickly and intuitively.\n\nBalance and Proportion\n----------------------\n\nCreate a balanced and proportional look by distributing elements on the screen evenly. This can be achieved through the use of grids or other layout techniques that help maintain a sense of harmony and order in your design.\n\nAccessibility\n-------------\n\nEnsure your design is accessible to all users by considering factors such as text size, contrast, and color combinations. Aim to create an inclusive prototype that caters to people of different abilities and preferences.\n\nResponsiveness and Flexibility\n------------------------------\n\nMake sure your prototype can adapt to different screen sizes and devices, ensuring a seamless user experience across various platforms. This is particularly important when designing for web and mobile applications.\n\nIterating and Testing\n---------------------\n\nAs you develop your design, continually test and iterate on your layout based on user feedback and data. This process will help refine your design and ensure it meets the needs and expectations of your users.\n\nBy incorporating these good layout rules into your prototyping process, you'll be well on your way to creating a user-friendly and effective design that meets the goals and objectives of your project.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "User Interface Design Guidelines: 10 Rules of Thumb",
|
||||
"url": "https://www.interaction-design.org/literature/article/user-interface-design-guidelines-10-rules-of-thumb",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
},
|
||||
"t46s6Piyd8MoJYzdDTsjr": {
|
||||
"title": "Figma",
|
||||
|
||||
@@ -234,6 +234,11 @@
|
||||
"title": "Global Properties",
|
||||
"description": "Global properties allows you to add properties or methods that can be accessed throughout your application. This is particularly useful for sharing functionality or data across components without the need to pass props explicitly.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Application API - globalProperties",
|
||||
"url": "https://vuejs.org/api/application.html#app-config-globalproperties",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Vue.js Global Properties",
|
||||
"url": "https://blog.logrocket.com/vue-js-globalproperties/",
|
||||
@@ -374,6 +379,11 @@
|
||||
"title": "v-on",
|
||||
"description": "The v-on directive is placed on an element to attach an event listener. To attach an event listener with v-on we need to provide the event type, and any modifier, and a method or expression that should run when that event occurs.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "v-on Documentation",
|
||||
"url": "https://vuejs.org/api/built-in-directives.html#v-on",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "v-on Directive",
|
||||
"url": "https://www.w3schools.com/vue/ref_v-on.php",
|
||||
@@ -539,7 +549,7 @@
|
||||
"links": [
|
||||
{
|
||||
"title": "Modifiers",
|
||||
"url": "https://v2.vuejs.org/v2/guide/components-custom-events.html",
|
||||
"url": "https://vuejs.org/guide/essentials/forms.html#modifiers",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -575,9 +585,14 @@
|
||||
"title": "Inline / Method Handlers",
|
||||
"description": "In Vue.js, **inline handlers** are defined directly in the template using expressions, making them suitable for simple tasks. For example, you might use an inline handler to increment a counter. **Method handlers**, on the other hand, are defined in the `methods` option and are better for more complex logic or when reusing functionality across multiple components. They improve code readability and maintainability.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Inline Handlers",
|
||||
"url": "https://vuejs.org/guide/essentials/event-handling#inline-handlers",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Method Handlers",
|
||||
"url": "https://v1.vuejs.org/guide/events.html",
|
||||
"url": "https://vuejs.org/guide/essentials/event-handling#method-handlers",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -586,6 +601,11 @@
|
||||
"title": "Event Modifiers",
|
||||
"description": "In Vue.js, event modifiers are special postfixes that you can add to event handlers to control the behavior of events more easily. They help simplify common tasks such as stopping propagation, preventing default actions, and ensuring that the event is triggered only under certain conditions.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Event Modifiers",
|
||||
"url": "https://vuejs.org/guide/essentials/event-handling#event-modifiers",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Event Modifiers in Vue.js",
|
||||
"url": "https://www.freecodecamp.org/news/how-event-handling-works-in-vue-3-guide-for-devs/",
|
||||
@@ -598,8 +618,8 @@
|
||||
"description": "Input bindings are a way to bind user input to a component's data. This allows the component to react to user input and update its state accordingly. Input bindings are typically used with form elements such as text inputs, checkboxes, and select dropdowns.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Input Bindings",
|
||||
"url": "https://vuejs.org/guide/essentials/forms",
|
||||
"title": "Key Modifiers",
|
||||
"url": "https://vuejs.org/guide/essentials/event-handling#key-modifiers",
|
||||
"type": "article"
|
||||
}
|
||||
]
|
||||
@@ -608,6 +628,11 @@
|
||||
"title": "Mouse Button Modifiers",
|
||||
"description": "Mouse button modifiers are a type of modifier that can be used with event handlers to specify which mouse button or buttons should trigger the event. These modifiers allow you to customize the behavior of event handlers, such as v-on:click, to respond to specific mouse button clicks.\n\nVisit the following resources to learn more:",
|
||||
"links": [
|
||||
{
|
||||
"title": "Mouse Button Modifiers",
|
||||
"url": "https://vuejs.org/guide/essentials/event-handling#mouse-button-modifiers",
|
||||
"type": "article"
|
||||
},
|
||||
{
|
||||
"title": "Button Modifiers",
|
||||
"url": "https://medium.com/evolve-you/vue-3-keyboard-and-mouse-a4866d7d0e8",
|
||||
|
||||
BIN
public/roadmaps/php.png
Normal file
BIN
public/roadmaps/php.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 443 KiB |
BIN
public/roadmaps/postgresql-dba.png
Normal file
BIN
public/roadmaps/postgresql-dba.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 561 KiB |
@@ -1,5 +1,5 @@
|
||||
<p align="center">
|
||||
<img src="public/images/brand.png" height="128">
|
||||
<a href="https://roadmap.sh/"><img src="public/images/brand.png" height="128"></a>
|
||||
<h2 align="center"><a href="https://roadmap.sh">roadmap.sh</a></h2>
|
||||
<p align="center">Community driven roadmaps, articles and resources for developers<p>
|
||||
<p align="center">
|
||||
@@ -62,6 +62,7 @@ Here is the list of available roadmaps with more being actively worked upon.
|
||||
- [Vue Roadmap](https://roadmap.sh/vue)
|
||||
- [Angular Roadmap](https://roadmap.sh/angular)
|
||||
- [Node.js Roadmap](https://roadmap.sh/nodejs)
|
||||
- [PHP Roadmap](https://roadmap.sh/php)
|
||||
- [GraphQL Roadmap](https://roadmap.sh/graphql)
|
||||
- [Android Roadmap](https://roadmap.sh/android)
|
||||
- [iOS Roadmap](https://roadmap.sh/ios)
|
||||
|
||||
44
scripts/extract-guide-images.cjs
Normal file
44
scripts/extract-guide-images.cjs
Normal file
@@ -0,0 +1,44 @@
|
||||
// get all the base64 encoded images and save them to a file from the given markdown file
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const matter = require('gray-matter');
|
||||
|
||||
const guidePath = path.join(process.cwd(), 'src/data/guides');
|
||||
const tempDir = path.join(process.cwd(), '.temp');
|
||||
|
||||
const guideId = process.argv[2];
|
||||
if (!guideId) {
|
||||
console.error('Guide ID is required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const guideContent = fs.readFileSync(
|
||||
path.join(guidePath, `${guideId}.md`),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
// Create temp directory if it doesn't exist
|
||||
const guideTempDir = path.join(tempDir, guideId);
|
||||
if (!fs.existsSync(guideTempDir)) {
|
||||
fs.mkdirSync(guideTempDir, { recursive: true });
|
||||
}
|
||||
|
||||
const { data, content } = matter(guideContent);
|
||||
|
||||
// Find all base64 image references in the content
|
||||
const images = content.match(/\[(.+?)\]:\s+?<data:image\/([^;]+);base64,([^\s]+)/g);
|
||||
|
||||
if (images) {
|
||||
images.forEach((image) => {
|
||||
const imageName = image.match(/\[(.+?)\]/)[1];
|
||||
const imageExtension = image.match(/<data:image\/([^;]+);base64/)[1];
|
||||
const imageData = image.match(/base64,([^\s]+)/)[1];
|
||||
|
||||
// Write file using Buffer to properly decode base64
|
||||
fs.writeFileSync(
|
||||
path.join(guideTempDir, `${imageName}.${imageExtension}`),
|
||||
Buffer.from(imageData, 'base64')
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -13,562 +13,494 @@ const __dirname = dirname(__filename);
|
||||
* @property {string} text - The text content of the node
|
||||
*/
|
||||
|
||||
const roadmapId = 'engineering-manager';
|
||||
const roadmapId = 'php';
|
||||
|
||||
/** @type {Node[]} */
|
||||
const nodes = [
|
||||
{
|
||||
id: 'oKbeLp4YB8rI1Q3vi0EnG',
|
||||
text: 'Engineering Manager > What is Engineering Management? > EM vs Tech Lead vs IC',
|
||||
"id": "_hYN0gEi9BL24nptEtXWU",
|
||||
"text": "PHP > Introduction to PHP"
|
||||
},
|
||||
{
|
||||
id: 'aSZ2uVCmpAdEPjJt6VKG4',
|
||||
text: 'Engineering Manager > What is Engineering Management? > People',
|
||||
"id": "_LhLDVZjLt1DoAP1NuUES",
|
||||
"text": "PHP > Introduction to PHP > What is PHP?"
|
||||
},
|
||||
{
|
||||
id: 'p9ecMvHCqjmvxf67di7pY',
|
||||
text: 'Engineering Manager > What is Engineering Management? > Product',
|
||||
"id": "b2CuLrhsUNnb4OxI6RRAS",
|
||||
"text": "PHP > Introduction to PHP > Evolution and History"
|
||||
},
|
||||
{
|
||||
id: 'iZFn0FaRdrGv_-_8zii_-',
|
||||
text: 'Engineering Manager > What is Engineering Management? > Process',
|
||||
"id": "6sHRQTcoKL3TlgNJlwyx8",
|
||||
"text": "PHP > Introduction to PHP > PHP Versions and Features"
|
||||
},
|
||||
{
|
||||
id: 'fBENrXdMhoGYgL_d96tgo',
|
||||
text: 'Engineering Manager > Software Engineering Background',
|
||||
"id": "3_TuxOSzBuktBlBF05r_z",
|
||||
"text": "PHP > Installing PHP"
|
||||
},
|
||||
{
|
||||
id: 'iX4HPgoiEbc_gze1A01n4',
|
||||
text: 'Engineering Manager > > System Design and Architecture',
|
||||
"id": "36Y1HkHxhuxh2qVQB8NVE",
|
||||
"text": "PHP > WAMP"
|
||||
},
|
||||
{
|
||||
id: 'EY6Hk5wPd9Y_VA1UROk44',
|
||||
text: 'Engineering Manager > Technical Debt and Management',
|
||||
"id": "-wniKEBwbF0Fi1fHpF-Gc",
|
||||
"text": "PHP > XAMPP"
|
||||
},
|
||||
{
|
||||
id: '40yK6XzI8lSxdiAXxtF75',
|
||||
text: 'Engineering Manager > Code Review Best Practices',
|
||||
"id": "t7p7TU2khaxsZPYAdwFAA",
|
||||
"text": "PHP > MAMP"
|
||||
},
|
||||
{
|
||||
id: '_2xnTKt5yi__jj_WgcLa7',
|
||||
text: 'Engineering Manager > Technical Documentation',
|
||||
"id": "7LjxtrmgJtTJc0_kP83Tr",
|
||||
"text": "PHP > LAMP"
|
||||
},
|
||||
{
|
||||
id: 'ikCJ8Ybu2AD1w5VuPNVAO',
|
||||
text: 'Engineering Manager > Technical Strategy > Technical Roadmapping',
|
||||
"id": "hzBUHSuFwLYNooF_vEmrs",
|
||||
"text": "PHP > Basic PHP Syntax"
|
||||
},
|
||||
{
|
||||
id: 'FtWNnOE3zObmjS-Og26M3',
|
||||
text: 'Engineering Manager > Technical Strategy > Architectural Decision-Making',
|
||||
"id": "D0BtyxyjIBcpfn5wP23WC",
|
||||
"text": "PHP > Variables and Scope"
|
||||
},
|
||||
{
|
||||
id: 'H0aav5qKDNiNegJOGP2rx',
|
||||
text: 'Engineering Manager > Technical Strategy > Build vs Buy Evaluation',
|
||||
"id": "srIHPZabaCGdB5VvUXaMa",
|
||||
"text": "PHP > Data Types"
|
||||
},
|
||||
{
|
||||
id: 'd7zMBhMFgY9MwmKC9CVVh',
|
||||
text: 'Engineering Manager > Technical Strategy > Technical Risk Assessment',
|
||||
"id": "pzReF4C0mcCWAnpfIJbwl",
|
||||
"text": "PHP > Casting Data Types"
|
||||
},
|
||||
{
|
||||
id: 'EyoVFmqOJbH1sAPHLISFt',
|
||||
text: 'Engineering Manager > Technical Strategy > Scaling Infrastructure',
|
||||
"id": "2ykzBBdYhWuM-neGf0AWP",
|
||||
"text": "PHP > echo"
|
||||
},
|
||||
{
|
||||
id: 'QUxpEK8smXRBs2gMdDInB',
|
||||
text: 'Engineering Manager > Technical Strategy > Legacy System Retirement',
|
||||
"id": "NQUmO90sqe7fnzod3Ia8H",
|
||||
"text": "PHP > print"
|
||||
},
|
||||
{
|
||||
id: 'pduPcv2QPpVmVvDdK4CPi',
|
||||
text: 'Engineering Manager > Quality and Process > System Monitoring & Performance',
|
||||
"id": "wsC7OGXOyfCY4pLLNrR2v",
|
||||
"text": "PHP > print_r"
|
||||
},
|
||||
{
|
||||
id: 'gAEmpSMvNyjmTa5q9oZSg',
|
||||
text: 'Engineering Manager > Quality and Process > CI/CD Implementation',
|
||||
"id": "JCCeVC0hOrvIeyfg1ScKA",
|
||||
"text": "PHP > var_dump"
|
||||
},
|
||||
{
|
||||
id: 'bpJPDbifPwS4ScOoATlEI',
|
||||
text: 'Engineering Manager > Quality and Process > Development / Release Workflow',
|
||||
"id": "VLRLymQmLfscrBfzXKvHi",
|
||||
"text": "PHP > Constants"
|
||||
},
|
||||
{
|
||||
id: 'q5SJyM1d8cQzzAcR-kotB',
|
||||
text: 'Engineering Manager > Quality and Process > Testing Strategies',
|
||||
"id": "IhKjvT6CjRz4dsSU7SNQo",
|
||||
"text": "PHP > Arrays"
|
||||
},
|
||||
{
|
||||
id: 'C2YsaZ32An_UXV8lB7opm',
|
||||
text: 'Engineering Manager > Quality and Process > Technical Standards Setting',
|
||||
"id": "j2S8dP3HlAOOoZdpj-7Dx",
|
||||
"text": "PHP > Arrays > Indexed Arrays"
|
||||
},
|
||||
{
|
||||
id: 'sQCLhk__jvbityuuLlxiW',
|
||||
text: 'Engineering Manager > Quality and Process > Security Best Practices',
|
||||
"id": "i_NRsOJNNp7AOqMgu5Jg8",
|
||||
"text": "PHP > Arrays > Associative Arrays"
|
||||
},
|
||||
{
|
||||
id: 'o1xPrfg8iNWQpD12xsbQJ',
|
||||
text: 'Engineering Manager > Quality and Process > Incident Management',
|
||||
"id": "uARTOZ-ZwugSmbCJoRS5Y",
|
||||
"text": "PHP > Arrays > Multi-dimensional Arrays"
|
||||
},
|
||||
{
|
||||
id: '3na5mBIPl5f6mjEzkgD_C',
|
||||
text: 'Engineering Manager > People Management > Hiring and Recruitment',
|
||||
"id": "38YksjvhXCbgnHqkl57Cz",
|
||||
"text": "PHP > Conditionals"
|
||||
},
|
||||
{
|
||||
id: 'tPDmXXjvFI_8-MTo_dEUw',
|
||||
text: 'Engineering Manager > People Management > Team Structure and Design',
|
||||
"id": "-McOv-ZPTGayX7Mx2Thw1",
|
||||
"text": "PHP > Conditionals > if/else"
|
||||
},
|
||||
{
|
||||
id: 'eJzYnoB6sArLjXRm51cM4',
|
||||
text: 'Engineering Manager > People Management > Performance Evaluations',
|
||||
"id": "bgJ9-m6Fiu3VCc-NZlbpn",
|
||||
"text": "PHP > Conditionals > switch"
|
||||
},
|
||||
{
|
||||
id: 'fhFSR_N4ZDTHINEinubHG',
|
||||
text: 'Engineering Manager > People Management > Career Development Planning',
|
||||
"id": "3gNzX-bw2iqur7U7-_W38",
|
||||
"text": "PHP > Conditionals > match"
|
||||
},
|
||||
{
|
||||
id: '0ULnfq0ZFJXgoLbKM1gxC',
|
||||
text: 'Engineering Manager > People Management > Mentoring and Coaching',
|
||||
"id": "w0ntgFBhgGd5RUFd-qlPK",
|
||||
"text": "PHP > Conditionals > Null Coalescing Operator"
|
||||
},
|
||||
{
|
||||
id: 'bx2SMhR58ud45se5dK7qS',
|
||||
text: 'Engineering Manager > People Management > Delegation',
|
||||
"id": "1NXSk8VZDr89jQTTkOL7x",
|
||||
"text": "PHP > Conditionals > Null Safe Operator"
|
||||
},
|
||||
{
|
||||
id: 'QA5CR5f0geC_RQc_SOK-N',
|
||||
text: 'Engineering Manager > Leadership Skills > Conflict Resolution',
|
||||
"id": "qwt8xN4vuTrY-D0czYITI",
|
||||
"text": "PHP > Loops"
|
||||
},
|
||||
{
|
||||
id: 'Az9GgkLFoat2t_sYRUBv5',
|
||||
text: 'Engineering Manager > Leadership Skills > Feedback Delivery',
|
||||
"id": "WiGv7vi7Mtw-YqPMcnnyw",
|
||||
"text": "PHP > Functions"
|
||||
},
|
||||
{
|
||||
id: 'U_oOnDXkCE387r9olvMZB',
|
||||
text: 'Engineering Manager > Leadership Skills > Team Motivation',
|
||||
"id": "1nODJchgSuWbcvSlxnWeE",
|
||||
"text": "PHP > Functions > Function Declaration"
|
||||
},
|
||||
{
|
||||
id: '7PBmYoSmIgZT21a2Ip3_S',
|
||||
text: 'Engineering Manager > Leadership Skills > Trust / Influence Building',
|
||||
"id": "mpQKoBzsOa-5iWo08sOhQ",
|
||||
"text": "PHP > Functions > Parameters / Return Values"
|
||||
},
|
||||
{
|
||||
id: 'h7gEQNbGiabDA1q1Bk_IB',
|
||||
text: 'Engineering Manager > Leadership Skills > Emotional Intelligence',
|
||||
"id": "RgVP99rJJ8FVecIA45w20",
|
||||
"text": "PHP > Functions > Default / Optional Params"
|
||||
},
|
||||
{
|
||||
id: 'b3qoH_LuW-Gz4N8WdGnZs',
|
||||
text: 'Engineering Manager > Communication > One-on-One Meetings',
|
||||
"id": "RkNjYva8o_jXp9suz5YdG",
|
||||
"text": "PHP > Functions > Named Arguments"
|
||||
},
|
||||
{
|
||||
id: 'C2EQ8JMyK6b4PvgK5TpXb',
|
||||
text: 'Engineering Manager > Communication',
|
||||
"id": "Nr5m6wQLp7VyG3AucrSc8",
|
||||
"text": "PHP > Functions > Anonymous Functions"
|
||||
},
|
||||
{
|
||||
id: 'e0ZuiCoS8sJ0XB1lNiz7_',
|
||||
text: 'Engineering Manager > Team Meetings',
|
||||
"id": "x7hA2KAzJIjc-prgCEw6V",
|
||||
"text": "PHP > Functions > Callback Functions"
|
||||
},
|
||||
{
|
||||
id: 'gqKEgKjEu5sOf5Gl-HS-j',
|
||||
text: 'Engineering Manager > Communication > Status Reporting',
|
||||
"id": "mP1BIkqbWVVTU-zZv1ZL6",
|
||||
"text": "PHP > Functions > Arrow Functions"
|
||||
},
|
||||
{
|
||||
id: 'TVqVlJqegLZRSkwNoHbBf',
|
||||
text: 'Engineering Manager > Communication > Stakeholder Management',
|
||||
"id": "D9ybK5INH5zSOcYMb5ZPi",
|
||||
"text": "PHP > Functions > Recursion"
|
||||
},
|
||||
{
|
||||
id: 'ZuZuzwy-Frsn_PFJZVuAQ',
|
||||
text: 'Engineering Manager > Communication > Cross-functional Collaboration',
|
||||
"id": "rtmytETfyyLdcXUC0QyzL",
|
||||
"text": "PHP > Functions > Variadic Functions"
|
||||
},
|
||||
{
|
||||
id: 'jt-LF5QbGVs0cwTuHFQF6',
|
||||
text: 'Engineering Manager > Project Management',
|
||||
"id": "Kaaqu-mN7xvHN6CbIn616",
|
||||
"text": "PHP > File Handling > require"
|
||||
},
|
||||
{
|
||||
id: '4v5yLKYVcMh0s7SQuf__C',
|
||||
text: 'Engineering Manager > Project Management > Resource Allocation',
|
||||
"id": "-CyJbsg2ho3RvfzKnJj5C",
|
||||
"text": "PHP > File Handling > require_once"
|
||||
},
|
||||
{
|
||||
id: '7BcToTqL78QmG4qb43X5Q',
|
||||
text: 'Engineering Manager > Project Management > Sprint Planning',
|
||||
"id": "hKfv7V6bl2LXssq9Ffi7C",
|
||||
"text": "PHP > File Handling > include"
|
||||
},
|
||||
{
|
||||
id: '-Qc6E3gkUUonfzifYqeJJ',
|
||||
text: 'Engineering Manager > Project Management > Release Management',
|
||||
"id": "SwtLDgyPmDry20qS4FBfH",
|
||||
"text": "PHP > File Handling > include_once"
|
||||
},
|
||||
{
|
||||
id: 'mgw6M8I9qy1EoJpJV-gy1',
|
||||
text: 'Engineering Manager > Project Management > Risk Management',
|
||||
"id": "S9wTlkbv9-R6dohhZ47hs",
|
||||
"text": "PHP > File Operations > Reading Files"
|
||||
},
|
||||
{
|
||||
id: 'hH-UDVFlgKoMJcI1ssDFv',
|
||||
text: 'Engineering Manager > Project Management > Dependency management',
|
||||
"id": "two4UycJaCfSp6jQqtTAb",
|
||||
"text": "PHP > File Operations > Writing Files"
|
||||
},
|
||||
{
|
||||
id: 'n9gvPHn4c1U-l6v-W9v6r',
|
||||
text: 'Engineering Manager > Project Management > Agile methodologies',
|
||||
"id": "tgIyG6vHWpe9sz6lHmj5a",
|
||||
"text": "PHP > File Operations > File Permissions"
|
||||
},
|
||||
{
|
||||
id: 'SuT6q5lMMSyVkadlQp7iU',
|
||||
text: 'Engineering Manager > Project Management > Project Tracking',
|
||||
"id": "MRDjEjbkMpk7shcWAoPOF",
|
||||
"text": "PHP > File Operations > CSV Processing"
|
||||
},
|
||||
{
|
||||
id: 'PXobPGPgCX3_55w4UtxT9',
|
||||
text: 'Engineering Manager > Project Management > Milestone Management',
|
||||
"id": "DB2cxZE58WCCavW2PNwmf",
|
||||
"text": "PHP > File Operations > JSON Processing"
|
||||
},
|
||||
{
|
||||
id: 'C-lJJSjT8Cxw_UT3ocFsO',
|
||||
text: 'Engineering Manager > Project Management > Scope Management',
|
||||
"id": "ggkWo0DRSSDDkHpbiyUyf",
|
||||
"text": "PHP > File Operations > XML Processing"
|
||||
},
|
||||
{
|
||||
id: 'QWO5QFS7kXwfu3aa8IiRt',
|
||||
text: 'Engineering Manager > Project Management > Timeline Estimation',
|
||||
"id": "tn_iIfaJZVtPK6vFds7FH",
|
||||
"text": "PHP > HTTP / Request Handling > HTTP Methods"
|
||||
},
|
||||
{
|
||||
id: 'Wd8FCEaGZBTvsD-k4t0r4',
|
||||
text: 'Engineering Manager > Project Management > KPI Definition',
|
||||
"id": "GFYGFVfxkOoPI5mI4zSt1",
|
||||
"text": "PHP > HTTP / Request Handling > $_GET"
|
||||
},
|
||||
{
|
||||
id: 'idd92ZTBVUzptBl5jRdc3',
|
||||
text: 'Engineering Manager > Project Management > Measurement > Velocity Tracking',
|
||||
"id": "qNG-a4iIO-puZsMwAMzYC",
|
||||
"text": "PHP > HTTP / Request Handling > $_POST"
|
||||
},
|
||||
{
|
||||
id: 'ZWWsuFm_G4kvvl_cv8l_t',
|
||||
text: 'Engineering Manager > Project Management > Measurement > Quality Metrics',
|
||||
"id": "A6rfW4uJhyfAX2b18_EEC",
|
||||
"text": "PHP > HTTP / Request Handling > $_REQUEST"
|
||||
},
|
||||
{
|
||||
id: 'ZWWsuFm_G4kvvl_cv8l_t',
|
||||
text: 'Engineering Manager > Project Management > Measurement > Quality Metrics',
|
||||
"id": "7Ja2at_N9tRTlvSGahrqn",
|
||||
"text": "PHP > HTTP / Request Handling > $_SERVER"
|
||||
},
|
||||
{
|
||||
id: 'KPDHk7tl_BnIj_obnq3Kl',
|
||||
text: 'Engineering Manager > Project Management > Measurement > Team Health Metrics',
|
||||
"id": "sYI7f1PYP7G30_Uj2mZRv",
|
||||
"text": "PHP > Form Processing"
|
||||
},
|
||||
{
|
||||
id: 'g9WWa50V8ZbhIJgBRx0Nd',
|
||||
text: 'Engineering Manager > Project Management > Measurement > Project Postmortems',
|
||||
"id": "HNo8QO4aPbvgePiA4l6tq",
|
||||
"text": "PHP > File Uploads"
|
||||
},
|
||||
{
|
||||
id: 'nC5dfGlxbLoXUAp2u-6Gl',
|
||||
text: 'Engineering Manager > Strategic Thinking > Product strategy alignment',
|
||||
"id": "CGehmZjcgTWC7fQAvxmNW",
|
||||
"text": "PHP > State Management"
|
||||
},
|
||||
{
|
||||
id: 'vhOHvfF_lfQrrOK6sGLTY',
|
||||
text: 'Engineering Manager > Strategic Thinking > Business Case Development',
|
||||
"id": "so03-fK7E2WvTm6XsPq4i",
|
||||
"text": "PHP > State Management > Cookies"
|
||||
},
|
||||
{
|
||||
id: 'XinUWPahOdufmLYcEwMj_',
|
||||
text: 'Engineering Manager > Strategic Thinking > ROI analysis',
|
||||
"id": "qobzzgzArNHLLn9Oiqc6G",
|
||||
"text": "PHP > State Management > Sessions"
|
||||
},
|
||||
{
|
||||
id: 'P2gIOt-i0sQEOMBo-XjZO',
|
||||
text: 'Engineering Manager > > Market awareness',
|
||||
"id": "93oEIZttb85S23C1fLraP",
|
||||
"text": "PHP > Basics of Security > Input Validation"
|
||||
},
|
||||
{
|
||||
id: '76GjwwEYaEX_kh02OSpdr',
|
||||
text: 'Engineering Manager > Strategic Thinking > Competitive Analysis',
|
||||
"id": "801vB_JMas4ucriUmfrLg",
|
||||
"text": "PHP > Basics of Security > SQL Injection"
|
||||
},
|
||||
{
|
||||
id: 'TQY4hjo56rDdlbzjs_-nl',
|
||||
text: 'Engineering Manager > Strategic Thinking > Competitive Analysis',
|
||||
"id": "DxqQrToZSayWplKdCkTgT",
|
||||
"text": "PHP > Basics of Security > XSS Prevention"
|
||||
},
|
||||
{
|
||||
id: 'KA0y6KdVTjJFeX3frHUNo',
|
||||
text: 'Engineering Manager > Organizational Awareness > Company Culture',
|
||||
"id": "J9yIXZTtwbFzH2u4dI1ep",
|
||||
"text": "PHP > Basics of Security > CSRF Protection"
|
||||
},
|
||||
{
|
||||
id: 'tt02qGHSn4fPbpboZ1Ni_',
|
||||
text: 'Engineering Manager > Organizational Awareness > Change management',
|
||||
"id": "JbWFfJiCRrXDhnuIx_lqx",
|
||||
"text": "PHP > Basics of Security > Password Hashing"
|
||||
},
|
||||
{
|
||||
id: 'mjMRNhPkeb4lEZXBb8Iot',
|
||||
text: 'Engineering Manager > Organizational Awareness > Organization structure',
|
||||
"id": "HJJzKYXdK4BWITLP4APLZ",
|
||||
"text": "PHP > Basics of Security > Auth Mechanisms"
|
||||
},
|
||||
{
|
||||
id: 'Zoz01JcNU69gr95IcWhYM',
|
||||
text: 'Engineering Manager > Organizational Awareness > Politics navigation',
|
||||
"id": "tfC1tCrbvH5J43WUpG9Yb",
|
||||
"text": "PHP > Basics of Security > Sanitization Techniques"
|
||||
},
|
||||
{
|
||||
id: 'Hb_rZe4k37Rr0enSh7woV',
|
||||
text: 'Engineering Manager > Organizational Awareness > Cross-department collaboration',
|
||||
"id": "cJtPz1RMN1qDE4eRdv4N_",
|
||||
"text": "PHP > Database Connectivity > PDO"
|
||||
},
|
||||
{
|
||||
id: 'oqjr26B27SHSYVQ4IFnA1',
|
||||
text: 'Engineering Manager > Financial Management > Budget Planning',
|
||||
"id": "YLuo0oZJzTCoiZoOSG57z",
|
||||
"text": "PHP > Database Connectivity > MySQLi"
|
||||
},
|
||||
{
|
||||
id: 'iwwxnSVvCmZ57stXwzk8G',
|
||||
text: 'Engineering Manager > Financial Management > Resource forecasting',
|
||||
"id": "SeqGIfcLuveZ2z5ZSXcOd",
|
||||
"text": "PHP > Advanced Database Techniques > Object-Relational Mapping (ORM)"
|
||||
},
|
||||
{
|
||||
id: 'rbhZJZtRV1ZZ5QaYW77ry',
|
||||
text: 'Engineering Manager > Financial Management > Cost Optimization',
|
||||
"id": "FY-F6n9j29hQrnFry3VGb",
|
||||
"text": "PHP > Advanced Database Techniques > Database Transactions"
|
||||
},
|
||||
{
|
||||
id: 'Imgt669vbUT_Iec2o4Gvt',
|
||||
text: 'Engineering Manager > Financial Management > Vendor Management',
|
||||
"id": "txUyPR_tdC8iTJV3RtvBz",
|
||||
"text": "PHP > Advanced Database Techniques > Connection Pooling"
|
||||
},
|
||||
{
|
||||
id: 'ZuZuzwy-Frsn_PFJZVuAQ',
|
||||
text: 'Engineering Manager > Team Culture > Defining and Enforcing Values',
|
||||
"id": "M1nVsh_sCSFJRf6-7Ttsj",
|
||||
"text": "PHP > Advanced Database Techniques > Performance Optimization"
|
||||
},
|
||||
{
|
||||
id: '6iM0n4faMNhk4mezS9AcG',
|
||||
text: 'Engineering Manager > Team Culture > Inclusive environment creation',
|
||||
"id": "meplwvmHMtI3Sb_fyodzZ",
|
||||
"text": "PHP > Advanced Database Techniques > Database Migrations"
|
||||
},
|
||||
{
|
||||
id: '8Nro6PTkEkNugYBjQfJ6O',
|
||||
text: 'Engineering Manager > Team Culture > Team Traditions and Rituals',
|
||||
"id": "yTviiPFR5b_dr3WyxdxxQ",
|
||||
"text": "PHP > OOP Fundamentals"
|
||||
},
|
||||
{
|
||||
id: 'Vb3A4a-UpGTAEs-dVI66s',
|
||||
text: 'Engineering Manager > Team Culture > Recognition programs',
|
||||
"id": "PIuplWreo7PFG3Mdn2t6W",
|
||||
"text": "PHP > OOP Fundamentals > Classes and Objects"
|
||||
},
|
||||
{
|
||||
id: 'LE3ykySYFL23KvuwxeBaR',
|
||||
text: 'Engineering Manager > Team Culture > Social connections',
|
||||
"id": "oNUt1oT8pYBVvH0S2P6cb",
|
||||
"text": "PHP > OOP Fundamentals > Constructor / Destructor"
|
||||
},
|
||||
{
|
||||
id: 'g9FvFKC715tZL2ZGlPl3N',
|
||||
text: 'Engineering Manager > Team Culture > Bias Recognition / Mitigation',
|
||||
"id": "MRAPXshy9RoYdReY6grf_",
|
||||
"text": "PHP > OOP Fundamentals > Properties and Methods"
|
||||
},
|
||||
{
|
||||
id: 'njqjYPMQK3nGYtqHzUylo',
|
||||
text: 'Engineering Manager > Engineering Culture > Innovation fostering',
|
||||
"id": "RD2RaBmA2XWkEa13PTCTX",
|
||||
"text": "PHP > OOP Fundamentals > Access Specifiers"
|
||||
},
|
||||
{
|
||||
id: 'aeD-kBZEr1NHFtAD8yHI_',
|
||||
text: 'Engineering Manager > Engineering Culture > Learning culture development',
|
||||
"id": "qlkpwXfOc1p7j37hrzffI",
|
||||
"text": "PHP > OOP Fundamentals > Static Methods and Properties"
|
||||
},
|
||||
{
|
||||
id: '74-7hDXaBVXYo6LJdgac_',
|
||||
text: 'Engineering Manager > Engineering Culture > Knowledge sharing practices',
|
||||
"id": "c5q2e_jyMt8Pir5Od3lRi",
|
||||
"text": "PHP > OOP Fundamentals > Inheritance"
|
||||
},
|
||||
{
|
||||
id: 'Cq0OFaWqSRathZO-bxBrP',
|
||||
text: 'Engineering Manager > Engineering Culture > Technical excellence mindset',
|
||||
"id": "gtq5KrghF28f5G8nuDcYQ",
|
||||
"text": "PHP > Polymorphism"
|
||||
},
|
||||
{
|
||||
id: 'fYkKo8D35AHd8agr3YrIP',
|
||||
text: 'Engineering Manager > > Blameless Post-mortems',
|
||||
"id": "ub79EkMiOmPBwXLRuYFL8",
|
||||
"text": "PHP > Abstract classes"
|
||||
},
|
||||
{
|
||||
id: 'Xaeb67Nqdi0kwvehQUYeJ',
|
||||
text: 'Engineering Manager > Incident Response > Emergency protocols',
|
||||
"id": "vu0H-TsD7hkJgOQbSRj92",
|
||||
"text": "PHP > Interfaces"
|
||||
},
|
||||
{
|
||||
id: 'LQ3YfAgJ4UaDgtnN-cMht',
|
||||
text: 'Engineering Manager > Incident Response > War Room Management',
|
||||
"id": "GR09ns9B-0cONQaQ_uj-7",
|
||||
"text": "PHP > Traits"
|
||||
},
|
||||
{
|
||||
id: 'irEwTIubCjORnlH27QpEo',
|
||||
text: 'Engineering Manager > Incident Response > Stakeholder Communication',
|
||||
"id": "9raJ06lKRZITbjWeLil-F",
|
||||
"text": "PHP > Namespaces"
|
||||
},
|
||||
{
|
||||
id: '2fHcb1dAnf34APCAAlwnR',
|
||||
text: 'Engineering Manager > Incident Response > Service Recovery',
|
||||
"id": "rSXsPWto7Jeyw3Szl9pvf",
|
||||
"text": "PHP > Magic methods"
|
||||
},
|
||||
{
|
||||
id: '8zyK34SwHry2lrWchw0KZ',
|
||||
text: 'Engineering Manager > Incident Response > Post-incident analysis',
|
||||
"id": "sPW-Ti2VyNYzxq6EYkbn7",
|
||||
"text": "PHP > Type Declarations"
|
||||
},
|
||||
{
|
||||
id: '2RwpGPegD2GyiiV6SVbbM',
|
||||
text: 'Engineering Manager > Risk Mitigation > Contingency planning',
|
||||
"id": "KEE50C6lOS4eX8sAbfhYe",
|
||||
"text": "PHP > Dependency injection"
|
||||
},
|
||||
{
|
||||
id: 'KOTzJ8e7mc0wmF46vrj3I',
|
||||
text: 'Engineering Manager > Risk Mitigation > Disaster recovery',
|
||||
"id": "zsscRQZIq5o0JZir9hlz-",
|
||||
"text": "PHP > Laravel"
|
||||
},
|
||||
{
|
||||
id: 'v6N7BH0B55gX0oNXb55D7',
|
||||
text: 'Engineering Manager > Risk Mitigation > Business continuity',
|
||||
"id": "57VSMVePOr9qUD5x_LNdf",
|
||||
"text": "PHP > Symfony"
|
||||
},
|
||||
{
|
||||
id: 'FNp4-RgPvfC76pJKjX56a',
|
||||
text: 'Engineering Manager > Risk Mitigation > Security incident handling',
|
||||
"id": "yVFDu2aTiEZ4PWMdKdW2P",
|
||||
"text": "PHP > Composer"
|
||||
},
|
||||
{
|
||||
id: 'kQG_wk66-51dA4Ly9ivjM',
|
||||
text: 'Engineering Manager > Risk Mitigation > Production issues management',
|
||||
"id": "xZf2jjnCVHwYfDH2hs9kR",
|
||||
"text": "PHP > Packagist"
|
||||
},
|
||||
{
|
||||
id: 'mIUx8zAHWyPWPGvxuTK4y',
|
||||
text: 'Engineering Manager > Team Support > Contingency planning',
|
||||
"id": "qFiTsf6Es-gwqe6J6bdL1",
|
||||
"text": "PHP > Autoloading"
|
||||
},
|
||||
{
|
||||
id: 'nnoVA8W70hrNDxN3XQCVL',
|
||||
text: 'Engineering Manager > Team Support > Disaster recovery',
|
||||
"id": "NfBKKwG2GGBPppOjoLLBg",
|
||||
"text": "PHP > PHPUnit"
|
||||
},
|
||||
{
|
||||
id: 'FwK-B7jRbBXVnuY9JxI1w',
|
||||
text: 'Engineering Manager > Team Support > Business continuity',
|
||||
"id": "d6MydchA52HIxfAUjmZui",
|
||||
"text": "PHP > Pest"
|
||||
},
|
||||
{
|
||||
id: 'QFhhOgwz_bgZgOfKFg5XA',
|
||||
text: 'Engineering Manager > Team Support > Security incident handling',
|
||||
"id": "6eWgZVLV479oQzl0fu-Od",
|
||||
"text": "PHP > Style Tools"
|
||||
},
|
||||
{
|
||||
id: 'tmY4Ktu6luFg5wKylJW76',
|
||||
text: 'Engineering Manager > Team Support > Production issues management',
|
||||
"id": "fSpvZ_4kGFMbFVCWhA8vn",
|
||||
"text": "PHP > Style Tools > PHPCodeSniffer"
|
||||
},
|
||||
{
|
||||
id: 'WYoqfmk5ejB2UOiYXh4Zi',
|
||||
text: 'Engineering Manager > Partner Management > Vendor relationships',
|
||||
"id": "r07k_hT2z2EiIBH4q3F7-",
|
||||
"text": "PHP > Style Tools > PHP CS Fixer"
|
||||
},
|
||||
{
|
||||
id: 'xMN575nnnQJeHe2oJYw17',
|
||||
text: 'Engineering Manager > Partner Management > Technology partnerships',
|
||||
"id": "PrG_5dyBblXsWYYRcOJMa",
|
||||
"text": "PHP > Static Analysis"
|
||||
},
|
||||
{
|
||||
id: 'f3P0fF4UzgVQZuMVTVmP1',
|
||||
text: 'Engineering Manager > Partner Management > Integration management',
|
||||
"id": "12k71gNfwAcT9K5aLWgbZ",
|
||||
"text": "PHP > Static Analysis > PHPStan"
|
||||
},
|
||||
{
|
||||
id: 'ukmMMWacekcejEiEKCLzh',
|
||||
text: 'Engineering Manager > Partner Management > API strategy',
|
||||
"id": "T1XD93j6Lkpl88JSmys9b",
|
||||
"text": "PHP > Static Analysis > Psalm"
|
||||
},
|
||||
{
|
||||
id: 'Jctp5tPCK_vY35_bh7QFk',
|
||||
text: 'Engineering Manager > Partner Management > External collaboration',
|
||||
"id": "B45YVzov8X_iOtneiFEqa",
|
||||
"text": "PHP > Static Analysis > Phan"
|
||||
},
|
||||
{
|
||||
id: 'QEViLNgG4Uv9Q9PWig0u3',
|
||||
text: 'Engineering Manager > Customer Relations > Customer feedback integration',
|
||||
"id": "KC6D81-T-FwQc7Osw1rlY",
|
||||
"text": "PHP > External Integrations > cURL"
|
||||
},
|
||||
{
|
||||
id: 'V5s2i-L2tsZFNxMLN_e_U',
|
||||
text: 'Engineering Manager > Customer Relations > Technical customer support',
|
||||
"id": "_Al4NXKVQAnk8OikwvXCL",
|
||||
"text": "PHP > External Integrations > Guzzle"
|
||||
},
|
||||
{
|
||||
id: 'A-Aa7VdDAYfaMUZD_cWwP',
|
||||
text: 'Engineering Manager > Customer Relations > Customer success alignment',
|
||||
"id": "SD9k16UlVve9WtNMDA5Za",
|
||||
"text": "PHP > PHP-FIG"
|
||||
},
|
||||
{
|
||||
id: '2QwMcO27H3ygtLlWVplxr',
|
||||
text: 'Engineering Manager > Customer Relations > Feature prioritization',
|
||||
"id": "3tONibbRgK7HCwGTE2Gqw",
|
||||
"text": "PHP > PHP-FIG > PSR Standards"
|
||||
},
|
||||
{
|
||||
id: 'tCT2syTMyEHCspDLXxk6R',
|
||||
text: 'Engineering Manager > Customer Relations > Technical partnerships',
|
||||
"id": "_Dh78x_tPLqZweg--qZFQ",
|
||||
"text": "PHP > Performance Optimization > Profiling Techniques"
|
||||
},
|
||||
{
|
||||
id: '5MM1ccB1pmQcd3Uyjmbr7',
|
||||
text: 'Engineering Manager > Executive Communication > Board presentations',
|
||||
"id": "Av-BMa57RvrLlAXLffOH0",
|
||||
"text": "PHP > Performance Optimization > Caching Strategies"
|
||||
},
|
||||
{
|
||||
id: 'CHothgVl8ulFthwS7uKqK',
|
||||
text: 'Engineering Manager > Executive Communication > Executive summaries',
|
||||
"id": "bt7dK2PcOZ72B9HXPyMwL",
|
||||
"text": "PHP > Performance Optimization > Memory Management"
|
||||
},
|
||||
{
|
||||
id: 'uBrsV_EocAkRWEqJYjoZn',
|
||||
text: 'Engineering Manager > Executive Communication > Strategic proposals',
|
||||
"id": "VpwwF8j5ZtXVSbzNfE7Sx",
|
||||
"text": "PHP > Performance Optimization > Configuration Tuning"
|
||||
},
|
||||
{
|
||||
id: 'pLUOU2AmAJ9aJAmIlVD7D',
|
||||
text: 'Engineering Manager > Executive Communication > Budget requests',
|
||||
"id": "NieqZd1juaNYoZOrB7e31",
|
||||
"text": "PHP > Performance Optimization > Opcode Caching"
|
||||
},
|
||||
{
|
||||
id: 'QssXmeifoI3dtu-eXp8PK',
|
||||
text: 'Engineering Manager > Executive Communication > Vision alignment',
|
||||
"id": "AoGS-5MSkp8gtJFQVPSBE",
|
||||
"text": "PHP > Performance Optimization > PHP-FPM"
|
||||
},
|
||||
{
|
||||
id: 'gHhNi32MSBmqk-oKOy-uj',
|
||||
text: 'Engineering Manager > Knowledge Management > Documentation > Architecture documentation',
|
||||
"id": "qp5Xi12c0qcSzTanzJq0Z",
|
||||
"text": "PHP > System Interactions"
|
||||
},
|
||||
{
|
||||
id: 'Kwy9O1z2hpeE0Sb3qtxEg',
|
||||
text: 'Engineering Manager > Knowledge Management > Documentation > Process documentation',
|
||||
"id": "VhyYNGhOdKKrz_-uTkrjD",
|
||||
"text": "PHP > System Interactions > Executing System Commands"
|
||||
},
|
||||
{
|
||||
id: 'dTjp_rEl1ITZjvELqVtfv',
|
||||
text: 'Engineering Manager > Knowledge Management > Documentation > Decision records',
|
||||
"id": "NTKUMgsKGYISIyhgOJPQn",
|
||||
"text": "PHP > System Interactions > Process Control"
|
||||
},
|
||||
{
|
||||
id: '4-MCXFOkMGcN369OPG-vw',
|
||||
text: 'Engineering Manager > Knowledge Management > Documentation > Best Practices',
|
||||
"id": "fitjnLYKLHJ2P5G7JAvzm",
|
||||
"text": "PHP > System Interactions > Environment Variables"
|
||||
},
|
||||
{
|
||||
id: '4-MCXFOkMGcN369OPG-vw',
|
||||
text: 'Engineering Manager > Knowledge Management > Documentation > Best Practices',
|
||||
"id": "DTaAZaU1CwzW7esoDhj85",
|
||||
"text": "PHP > System Interactions > Configuration Files"
|
||||
},
|
||||
{
|
||||
id: 'HUQ_-vU2pdBPyF0mBocHz',
|
||||
text: 'Engineering Manager > Knowledge Management > Documentation > Lessons Learned',
|
||||
"id": "lFoHoMRywCWa056ii5cKQ",
|
||||
"text": "PHP > Debugging Tools > Xdebug"
|
||||
},
|
||||
{
|
||||
id: 'g6K9fxWdRQT5h_u4Y_bkq',
|
||||
text: 'Engineering Manager > Knowledge Management > Knowledge Transfer > Mentoring Programs',
|
||||
"id": "KpQb5Zh3GUcbYUyXHvyu2",
|
||||
"text": "PHP > Debugging Tools > Zend Debugger"
|
||||
},
|
||||
{
|
||||
id: '7t9jmv3_lRCEG5y5DA8bF',
|
||||
text: 'Engineering Manager > Knowledge Management > Knowledge Transfer > Knowledge bases',
|
||||
"id": "KMQqePqAjQ-ReDwHqeofx",
|
||||
"text": "PHP > Web Servers > Apache"
|
||||
},
|
||||
{
|
||||
id: '2LO0iWf-y3l4rA1n_oG1g',
|
||||
text: 'Engineering Manager > Knowledge Management > Knowledge Transfer > Tech Talks',
|
||||
},
|
||||
{
|
||||
id: 'S8-nwYKlG7YHL2dWwR303',
|
||||
text: 'Engineering Manager > Knowledge Management > Knowledge Transfer > Brown Bags',
|
||||
},
|
||||
{
|
||||
id: 'QMAIEkVFHrrP6lUWvd0S8',
|
||||
text: 'Engineering Manager > Change Management > Technical Change > Migration planning',
|
||||
},
|
||||
{
|
||||
id: '9mNLfntu1TPjcX3RoUeMq',
|
||||
text: 'Engineering Manager > Change Management > Technical Change > Legacy system retirement',
|
||||
},
|
||||
{
|
||||
id: 'jerPoyfCcwZbNuE_cl1hq',
|
||||
text: 'Engineering Manager > Change Management > Technical Change > Technology adoption',
|
||||
},
|
||||
{
|
||||
id: 'f-52wRfPRrA9iniOMYQB7',
|
||||
text: 'Engineering Manager > Change Management > Technical Change > Tool transitions',
|
||||
},
|
||||
{
|
||||
id: 'ev9ZKygqETctLMSt1GAFU',
|
||||
text: 'Engineering Manager > Change Management > Technical Change > Process changes',
|
||||
},
|
||||
{
|
||||
id: '1__zRE1iu1FDX9ynpWSBS',
|
||||
text: 'Engineering Manager > Change Management > Organizational Change > Change strategy',
|
||||
},
|
||||
{
|
||||
id: 'oGmtkOGVgA4huGJqkBEfj',
|
||||
text: 'Engineering Manager > Change Management > Organizational Change > Impact assessment',
|
||||
},
|
||||
{
|
||||
id: '34uOnta7dKOyZL0et_RC8',
|
||||
text: 'Engineering Manager > Change Management > Organizational Change > Stakeholder management',
|
||||
},
|
||||
{
|
||||
id: 'Mxi4g_PzT0oYc3NgR0UVg',
|
||||
text: 'Engineering Manager > Change Management > Organizational Change > Communication planning',
|
||||
},
|
||||
{
|
||||
id: 'Mxi4g_PzT0oYc3NgR0UVg',
|
||||
text: 'Engineering Manager > Change Management > Organizational Change > Communication planning',
|
||||
},
|
||||
{
|
||||
id: 'vfp6VmWnhpre_eDORg7ht',
|
||||
text: 'Engineering Manager > Change Management > Organizational Change > Resistance management',
|
||||
},
|
||||
{
|
||||
id: '5_CE3p5jMA1uEqFNfp7Kh',
|
||||
text: 'Engineering Manager > Change Management > > Reorganizations',
|
||||
},
|
||||
{
|
||||
id: 'ph0U4l2alVJ8lUJ96q7co',
|
||||
text: 'Engineering Manager > Change Management > Team Change > Team mergers',
|
||||
},
|
||||
{
|
||||
id: 'FayHWdUHHYFFBwnXx37Gk',
|
||||
text: 'Engineering Manager > Change Management > Team Change > Role transitions',
|
||||
},
|
||||
{
|
||||
id: 'eIlW4mZKNQfBsTDmZf7ex',
|
||||
text: 'Engineering Manager > Change Management > Team Change > Responsibility shifts',
|
||||
},
|
||||
{
|
||||
id: 'y7YHIz7OI4sNfC_nhfLcu',
|
||||
text: 'Engineering Manager > Change Management > Team Change > Culture evolution',
|
||||
},
|
||||
"id": "aspZpACHEKOsi_Er5FYPY",
|
||||
"text": "PHP > Web Servers > Nginx"
|
||||
}
|
||||
];
|
||||
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
|
||||
@@ -586,18 +518,17 @@ const prompt = `
|
||||
You are a helpful assistant that can help me generate content for a roadmap tree.
|
||||
User will give you roadmap topics in the form of "Parent > Child > Leaf". You need
|
||||
to generate content for the last node in the hierarchy in relation to the parents.
|
||||
Remember that you are describing how an Engineering Manager interacts with or handles
|
||||
the given topic, not just explaining the topic itself. You may explain why the given
|
||||
topic is important in an engineering team. Also, I hate it when you say "In the realm of..."
|
||||
Remember that you are explaining the topics for PHP showing what the given topic is
|
||||
with respect to PHP and giving a short code sample ONLY when required.
|
||||
Also, I hate it when you say "In the realm of..."
|
||||
or "In the context of..." or "..in the context of..." or "when we talk about..." or something
|
||||
similar.
|
||||
Content should be helpful and engaging for a technical audience.
|
||||
It can include things like (you can include more or less, depending on the topic):
|
||||
- How does an Engineering Manager work with or handle this area?
|
||||
- What are their key responsibilities related to this topic?
|
||||
- What challenges do they face and how do they address them?
|
||||
- What skills and approaches are needed to succeed in this aspect?
|
||||
The content should be a few short textual paragraphs (MAXIMUM 3) that is NO MORE THAN 130 words.
|
||||
- Briefly explain the given topic in relation to PHP.
|
||||
- Code sample if applicable.
|
||||
- Add a link to PHP documentation
|
||||
The content should be a a single textual paragraph.
|
||||
IMPORTANT: Use simple and clear English. Avoid complex words and jargon when possible.
|
||||
Write in a way that is easy to understand. Use short sentences and common words.
|
||||
`;
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useAuth } from '../../hooks/use-auth';
|
||||
import { useCopyText } from '../../hooks/use-copy-text';
|
||||
import { cn } from '../../lib/classname';
|
||||
import { CheckIcon } from '../ReactIcons/CheckIcon';
|
||||
import { TrophyEmoji } from '../ReactIcons/TrophyEmoji.tsx';
|
||||
|
||||
type InviteFriendsProps = {
|
||||
refByUserCount: number;
|
||||
|
||||
@@ -86,9 +86,6 @@ export function AdvertiseForm() {
|
||||
|
||||
pageProgressMessage.set('Please wait');
|
||||
|
||||
// Placeholder function to send data
|
||||
console.log('Form data:', formData);
|
||||
|
||||
const { response, error } = await httpPost(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-advertise`,
|
||||
formData,
|
||||
|
||||
@@ -6,6 +6,7 @@ declare global {
|
||||
category: string;
|
||||
label?: string;
|
||||
value?: string;
|
||||
callback?: () => void;
|
||||
}) => void;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +18,7 @@ declare global {
|
||||
* @returns void
|
||||
*/
|
||||
window.fireEvent = (props) => {
|
||||
const { action, category, label, value } = props;
|
||||
const { action, category, label, value, callback } = props;
|
||||
if (!window.gtag) {
|
||||
console.warn('Missing GTAG - Analytics disabled');
|
||||
return;
|
||||
@@ -25,11 +26,16 @@ window.fireEvent = (props) => {
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
console.log('Analytics event fired', props);
|
||||
callback?.();
|
||||
return;
|
||||
}
|
||||
|
||||
window.gtag('event', action, {
|
||||
event_category: category,
|
||||
event_label: label,
|
||||
value: value,
|
||||
...(callback ? { event_callback: callback } : {}),
|
||||
});
|
||||
};
|
||||
|
||||
export {};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
---
|
||||
import { parse } from 'node-html-parser';
|
||||
import type { Attributes } from 'node-html-parser/dist/nodes/html';
|
||||
|
||||
export interface Props {
|
||||
icon: string;
|
||||
@@ -15,7 +14,6 @@ async function getSVG(name: string) {
|
||||
eager: true,
|
||||
});
|
||||
|
||||
|
||||
if (!(filepath in files)) {
|
||||
throw new Error(`${filepath} not found`);
|
||||
}
|
||||
|
||||
143
src/components/AuthenticationFlow/CourseLoginPopup.tsx
Normal file
143
src/components/AuthenticationFlow/CourseLoginPopup.tsx
Normal file
@@ -0,0 +1,143 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Modal } from '../Modal';
|
||||
import { GitHubButton } from './GitHubButton';
|
||||
import { GoogleButton } from './GoogleButton';
|
||||
import { LinkedInButton } from './LinkedInButton';
|
||||
import { EmailLoginForm } from './EmailLoginForm';
|
||||
import { EmailSignupForm } from './EmailSignupForm';
|
||||
|
||||
type CourseLoginPopupProps = {
|
||||
onClose: () => void;
|
||||
checkoutAfterLogin?: boolean;
|
||||
};
|
||||
|
||||
export const CHECKOUT_AFTER_LOGIN_KEY = 'checkoutAfterLogin';
|
||||
|
||||
export function CourseLoginPopup(props: CourseLoginPopupProps) {
|
||||
const { onClose: parentOnClose, checkoutAfterLogin = true } = props;
|
||||
|
||||
const [isDisabled, setIsDisabled] = useState(false);
|
||||
const [isUsingEmail, setIsUsingEmail] = useState(false);
|
||||
|
||||
const [emailNature, setEmailNature] = useState<'login' | 'signup' | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
function onClose() {
|
||||
// if user didn't login and closed the popup, we remove the checkoutAfterLogin flag
|
||||
// so that login from other buttons on course page will trigger purchase
|
||||
localStorage.removeItem(CHECKOUT_AFTER_LOGIN_KEY);
|
||||
parentOnClose();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem(
|
||||
CHECKOUT_AFTER_LOGIN_KEY,
|
||||
checkoutAfterLogin ? '1' : '0',
|
||||
);
|
||||
}, [checkoutAfterLogin]);
|
||||
|
||||
if (emailNature) {
|
||||
const emailHeader = (
|
||||
<div className="mb-7 text-center">
|
||||
<p className="mb-3.5 pt-2 text-2xl font-semibold leading-5 text-slate-900">
|
||||
{emailNature === 'login'
|
||||
? 'Login to your account'
|
||||
: 'Create an account'}
|
||||
</p>
|
||||
<p className="mt-2 text-sm leading-4 text-slate-600">
|
||||
Fill in the details below to continue
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal onClose={onClose} bodyClassName="p-5 h-auto">
|
||||
{emailHeader}
|
||||
{emailNature === 'login' && (
|
||||
<EmailLoginForm
|
||||
isDisabled={isDisabled}
|
||||
setIsDisabled={setIsDisabled}
|
||||
/>
|
||||
)}
|
||||
{emailNature === 'signup' && (
|
||||
<EmailSignupForm
|
||||
isDisabled={isDisabled}
|
||||
setIsDisabled={setIsDisabled}
|
||||
/>
|
||||
)}
|
||||
|
||||
<button
|
||||
className="mt-2 w-full rounded-md border border-gray-400 py-2 text-center text-sm text-gray-600 hover:bg-gray-100"
|
||||
onClick={() => setEmailNature(null)}
|
||||
>
|
||||
Back to Options
|
||||
</button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal onClose={onClose} bodyClassName="p-5 h-auto">
|
||||
<div className="mb-7 text-center">
|
||||
<p className="mb-3.5 pt-2 text-2xl font-semibold leading-5 text-slate-900">
|
||||
Create or login to your account
|
||||
</p>
|
||||
<p className="mt-2 text-sm leading-4 text-slate-600">
|
||||
Login or sign up for an account to start learning
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<GitHubButton
|
||||
className="rounded-md border-gray-400 hover:bg-gray-100"
|
||||
isDisabled={isDisabled}
|
||||
setIsDisabled={setIsDisabled}
|
||||
/>
|
||||
<GoogleButton
|
||||
className="rounded-md border-gray-400 hover:bg-gray-100"
|
||||
isDisabled={isDisabled}
|
||||
setIsDisabled={setIsDisabled}
|
||||
/>
|
||||
<LinkedInButton
|
||||
className="rounded-md border-gray-400 hover:bg-gray-100"
|
||||
isDisabled={isDisabled}
|
||||
setIsDisabled={setIsDisabled}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full items-center gap-4 py-6 text-sm text-gray-600">
|
||||
<div className="h-px w-full bg-gray-200" />
|
||||
OR
|
||||
<div className="h-px w-full bg-gray-200" />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row gap-2">
|
||||
{!isUsingEmail && (
|
||||
<button
|
||||
className="flex-grow rounded-md border border-gray-400 px-4 py-2 text-sm text-gray-600 hover:bg-gray-100"
|
||||
onClick={() => setIsUsingEmail(true)}
|
||||
>
|
||||
Use your email address
|
||||
</button>
|
||||
)}
|
||||
{isUsingEmail && (
|
||||
<>
|
||||
<button
|
||||
className="flex-grow rounded-md border border-gray-400 px-4 py-2 text-sm text-gray-600 hover:bg-gray-100"
|
||||
onClick={() => setEmailNature('login')}
|
||||
>
|
||||
Already have an account
|
||||
</button>
|
||||
<button
|
||||
className="flex-grow rounded-md border border-gray-400 px-4 py-2 text-sm text-gray-600 hover:bg-gray-100"
|
||||
onClick={() => setEmailNature('signup')}
|
||||
>
|
||||
Create an account
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Cookies from 'js-cookie';
|
||||
import type { FormEvent } from 'react';
|
||||
import { useId, useState } from 'react';
|
||||
import { httpPost } from '../../lib/http';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
import { FIRST_LOGIN_PARAM, setAuthToken } from '../../lib/jwt';
|
||||
|
||||
type EmailLoginFormProps = {
|
||||
isDisabled?: boolean;
|
||||
@@ -24,19 +24,22 @@ export function EmailLoginForm(props: EmailLoginFormProps) {
|
||||
setIsDisabled?.(true);
|
||||
setError('');
|
||||
|
||||
const { response, error } = await httpPost<{ token: string }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-login`,
|
||||
{
|
||||
email,
|
||||
password,
|
||||
},
|
||||
);
|
||||
const { response, error } = await httpPost<{
|
||||
token: string;
|
||||
isNewUser: boolean;
|
||||
}>(`${import.meta.env.PUBLIC_API_URL}/v1-login`, {
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
// Log the user in and reload the page
|
||||
if (response?.token) {
|
||||
setAuthToken(response.token);
|
||||
window.location.reload();
|
||||
|
||||
const currentLocation = window.location.href;
|
||||
const url = new URL(currentLocation, window.location.origin);
|
||||
url.searchParams.set(FIRST_LOGIN_PARAM, response?.isNewUser ? '1' : '0');
|
||||
window.location.href = url.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx';
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
import {
|
||||
FIRST_LOGIN_PARAM,
|
||||
COURSE_PURCHASE_PARAM,
|
||||
setAuthToken,
|
||||
} from '../../lib/jwt';
|
||||
import { cn } from '../../../editor/utils/classname.ts';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { Spinner } from '../ReactIcons/Spinner.tsx';
|
||||
import { CHECKOUT_AFTER_LOGIN_KEY } from './CourseLoginPopup.tsx';
|
||||
import { triggerUtmRegistration } from '../../lib/browser.ts';
|
||||
|
||||
type GitHubButtonProps = {
|
||||
isDisabled?: boolean;
|
||||
setIsDisabled?: (isDisabled: boolean) => void;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const GITHUB_REDIRECT_AT = 'githubRedirectAt';
|
||||
const GITHUB_LAST_PAGE = 'githubLastPage';
|
||||
|
||||
export function GitHubButton(props: GitHubButtonProps) {
|
||||
const { isDisabled, setIsDisabled } = props;
|
||||
const { isDisabled, setIsDisabled, className } = props;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
@@ -32,7 +38,7 @@ export function GitHubButton(props: GitHubButtonProps) {
|
||||
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
httpGet<{ token: string }>(
|
||||
httpGet<{ token: string; isNewUser: boolean }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-github-callback${
|
||||
window.location.search
|
||||
}`,
|
||||
@@ -49,7 +55,7 @@ export function GitHubButton(props: GitHubButtonProps) {
|
||||
|
||||
triggerUtmRegistration();
|
||||
|
||||
let redirectUrl = '/';
|
||||
let redirectUrl = new URL('/', window.location.origin);
|
||||
const gitHubRedirectAt = localStorage.getItem(GITHUB_REDIRECT_AT);
|
||||
const lastPageBeforeGithub = localStorage.getItem(GITHUB_LAST_PAGE);
|
||||
|
||||
@@ -61,20 +67,37 @@ export function GitHubButton(props: GitHubButtonProps) {
|
||||
const timeSinceRedirect = now - socialRedirectAtTime;
|
||||
|
||||
if (timeSinceRedirect < 30 * 1000) {
|
||||
redirectUrl = lastPageBeforeGithub;
|
||||
redirectUrl = new URL(lastPageBeforeGithub, window.location.origin);
|
||||
}
|
||||
}
|
||||
|
||||
const authRedirectUrl = localStorage.getItem('authRedirect');
|
||||
if (authRedirectUrl) {
|
||||
localStorage.removeItem('authRedirect');
|
||||
redirectUrl = authRedirectUrl;
|
||||
redirectUrl = new URL(authRedirectUrl, window.location.origin);
|
||||
}
|
||||
|
||||
localStorage.removeItem(GITHUB_REDIRECT_AT);
|
||||
localStorage.removeItem(GITHUB_LAST_PAGE);
|
||||
setAuthToken(response.token);
|
||||
window.location.href = redirectUrl;
|
||||
|
||||
redirectUrl.searchParams.set(
|
||||
FIRST_LOGIN_PARAM,
|
||||
response?.isNewUser ? '1' : '0',
|
||||
);
|
||||
|
||||
const shouldTriggerPurchase =
|
||||
localStorage.getItem(CHECKOUT_AFTER_LOGIN_KEY) !== '0';
|
||||
|
||||
if (
|
||||
redirectUrl.pathname.includes('/courses/sql') &&
|
||||
shouldTriggerPurchase
|
||||
) {
|
||||
redirectUrl.searchParams.set(COURSE_PURCHASE_PARAM, '1');
|
||||
localStorage.removeItem(CHECKOUT_AFTER_LOGIN_KEY);
|
||||
}
|
||||
|
||||
window.location.href = redirectUrl.toString();
|
||||
})
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
@@ -120,7 +143,10 @@ export function GitHubButton(props: GitHubButtonProps) {
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
className={cn(
|
||||
'inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none hover:border-gray-400 hover:bg-gray-50 focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60',
|
||||
className,
|
||||
)}
|
||||
disabled={isLoading || isDisabled}
|
||||
onClick={handleClick}
|
||||
>
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
import {
|
||||
FIRST_LOGIN_PARAM,
|
||||
TOKEN_COOKIE_NAME,
|
||||
setAuthToken,
|
||||
} from '../../lib/jwt';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { Spinner } from '../ReactIcons/Spinner.tsx';
|
||||
import { COURSE_PURCHASE_PARAM } from '../../lib/jwt';
|
||||
import { GoogleIcon } from '../ReactIcons/GoogleIcon.tsx';
|
||||
import { Spinner } from '../ReactIcons/Spinner.tsx';
|
||||
import { CHECKOUT_AFTER_LOGIN_KEY } from './CourseLoginPopup.tsx';
|
||||
import {
|
||||
getStoredUtmParams,
|
||||
triggerUtmRegistration,
|
||||
} from '../../lib/browser.ts';
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
|
||||
type GoogleButtonProps = {
|
||||
isDisabled?: boolean;
|
||||
setIsDisabled?: (isDisabled: boolean) => void;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const GOOGLE_REDIRECT_AT = 'googleRedirectAt';
|
||||
const GOOGLE_LAST_PAGE = 'googleLastPage';
|
||||
|
||||
export function GoogleButton(props: GoogleButtonProps) {
|
||||
const { isDisabled, setIsDisabled } = props;
|
||||
const { isDisabled, setIsDisabled, className } = props;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
@@ -35,14 +43,12 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
httpGet<{ token: string }>(
|
||||
httpGet<{ token: string; isNewUser: boolean }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-google-callback${
|
||||
window.location.search
|
||||
}`,
|
||||
)
|
||||
.then(({ response, error }) => {
|
||||
const utmParams = getStoredUtmParams();
|
||||
|
||||
if (!response?.token) {
|
||||
setError(error?.message || 'Something went wrong.');
|
||||
setIsLoading(false);
|
||||
@@ -53,7 +59,7 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
|
||||
triggerUtmRegistration();
|
||||
|
||||
let redirectUrl = '/';
|
||||
let redirectUrl = new URL('/', window.location.origin);
|
||||
const googleRedirectAt = localStorage.getItem(GOOGLE_REDIRECT_AT);
|
||||
const lastPageBeforeGoogle = localStorage.getItem(GOOGLE_LAST_PAGE);
|
||||
|
||||
@@ -65,20 +71,37 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
const timeSinceRedirect = now - socialRedirectAtTime;
|
||||
|
||||
if (timeSinceRedirect < 30 * 1000) {
|
||||
redirectUrl = lastPageBeforeGoogle;
|
||||
redirectUrl = new URL(lastPageBeforeGoogle, window.location.origin);
|
||||
}
|
||||
}
|
||||
|
||||
const authRedirectUrl = localStorage.getItem('authRedirect');
|
||||
if (authRedirectUrl) {
|
||||
localStorage.removeItem('authRedirect');
|
||||
redirectUrl = authRedirectUrl;
|
||||
redirectUrl = new URL(authRedirectUrl, window.location.origin);
|
||||
}
|
||||
|
||||
redirectUrl.searchParams.set(
|
||||
FIRST_LOGIN_PARAM,
|
||||
response?.isNewUser ? '1' : '0',
|
||||
);
|
||||
|
||||
const shouldTriggerPurchase =
|
||||
localStorage.getItem(CHECKOUT_AFTER_LOGIN_KEY) !== '0';
|
||||
if (
|
||||
redirectUrl.pathname.includes('/courses/sql') &&
|
||||
shouldTriggerPurchase
|
||||
) {
|
||||
redirectUrl.searchParams.set(COURSE_PURCHASE_PARAM, '1');
|
||||
|
||||
localStorage.removeItem(CHECKOUT_AFTER_LOGIN_KEY);
|
||||
}
|
||||
|
||||
localStorage.removeItem(GOOGLE_REDIRECT_AT);
|
||||
localStorage.removeItem(GOOGLE_LAST_PAGE);
|
||||
setAuthToken(response.token);
|
||||
window.location.href = redirectUrl;
|
||||
|
||||
window.location.href = redirectUrl.toString();
|
||||
})
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
@@ -130,7 +153,10 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
className={cn(
|
||||
'inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none hover:border-gray-400 hover:bg-gray-50 focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60',
|
||||
className,
|
||||
)}
|
||||
disabled={isLoading || isDisabled}
|
||||
onClick={handleClick}
|
||||
>
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
import {
|
||||
FIRST_LOGIN_PARAM,
|
||||
COURSE_PURCHASE_PARAM,
|
||||
TOKEN_COOKIE_NAME,
|
||||
setAuthToken,
|
||||
} from '../../lib/jwt';
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { Spinner } from '../ReactIcons/Spinner.tsx';
|
||||
import { LinkedInIcon } from '../ReactIcons/LinkedInIcon.tsx';
|
||||
import { Spinner } from '../ReactIcons/Spinner.tsx';
|
||||
import { CHECKOUT_AFTER_LOGIN_KEY } from './CourseLoginPopup.tsx';
|
||||
import { triggerUtmRegistration } from '../../lib/browser.ts';
|
||||
|
||||
type LinkedInButtonProps = {
|
||||
isDisabled?: boolean;
|
||||
setIsDisabled?: (isDisabled: boolean) => void;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const LINKEDIN_REDIRECT_AT = 'linkedInRedirectAt';
|
||||
const LINKEDIN_LAST_PAGE = 'linkedInLastPage';
|
||||
|
||||
export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
const { isDisabled, setIsDisabled } = props;
|
||||
const { isDisabled, setIsDisabled, className } = props;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
@@ -32,7 +40,7 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
httpGet<{ token: string }>(
|
||||
httpGet<{ token: string; isNewUser: boolean }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-linkedin-callback${
|
||||
window.location.search
|
||||
}`,
|
||||
@@ -48,7 +56,7 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
|
||||
triggerUtmRegistration();
|
||||
|
||||
let redirectUrl = '/';
|
||||
let redirectUrl = new URL('/', window.location.origin);
|
||||
const linkedInRedirectAt = localStorage.getItem(LINKEDIN_REDIRECT_AT);
|
||||
const lastPageBeforeLinkedIn = localStorage.getItem(LINKEDIN_LAST_PAGE);
|
||||
|
||||
@@ -60,20 +68,39 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
const timeSinceRedirect = now - socialRedirectAtTime;
|
||||
|
||||
if (timeSinceRedirect < 30 * 1000) {
|
||||
redirectUrl = lastPageBeforeLinkedIn;
|
||||
redirectUrl = new URL(
|
||||
lastPageBeforeLinkedIn,
|
||||
window.location.origin,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const authRedirectUrl = localStorage.getItem('authRedirect');
|
||||
if (authRedirectUrl) {
|
||||
localStorage.removeItem('authRedirect');
|
||||
redirectUrl = authRedirectUrl;
|
||||
redirectUrl = new URL(authRedirectUrl, window.location.origin);
|
||||
}
|
||||
|
||||
redirectUrl.searchParams.set(
|
||||
FIRST_LOGIN_PARAM,
|
||||
response?.isNewUser ? '1' : '0',
|
||||
);
|
||||
|
||||
const shouldTriggerPurchase =
|
||||
localStorage.getItem(CHECKOUT_AFTER_LOGIN_KEY) !== '0';
|
||||
if (
|
||||
redirectUrl.pathname.includes('/courses/sql') &&
|
||||
shouldTriggerPurchase
|
||||
) {
|
||||
redirectUrl.searchParams.set(COURSE_PURCHASE_PARAM, '1');
|
||||
localStorage.removeItem(CHECKOUT_AFTER_LOGIN_KEY);
|
||||
}
|
||||
|
||||
localStorage.removeItem(LINKEDIN_REDIRECT_AT);
|
||||
localStorage.removeItem(LINKEDIN_LAST_PAGE);
|
||||
setAuthToken(response.token);
|
||||
window.location.href = redirectUrl;
|
||||
|
||||
window.location.href = redirectUrl.toString();
|
||||
})
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
@@ -125,14 +152,17 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
className={cn(
|
||||
'inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none hover:border-gray-400 focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60',
|
||||
className,
|
||||
)}
|
||||
disabled={isLoading || isDisabled}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{isLoading ? (
|
||||
<Spinner className={'h-[18px] w-[18px]'} isDualRing={false} />
|
||||
) : (
|
||||
<LinkedInIcon className={'h-[18px] w-[18px]'} />
|
||||
<LinkedInIcon className={'h-[18px] w-[18px] text-blue-700'} />
|
||||
)}
|
||||
Continue with LinkedIn
|
||||
</button>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Cookies from 'js-cookie';
|
||||
import { httpPost } from '../../lib/http';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
import {
|
||||
FIRST_LOGIN_PARAM,
|
||||
TOKEN_COOKIE_NAME,
|
||||
setAuthToken,
|
||||
} from '../../lib/jwt';
|
||||
import { Spinner } from '../ReactIcons/Spinner';
|
||||
import { ErrorIcon2 } from '../ReactIcons/ErrorIcon2';
|
||||
import { triggerUtmRegistration } from '../../lib/browser.ts';
|
||||
@@ -13,7 +17,7 @@ export function TriggerVerifyAccount() {
|
||||
const triggerVerify = (code: string) => {
|
||||
setIsLoading(true);
|
||||
|
||||
httpPost<{ token: string }>(
|
||||
httpPost<{ token: string; isNewUser: boolean }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-verify-account`,
|
||||
{
|
||||
code,
|
||||
@@ -30,7 +34,13 @@ export function TriggerVerifyAccount() {
|
||||
triggerUtmRegistration();
|
||||
|
||||
setAuthToken(response.token);
|
||||
window.location.href = '/';
|
||||
|
||||
const url = new URL('/', window.location.origin);
|
||||
url.searchParams.set(
|
||||
FIRST_LOGIN_PARAM,
|
||||
response?.isNewUser ? '1' : '0',
|
||||
);
|
||||
window.location.href = url.toString();
|
||||
})
|
||||
.catch((err) => {
|
||||
setIsLoading(false);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
|
||||
|
||||
export const REDIRECT_PAGE_AFTER_AUTH = 'redirect_page_after_auth';
|
||||
|
||||
function easeInElement(el: Element) {
|
||||
el.classList.add('opacity-0', 'transition-opacity', 'duration-300');
|
||||
el.classList.remove('hidden');
|
||||
@@ -56,7 +58,8 @@ function handleGuest() {
|
||||
|
||||
// If the user is on an authenticated route, redirect them to the home page
|
||||
if (authenticatedRoutes.includes(window.location.pathname)) {
|
||||
window.location.href = '/';
|
||||
localStorage.setItem(REDIRECT_PAGE_AFTER_AUTH, window.location.pathname);
|
||||
window.location.href = '/login';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +89,14 @@ function handleAuthenticated() {
|
||||
export function handleAuthRequired() {
|
||||
const token = Cookies.get(TOKEN_COOKIE_NAME);
|
||||
if (token) {
|
||||
const pageAfterAuth = localStorage.getItem(REDIRECT_PAGE_AFTER_AUTH);
|
||||
if (pageAfterAuth) {
|
||||
localStorage.removeItem(REDIRECT_PAGE_AFTER_AUTH);
|
||||
window.location.href = pageAfterAuth;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
handleAuthenticated();
|
||||
} else {
|
||||
handleGuest();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
import { getAllChangelogs } from '../lib/changelog';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import AstroIcon from './AstroIcon.astro';
|
||||
const allChangelogs = await getAllChangelogs();
|
||||
const top10Changelogs = allChangelogs.slice(0, 10);
|
||||
---
|
||||
@@ -12,16 +12,18 @@ const top10Changelogs = allChangelogs.slice(0, 10);
|
||||
<img
|
||||
src='/images/gifs/rocket.gif'
|
||||
alt='Rocket'
|
||||
class='mr-2 hidden sm:inline h-12 w-12'
|
||||
class='mr-2 hidden h-12 w-12 sm:inline'
|
||||
/>
|
||||
Actively Maintained
|
||||
</p>
|
||||
<p class='mt-1 mb-2 sm:my-2 text-sm leading-relaxed text-gray-600 sm:my-5 sm:text-lg'>
|
||||
<p
|
||||
class='mb-2 mt-1 text-sm leading-relaxed text-gray-600 sm:my-2 sm:my-5 sm:text-lg'
|
||||
>
|
||||
We are always improving our content, adding new resources and adding
|
||||
features to enhance your learning experience.
|
||||
</p>
|
||||
|
||||
<div class='relative mt-2 sm:mt-8 text-left'>
|
||||
<div class='relative mt-2 text-left sm:mt-8'>
|
||||
<div
|
||||
class='absolute inset-y-0 left-[120px] hidden w-px -translate-x-[0.5px] translate-x-[5.75px] bg-gray-300 sm:block'
|
||||
>
|
||||
@@ -36,13 +38,13 @@ const top10Changelogs = allChangelogs.slice(0, 10);
|
||||
<li class='relative'>
|
||||
<a
|
||||
href={`/changelog#${changelog.id}`}
|
||||
class='flex flex-col sm:flex-row items-start sm:items-center'
|
||||
class='flex flex-col items-start sm:flex-row sm:items-center'
|
||||
>
|
||||
<span class='sm:w-[120px] flex-shrink-0 pr-0 sm:pr-4 text-right text-sm tracking-wide text-gray-400'>
|
||||
<span class='flex-shrink-0 pr-0 text-right text-sm tracking-wide text-gray-400 sm:w-[120px] sm:pr-4'>
|
||||
{formattedDate}
|
||||
</span>
|
||||
<span class='h-3 w-3 flex-shrink-0 rounded-full bg-gray-300 hidden sm:block' />
|
||||
<span class='text-balance sm:pl-8 text-base font-medium text-gray-900'>
|
||||
<span class='hidden h-3 w-3 flex-shrink-0 rounded-full bg-gray-300 sm:block' />
|
||||
<span class='text-balance text-base font-medium text-gray-900 sm:pl-8'>
|
||||
{changelog.frontmatter.title}
|
||||
</span>
|
||||
</a>
|
||||
@@ -52,13 +54,23 @@ const top10Changelogs = allChangelogs.slice(0, 10);
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
<div class='mt-2 sm:mt-8 text-left sm:text-center'>
|
||||
<div
|
||||
class='mt-2 flex flex-col gap-2 sm:flex-row sm:mt-8 sm:items-center sm:justify-center'
|
||||
>
|
||||
<a
|
||||
href='/changelog'
|
||||
class='inline-block text-sm sm:text-base rounded-lg sm:rounded-full bg-gray-800 px-4 sm:px-6 py-2 text-white transition-colors hover:bg-gray-700'
|
||||
class='inline-block rounded-lg border border-black bg-black px-4 py-2 text-sm text-white transition-colors hover:bg-gray-700 sm:rounded-full sm:px-6 sm:text-base'
|
||||
>
|
||||
View Full Changelog
|
||||
</a>
|
||||
<button
|
||||
data-guest-required
|
||||
data-popup='login-popup'
|
||||
class='flex flex-row items-center gap-2 rounded-lg border border-black bg-white px-4 py-2 text-sm text-black transition-all hover:bg-black hover:text-white sm:rounded-full sm:pl-4 sm:pr-5 sm:text-base'
|
||||
>
|
||||
<AstroIcon icon='bell' class='h-5 w-5' />
|
||||
Subscribe for Notifications
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
} from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
|
||||
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import { ContentConfirmationModal } from './ContentConfirmationModal';
|
||||
|
||||
export type TeamResourceConfig = {
|
||||
isCustomResource: boolean;
|
||||
@@ -44,6 +45,7 @@ export function RoadmapSelector(props: RoadmapSelectorProps) {
|
||||
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState<boolean>(false);
|
||||
|
||||
const [error, setError] = useState<string>('');
|
||||
const [confirmationContentId, setConfirmationContentId] = useState<string>();
|
||||
|
||||
async function loadAllRoadmaps() {
|
||||
const { error, response } = await httpGet<PageType[]>(`/pages.json`);
|
||||
@@ -101,7 +103,7 @@ export function RoadmapSelector(props: RoadmapSelectorProps) {
|
||||
});
|
||||
}
|
||||
|
||||
async function addTeamResource(roadmapId: string) {
|
||||
async function addTeamResource(roadmapId: string, shouldCopyContent = false) {
|
||||
if (!teamId) {
|
||||
return;
|
||||
}
|
||||
@@ -118,6 +120,7 @@ export function RoadmapSelector(props: RoadmapSelectorProps) {
|
||||
resourceType: 'roadmap',
|
||||
removed: [],
|
||||
renderer: renderer || 'balsamiq',
|
||||
shouldCopyContent,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -148,8 +151,24 @@ export function RoadmapSelector(props: RoadmapSelectorProps) {
|
||||
});
|
||||
}
|
||||
|
||||
const confirmationContentIdModal = confirmationContentId && (
|
||||
<ContentConfirmationModal
|
||||
onClose={() => {
|
||||
setConfirmationContentId('');
|
||||
}}
|
||||
onClick={(shouldCopy) => {
|
||||
addTeamResource(confirmationContentId, shouldCopy).finally(() => {
|
||||
pageProgressMessage.set('');
|
||||
setConfirmationContentId('');
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{confirmationContentIdModal}
|
||||
|
||||
{changingRoadmapId && (
|
||||
<UpdateTeamResourceModal
|
||||
onClose={() => setChangingRoadmapId('')}
|
||||
@@ -170,9 +189,20 @@ export function RoadmapSelector(props: RoadmapSelectorProps) {
|
||||
allRoadmaps={allRoadmaps.filter((r) => r.renderer === 'editor')}
|
||||
teamId={teamId}
|
||||
onRoadmapAdd={(roadmapId) => {
|
||||
addTeamResource(roadmapId).finally(() => {
|
||||
pageProgressMessage.set('');
|
||||
});
|
||||
const isEditorRoadmap = allRoadmaps.find(
|
||||
(r) => r.id === roadmapId && r.renderer === 'editor',
|
||||
);
|
||||
|
||||
if (!isEditorRoadmap) {
|
||||
addTeamResource(roadmapId).finally(() => {
|
||||
pageProgressMessage.set('');
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setShowSelectRoadmapModal(false);
|
||||
setConfirmationContentId(roadmapId);
|
||||
}}
|
||||
onRoadmapRemove={(roadmapId) => {
|
||||
onRemove(roadmapId).finally(() => {});
|
||||
|
||||
@@ -17,7 +17,9 @@ import { totalRoadmapNodes } from '../../stores/roadmap.ts';
|
||||
|
||||
type FlowRoadmapRendererProps = {
|
||||
isEmbed?: boolean;
|
||||
roadmap: RoadmapDocument;
|
||||
roadmap: RoadmapDocument & {
|
||||
canManage?: boolean
|
||||
};
|
||||
};
|
||||
|
||||
export function FlowRoadmapRenderer(props: FlowRoadmapRendererProps) {
|
||||
@@ -159,7 +161,7 @@ export function FlowRoadmapRenderer(props: FlowRoadmapRendererProps) {
|
||||
{hideRenderer && (
|
||||
<EmptyRoadmap
|
||||
roadmapId={roadmapId}
|
||||
canManage={roadmap.canManage}
|
||||
canManage={roadmap.canManage || false}
|
||||
className="grow"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -13,7 +13,7 @@ export function ShowcaseStatus(props: ShowcaseStatusProps) {
|
||||
const { showcaseStatus } = currentRoadmap;
|
||||
const [showSubmitWarning, setShowSubmitWarning] = useState(false);
|
||||
|
||||
if (!currentRoadmap || showcaseStatus) {
|
||||
if (!currentRoadmap || showcaseStatus || currentRoadmap.aiRoadmapId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { cn } from '../../../editor/utils/classname';
|
||||
import { useParams } from '../../hooks/use-params';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { getUser } from '../../lib/jwt';
|
||||
import { $teamList } from '../../stores/team';
|
||||
import type { TeamListResponse } from '../TeamDropdown/TeamDropdown';
|
||||
import { DashboardTab } from './DashboardTab';
|
||||
import { DashboardTabButton } from './DashboardTabButton';
|
||||
import { PersonalDashboard, type BuiltInRoadmap } from './PersonalDashboard';
|
||||
import { TeamDashboard } from './TeamDashboard';
|
||||
import { getUser } from '../../lib/jwt';
|
||||
import { useParams } from '../../hooks/use-params';
|
||||
import type { QuestionGroupType } from '../../lib/question-group';
|
||||
import type { GuideFileType } from '../../lib/guide';
|
||||
import type { VideoFileType } from '../../lib/video';
|
||||
|
||||
type DashboardPageProps = {
|
||||
builtInRoleRoadmaps?: BuiltInRoadmap[];
|
||||
builtInSkillRoadmaps?: BuiltInRoadmap[];
|
||||
builtInBestPractices?: BuiltInRoadmap[];
|
||||
isTeamPage?: boolean;
|
||||
questionGroups?: QuestionGroupType[];
|
||||
guides?: GuideFileType[];
|
||||
videos?: VideoFileType[];
|
||||
};
|
||||
|
||||
export function DashboardPage(props: DashboardPageProps) {
|
||||
@@ -23,6 +30,9 @@ export function DashboardPage(props: DashboardPageProps) {
|
||||
builtInBestPractices,
|
||||
builtInSkillRoadmaps,
|
||||
isTeamPage = false,
|
||||
questionGroups,
|
||||
guides,
|
||||
videos,
|
||||
} = props;
|
||||
|
||||
const currentUser = getUser();
|
||||
@@ -66,78 +76,80 @@ export function DashboardPage(props: DashboardPageProps) {
|
||||
: '/images/default-avatar.png';
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 pb-20 pt-8">
|
||||
<div className="container">
|
||||
<div className="mb-6 flex flex-wrap items-center gap-1.5 sm:mb-8">
|
||||
<DashboardTab
|
||||
label="Personal"
|
||||
isActive={!selectedTeamId && !isTeamPage}
|
||||
href="/dashboard"
|
||||
avatar={userAvatar}
|
||||
/>
|
||||
<>
|
||||
<div
|
||||
className={cn('bg-slate-900', {
|
||||
'striped-loader-slate': isLoading,
|
||||
})}
|
||||
>
|
||||
<div className="bg-slate-800/30 py-5">
|
||||
<div className="container flex flex-wrap items-center gap-1.5">
|
||||
<DashboardTabButton
|
||||
label="Personal"
|
||||
isActive={!selectedTeamId && !isTeamPage}
|
||||
href="/dashboard"
|
||||
avatar={userAvatar}
|
||||
/>
|
||||
|
||||
{isLoading && (
|
||||
<>
|
||||
<DashboardTabSkeleton />
|
||||
<DashboardTabSkeleton />
|
||||
</>
|
||||
)}
|
||||
|
||||
{!isLoading && (
|
||||
<>
|
||||
{teamList.map((team) => {
|
||||
const { avatar } = team;
|
||||
const avatarUrl = avatar
|
||||
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
|
||||
: '/images/default-avatar.png';
|
||||
return (
|
||||
<DashboardTab
|
||||
key={team._id}
|
||||
label={team.name}
|
||||
isActive={team._id === selectedTeamId}
|
||||
{...(team.status === 'invited'
|
||||
? {
|
||||
href: `/respond-invite?i=${team.memberId}`,
|
||||
}
|
||||
: {
|
||||
href: `/team?t=${team._id}`,
|
||||
})}
|
||||
avatar={avatarUrl}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<DashboardTab
|
||||
label="+ Create Team"
|
||||
isActive={false}
|
||||
href="/team/new"
|
||||
className="border border-dashed border-gray-300 bg-transparent px-3 text-[13px] text-sm text-gray-500 hover:border-gray-600 hover:text-black"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!isLoading && (
|
||||
<>
|
||||
{teamList.map((team) => {
|
||||
const { avatar } = team;
|
||||
const avatarUrl = avatar
|
||||
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
|
||||
: '/images/default-avatar.png';
|
||||
return (
|
||||
<DashboardTabButton
|
||||
key={team._id}
|
||||
label={team.name}
|
||||
isActive={team._id === selectedTeamId}
|
||||
{...(team.status === 'invited'
|
||||
? {
|
||||
href: `/respond-invite?i=${team.memberId}`,
|
||||
}
|
||||
: {
|
||||
href: `/team?t=${team._id}`,
|
||||
})}
|
||||
avatar={avatarUrl}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<DashboardTabButton
|
||||
label="+ Create Team"
|
||||
isActive={false}
|
||||
href="/team/new"
|
||||
className="border border-dashed border-slate-700 bg-transparent px-3 text-[13px] text-sm text-gray-500 hover:border-solid hover:border-slate-700 hover:text-gray-400"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="">
|
||||
{!selectedTeamId && !isTeamPage && (
|
||||
<PersonalDashboard
|
||||
builtInRoleRoadmaps={builtInRoleRoadmaps}
|
||||
builtInSkillRoadmaps={builtInSkillRoadmaps}
|
||||
builtInBestPractices={builtInBestPractices}
|
||||
/>
|
||||
<div className="bg-slate-900">
|
||||
<PersonalDashboard
|
||||
builtInRoleRoadmaps={builtInRoleRoadmaps}
|
||||
builtInSkillRoadmaps={builtInSkillRoadmaps}
|
||||
builtInBestPractices={builtInBestPractices}
|
||||
questionGroups={questionGroups}
|
||||
guides={guides}
|
||||
videos={videos}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(selectedTeamId || isTeamPage) && (
|
||||
<TeamDashboard
|
||||
builtInRoleRoadmaps={builtInRoleRoadmaps!}
|
||||
builtInSkillRoadmaps={builtInSkillRoadmaps!}
|
||||
teamId={selectedTeamId!}
|
||||
/>
|
||||
<div className="container">
|
||||
<TeamDashboard
|
||||
builtInRoleRoadmaps={builtInRoleRoadmaps!}
|
||||
builtInSkillRoadmaps={builtInSkillRoadmaps!}
|
||||
teamId={selectedTeamId!}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DashboardTabSkeleton() {
|
||||
return (
|
||||
<div className="h-[30px] w-[114px] animate-pulse rounded-md border bg-white"></div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ type DashboardTabProps = {
|
||||
icon?: ReactNode;
|
||||
};
|
||||
|
||||
export function DashboardTab(props: DashboardTabProps) {
|
||||
export function DashboardTabButton(props: DashboardTabProps) {
|
||||
const { isActive, onClick, label, className, href, avatar, icon } = props;
|
||||
|
||||
const Slot = href ? 'a' : 'button';
|
||||
@@ -20,8 +20,10 @@ export function DashboardTab(props: DashboardTabProps) {
|
||||
<Slot
|
||||
onClick={onClick}
|
||||
className={cn(
|
||||
'flex h-[30px] shrink-0 items-center gap-1 rounded-md border bg-white p-1.5 px-2 text-sm leading-none text-gray-600',
|
||||
isActive ? 'border-gray-500 bg-gray-200 text-gray-900' : '',
|
||||
'flex h-[30px] shrink-0 items-center gap-1 rounded-md border border-slate-700 bg-slate-800 p-1.5 pl-2 pr-3 text-sm leading-none text-gray-400 transition-colors hover:bg-slate-700',
|
||||
isActive
|
||||
? 'border-slate-200 bg-slate-200 text-gray-900 hover:bg-slate-200'
|
||||
: '',
|
||||
className,
|
||||
)}
|
||||
{...(href ? { href } : {})}
|
||||
@@ -30,7 +32,7 @@ export function DashboardTab(props: DashboardTabProps) {
|
||||
<img
|
||||
src={avatar}
|
||||
alt="avatar"
|
||||
className="h-4 w-4 mr-0.5 rounded-full object-cover"
|
||||
className="mr-0.5 h-4 w-4 rounded-full object-cover"
|
||||
/>
|
||||
)}
|
||||
{icon}
|
||||
@@ -1,23 +1,35 @@
|
||||
import { type JSXElementConstructor, useEffect, useState } from 'react';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import type { UserProgress } from '../TeamProgress/TeamProgressPage';
|
||||
import type { ProjectStatusDocument } from '../Projects/ListProjectSolutions';
|
||||
import type { PageType } from '../CommandMenu/CommandMenu';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import { getCurrentPeriod } from '../../lib/date';
|
||||
import { ListDashboardCustomProgress } from './ListDashboardCustomProgress';
|
||||
import { RecommendedRoadmaps } from './RecommendedRoadmaps';
|
||||
import { ProgressStack } from './ProgressStack';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { $accountStreak, type StreakResponse } from '../../stores/streak';
|
||||
import { CheckEmoji } from '../ReactIcons/CheckEmoji.tsx';
|
||||
import { ConstructionEmoji } from '../ReactIcons/ConstructionEmoji.tsx';
|
||||
import { BookEmoji } from '../ReactIcons/BookEmoji.tsx';
|
||||
import { DashboardAiRoadmaps } from './DashboardAiRoadmaps.tsx';
|
||||
import {
|
||||
ChartColumn,
|
||||
CheckCircle,
|
||||
CheckSquare,
|
||||
FolderGit2,
|
||||
Pencil,
|
||||
SquarePen,
|
||||
Zap,
|
||||
type LucideIcon,
|
||||
} from 'lucide-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { AllowedProfileVisibility } from '../../api/user.ts';
|
||||
import { PencilIcon, type LucideIcon } from 'lucide-react';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import type { AllowedRoadmapRenderer } from '../../lib/roadmap.ts';
|
||||
import { $accountStreak, type StreakResponse } from '../../stores/streak';
|
||||
import type { PageType } from '../CommandMenu/CommandMenu';
|
||||
import {
|
||||
FavoriteRoadmaps,
|
||||
type AIRoadmapType,
|
||||
} from '../HeroSection/FavoriteRoadmaps.tsx';
|
||||
import { HeroRoadmap } from '../HeroSection/HeroRoadmap.tsx';
|
||||
import type { ProjectStatusDocument } from '../Projects/ListProjectSolutions';
|
||||
import type { UserProgress } from '../TeamProgress/TeamProgressPage';
|
||||
import { projectGroups } from '../../pages/index.astro';
|
||||
import type { QuestionGroupType } from '../../lib/question-group';
|
||||
import { FeaturedGuideList } from '../FeaturedGuides/FeaturedGuideList';
|
||||
import { FeaturedVideoList } from '../FeaturedVideos/FeaturedVideoList';
|
||||
import type { GuideFileType } from '../../lib/guide';
|
||||
import type { VideoFileType } from '../../lib/video';
|
||||
|
||||
type UserDashboardResponse = {
|
||||
name: string;
|
||||
@@ -28,11 +40,7 @@ type UserDashboardResponse = {
|
||||
profileVisibility: AllowedProfileVisibility;
|
||||
progresses: UserProgress[];
|
||||
projects: ProjectStatusDocument[];
|
||||
aiRoadmaps: {
|
||||
id: string;
|
||||
title: string;
|
||||
slug: string;
|
||||
}[];
|
||||
aiRoadmaps: AIRoadmapType[];
|
||||
topicDoneToday: number;
|
||||
};
|
||||
|
||||
@@ -42,6 +50,7 @@ export type BuiltInRoadmap = {
|
||||
title: string;
|
||||
description: string;
|
||||
isFavorite?: boolean;
|
||||
isNew?: boolean;
|
||||
relatedRoadmapIds?: string[];
|
||||
renderer?: AllowedRoadmapRenderer;
|
||||
metadata?: Record<string, any>;
|
||||
@@ -51,16 +60,162 @@ type PersonalDashboardProps = {
|
||||
builtInRoleRoadmaps?: BuiltInRoadmap[];
|
||||
builtInSkillRoadmaps?: BuiltInRoadmap[];
|
||||
builtInBestPractices?: BuiltInRoadmap[];
|
||||
questionGroups?: QuestionGroupType[];
|
||||
guides?: GuideFileType[];
|
||||
videos?: VideoFileType[];
|
||||
};
|
||||
|
||||
type DashboardStatItemProps = {
|
||||
icon: LucideIcon;
|
||||
iconClassName: string;
|
||||
value: number;
|
||||
label: string;
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
||||
function DashboardStatItem(props: DashboardStatItemProps) {
|
||||
const { icon: Icon, iconClassName, value, label, isLoading } = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center gap-1.5 rounded-lg bg-slate-800/50 py-2 pl-3 pr-3',
|
||||
{
|
||||
'striped-loader-slate striped-loader-slate-fast text-transparent':
|
||||
isLoading,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
size={16}
|
||||
className={cn(iconClassName, { 'text-transparent': isLoading })}
|
||||
/>
|
||||
<span>
|
||||
<span className="tabular-nums">{value}</span> {label}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type ProfileButtonProps = {
|
||||
isLoading: boolean;
|
||||
name?: string;
|
||||
username?: string;
|
||||
avatar?: string;
|
||||
};
|
||||
|
||||
function PersonalProfileButton(props: ProfileButtonProps) {
|
||||
const { isLoading, name, username, avatar } = props;
|
||||
|
||||
if (isLoading || !username) {
|
||||
return (
|
||||
<a
|
||||
href="/account/update-profile"
|
||||
className={cn(
|
||||
'flex items-center gap-2 rounded-lg bg-slate-800/50 py-2 pl-3 pr-3 font-medium outline-slate-700 hover:bg-slate-800 hover:outline-slate-400',
|
||||
{
|
||||
'striped-loader-slate striped-loader-slate-fast text-transparent':
|
||||
isLoading,
|
||||
'bg-blue-500/10 text-blue-500 hover:bg-blue-500/20': !isLoading,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<CheckSquare className="h-4 w-4" strokeWidth={2.5} />
|
||||
Set up your profile
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex gap-1.5">
|
||||
<a
|
||||
href={`/u/${username}`}
|
||||
className="flex items-center gap-2 rounded-lg bg-slate-800/50 py-2 pl-3 pr-3 text-slate-300 transition-colors hover:bg-slate-800/70"
|
||||
>
|
||||
<img
|
||||
src={avatar}
|
||||
alt={name || 'Profile'}
|
||||
className="h-5 w-5 rounded-full ring-1 ring-slate-700"
|
||||
/>
|
||||
<span className="font-medium">Visit Profile</span>
|
||||
</a>
|
||||
<a
|
||||
href="/account/update-profile"
|
||||
className="flex items-center gap-2 rounded-lg bg-slate-800/50 py-2 pl-3 pr-3 text-slate-400 transition-colors hover:bg-slate-800/70 hover:text-slate-300"
|
||||
title="Edit Profile"
|
||||
>
|
||||
<SquarePen className="h-4 w-4" />
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type DashboardStatsProps = {
|
||||
profile: ProfileButtonProps;
|
||||
accountStreak?: StreakResponse;
|
||||
topicsDoneToday?: number;
|
||||
finishedProjectsCount?: number;
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
||||
function DashboardStats(props: DashboardStatsProps) {
|
||||
const {
|
||||
accountStreak,
|
||||
topicsDoneToday = 0,
|
||||
finishedProjectsCount = 0,
|
||||
isLoading,
|
||||
profile,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className="container mb-3 flex flex-col gap-4 pb-2 pt-6 text-sm text-slate-400 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div className="flex w-full flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<PersonalProfileButton
|
||||
isLoading={isLoading}
|
||||
name={profile.name}
|
||||
username={profile.username}
|
||||
avatar={profile.avatar}
|
||||
/>
|
||||
<div className="hidden flex-wrap items-center gap-2 md:flex">
|
||||
<DashboardStatItem
|
||||
icon={Zap}
|
||||
iconClassName="text-yellow-500"
|
||||
value={accountStreak?.count || 0}
|
||||
label="day streak"
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<DashboardStatItem
|
||||
icon={ChartColumn}
|
||||
iconClassName="text-green-500"
|
||||
value={topicsDoneToday}
|
||||
label="learnt today"
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<DashboardStatItem
|
||||
icon={FolderGit2}
|
||||
iconClassName="text-blue-500"
|
||||
value={finishedProjectsCount}
|
||||
label="projects finished"
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function PersonalDashboard(props: PersonalDashboardProps) {
|
||||
const {
|
||||
builtInRoleRoadmaps = [],
|
||||
builtInBestPractices = [],
|
||||
builtInSkillRoadmaps = [],
|
||||
questionGroups = [],
|
||||
guides = [],
|
||||
videos = [],
|
||||
} = props;
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [personalDashboardDetails, setPersonalDashboardDetails] =
|
||||
useState<UserDashboardResponse>();
|
||||
@@ -138,7 +293,9 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
|
||||
return () => window.removeEventListener('refresh-favorites', loadProgress);
|
||||
}, []);
|
||||
|
||||
const learningRoadmapsToShow = (personalDashboardDetails?.progresses || [])
|
||||
const learningRoadmapsToShow: UserProgress[] = (
|
||||
personalDashboardDetails?.progresses || []
|
||||
)
|
||||
.filter((progress) => !progress.isCustomResource)
|
||||
.sort((a, b) => {
|
||||
const updatedAtA = new Date(a.updatedAt);
|
||||
@@ -156,7 +313,10 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
|
||||
});
|
||||
|
||||
const aiGeneratedRoadmaps = personalDashboardDetails?.aiRoadmaps || [];
|
||||
const customRoadmaps = (personalDashboardDetails?.progresses || [])
|
||||
|
||||
const customRoadmaps: UserProgress[] = (
|
||||
personalDashboardDetails?.progresses || []
|
||||
)
|
||||
.filter((progress) => progress.isCustomResource)
|
||||
.sort((a, b) => {
|
||||
const updatedAtA = new Date(a.updatedAt);
|
||||
@@ -169,43 +329,6 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
|
||||
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
|
||||
: '/images/default-avatar.png';
|
||||
|
||||
const allRoadmapsAndBestPractices = [
|
||||
...builtInRoleRoadmaps,
|
||||
...builtInSkillRoadmaps,
|
||||
...builtInBestPractices,
|
||||
];
|
||||
|
||||
const relatedRoadmapIds = allRoadmapsAndBestPractices
|
||||
// take the ones that user is learning
|
||||
.filter((roadmap) =>
|
||||
learningRoadmapsToShow?.some(
|
||||
(learningRoadmap) => learningRoadmap.resourceId === roadmap.id,
|
||||
),
|
||||
)
|
||||
.flatMap((roadmap) => roadmap.relatedRoadmapIds)
|
||||
// remove the ones that user is already learning or has bookmarked
|
||||
.filter(
|
||||
(roadmapId) =>
|
||||
!learningRoadmapsToShow.some((lr) => lr.resourceId === roadmapId),
|
||||
);
|
||||
|
||||
const recommendedRoadmapIds = new Set(
|
||||
relatedRoadmapIds.length === 0
|
||||
? [
|
||||
'frontend',
|
||||
'backend',
|
||||
'devops',
|
||||
'ai-data-scientist',
|
||||
'full-stack',
|
||||
'api-design',
|
||||
]
|
||||
: relatedRoadmapIds,
|
||||
);
|
||||
|
||||
const recommendedRoadmaps = allRoadmapsAndBestPractices.filter((roadmap) =>
|
||||
recommendedRoadmapIds.has(roadmap.id),
|
||||
);
|
||||
|
||||
const enrichedProjects = personalDashboardDetails?.projects
|
||||
.map((project) => {
|
||||
const projectDetail = projectDetails.find(
|
||||
@@ -232,165 +355,200 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
|
||||
const { username } = personalDashboardDetails || {};
|
||||
|
||||
return (
|
||||
<section>
|
||||
{isLoading ? (
|
||||
<div className="h-7 w-1/4 animate-pulse rounded-lg bg-gray-200"></div>
|
||||
) : (
|
||||
<div className="flex flex-col items-start justify-between gap-1 sm:flex-row sm:items-center">
|
||||
<h2 className="text-lg font-medium">
|
||||
Hi {name}, good {getCurrentPeriod()}!
|
||||
</h2>
|
||||
<a
|
||||
href="/home"
|
||||
className="rounded-full bg-gray-200 px-2.5 py-1 text-xs font-medium text-gray-700 hover:bg-gray-300 hover:text-black"
|
||||
>
|
||||
Visit Homepage
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-4">
|
||||
{isLoading ? (
|
||||
<>
|
||||
<DashboardCardSkeleton />
|
||||
<DashboardCardSkeleton />
|
||||
<DashboardCardSkeleton />
|
||||
<DashboardCardSkeleton />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<DashboardCard
|
||||
imgUrl={avatarLink}
|
||||
title={name!}
|
||||
description={
|
||||
username ? 'View your profile' : 'Setup your profile'
|
||||
}
|
||||
href={username ? `/u/${username}` : '/account/update-profile'}
|
||||
{...(username && {
|
||||
externalLinkIcon: PencilIcon,
|
||||
externalLinkHref: '/account/update-profile',
|
||||
externalLinkText: 'Edit',
|
||||
})}
|
||||
className={
|
||||
!username
|
||||
? 'border-dashed border-gray-500 bg-gray-100 hover:border-gray-500 hover:bg-gray-200'
|
||||
: ''
|
||||
}
|
||||
/>
|
||||
|
||||
<DashboardCard
|
||||
icon={BookEmoji}
|
||||
title="Visit Roadmaps"
|
||||
description="Learn new skills"
|
||||
href="/roadmaps"
|
||||
/>
|
||||
|
||||
<DashboardCard
|
||||
icon={ConstructionEmoji}
|
||||
title="Build Projects"
|
||||
description="Practice what you learn"
|
||||
href="/projects"
|
||||
/>
|
||||
<DashboardCard
|
||||
icon={CheckEmoji}
|
||||
title="Best Practices"
|
||||
description="Do things the right way"
|
||||
href="/best-practices"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ProgressStack
|
||||
progresses={learningRoadmapsToShow}
|
||||
projects={enrichedProjects || []}
|
||||
<div>
|
||||
<DashboardStats
|
||||
profile={{
|
||||
name,
|
||||
username,
|
||||
avatar: avatarLink,
|
||||
isLoading,
|
||||
}}
|
||||
isLoading={isLoading}
|
||||
accountStreak={accountStreak}
|
||||
topicDoneToday={personalDashboardDetails?.topicDoneToday || 0}
|
||||
topicsDoneToday={personalDashboardDetails?.topicDoneToday}
|
||||
finishedProjectsCount={
|
||||
enrichedProjects?.filter((p) => p.submittedAt && p.repositoryUrl)
|
||||
.length
|
||||
}
|
||||
/>
|
||||
|
||||
<ListDashboardCustomProgress
|
||||
progresses={customRoadmaps}
|
||||
<FavoriteRoadmaps
|
||||
progress={learningRoadmapsToShow}
|
||||
customRoadmaps={customRoadmaps}
|
||||
aiRoadmaps={aiGeneratedRoadmaps}
|
||||
projects={enrichedProjects || []}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
|
||||
<DashboardAiRoadmaps
|
||||
roadmaps={aiGeneratedRoadmaps}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<div className="bg-gradient-to-b from-slate-900 to-black pb-12">
|
||||
<div className="relative mt-6 border-t border-t-[#1e293c] pt-12">
|
||||
<div className="container">
|
||||
<h2
|
||||
id="role-based-roadmaps"
|
||||
className="text-md font-regular absolute -top-[17px] left-4 flex rounded-lg border border-[#1e293c] bg-slate-900 px-3 py-1 text-slate-400 sm:left-1/2 sm:-translate-x-1/2"
|
||||
>
|
||||
Role Based Roadmaps
|
||||
</h2>
|
||||
|
||||
<RecommendedRoadmaps
|
||||
roadmaps={recommendedRoadmaps}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
<div className="grid grid-cols-1 gap-3 px-2 sm:grid-cols-2 sm:px-0 lg:grid-cols-3">
|
||||
{builtInRoleRoadmaps.map((roadmap) => {
|
||||
const roadmapProgress = learningRoadmapsToShow.find(
|
||||
(lr) => lr.resourceId === roadmap.id,
|
||||
);
|
||||
|
||||
type DashboardCardProps = {
|
||||
icon?: JSXElementConstructor<any>;
|
||||
imgUrl?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
href: string;
|
||||
externalLinkIcon?: LucideIcon;
|
||||
externalLinkText?: string;
|
||||
externalLinkHref?: string;
|
||||
className?: string;
|
||||
};
|
||||
const percentageDone =
|
||||
(((roadmapProgress?.skipped || 0) +
|
||||
(roadmapProgress?.done || 0)) /
|
||||
(roadmapProgress?.total || 1)) *
|
||||
100;
|
||||
|
||||
function DashboardCard(props: DashboardCardProps) {
|
||||
const {
|
||||
icon: Icon,
|
||||
imgUrl,
|
||||
title,
|
||||
description,
|
||||
href,
|
||||
externalLinkHref,
|
||||
externalLinkIcon: ExternalLinkIcon,
|
||||
externalLinkText,
|
||||
className,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className={cn('relative overflow-hidden', className)}>
|
||||
<a
|
||||
href={href}
|
||||
className="flex flex-col rounded-lg border border-gray-300 bg-white hover:border-gray-400 hover:bg-gray-50"
|
||||
>
|
||||
{Icon && (
|
||||
<div className="px-4 pb-3 pt-4">
|
||||
<Icon className="size-6" />
|
||||
return (
|
||||
<HeroRoadmap
|
||||
key={roadmap.id}
|
||||
resourceId={roadmap.id}
|
||||
resourceType="roadmap"
|
||||
resourceTitle={roadmap.title}
|
||||
isFavorite={roadmap.isFavorite}
|
||||
percentageDone={percentageDone}
|
||||
isNew={roadmap.isNew}
|
||||
url={`/${roadmap.id}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{imgUrl && (
|
||||
<div className="px-4 pb-1.5 pt-3.5">
|
||||
<img src={imgUrl} alt={title} className="size-8 rounded-full" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex grow flex-col justify-center gap-0.5 p-4">
|
||||
<h3 className="truncate font-medium text-black">{title}</h3>
|
||||
<p className="text-xs text-black">{description}</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{externalLinkHref && (
|
||||
<a
|
||||
href={externalLinkHref}
|
||||
className="absolute right-1 top-1 flex items-center gap-1.5 rounded-md bg-gray-200 p-1 px-2 text-xs text-gray-600 hover:bg-gray-300 hover:text-black"
|
||||
>
|
||||
{ExternalLinkIcon && <ExternalLinkIcon className="size-3" />}
|
||||
{externalLinkText}
|
||||
</a>
|
||||
)}
|
||||
<div className="relative mt-12 border-t border-t-[#1e293c] pt-12">
|
||||
<div className="container">
|
||||
<h2 className="text-md font-regular absolute -top-[17px] left-4 flex rounded-lg border border-[#1e293c] bg-slate-900 px-3 py-1 text-slate-400 sm:left-1/2 sm:-translate-x-1/2">
|
||||
Skill Based Roadmaps
|
||||
</h2>
|
||||
|
||||
<div className="grid grid-cols-1 gap-3 px-2 sm:grid-cols-2 sm:px-0 lg:grid-cols-3">
|
||||
{builtInSkillRoadmaps.map((roadmap) => {
|
||||
const roadmapProgress = learningRoadmapsToShow.find(
|
||||
(lr) => lr.resourceId === roadmap.id,
|
||||
);
|
||||
|
||||
const percentageDone =
|
||||
(((roadmapProgress?.skipped || 0) +
|
||||
(roadmapProgress?.done || 0)) /
|
||||
(roadmapProgress?.total || 1)) *
|
||||
100;
|
||||
|
||||
return (
|
||||
<HeroRoadmap
|
||||
key={roadmap.id}
|
||||
resourceId={roadmap.id}
|
||||
resourceType="roadmap"
|
||||
resourceTitle={roadmap.title}
|
||||
isFavorite={roadmap.isFavorite}
|
||||
percentageDone={percentageDone}
|
||||
isNew={roadmap.isNew}
|
||||
url={`/${roadmap.id}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-12 border-t border-t-[#1e293c] pt-12">
|
||||
<div className="container">
|
||||
<h2 className="text-md font-regular absolute -top-[17px] left-4 flex rounded-lg border border-[#1e293c] bg-slate-900 px-3 py-1 text-slate-400 sm:left-1/2 sm:-translate-x-1/2">
|
||||
Project Ideas
|
||||
</h2>
|
||||
|
||||
<div className="grid grid-cols-1 gap-3 px-2 sm:grid-cols-2 sm:px-0 lg:grid-cols-3">
|
||||
{projectGroups.map((projectGroup) => {
|
||||
return (
|
||||
<HeroRoadmap
|
||||
percentageDone={0}
|
||||
key={projectGroup.id}
|
||||
resourceId={projectGroup.id}
|
||||
resourceType="roadmap"
|
||||
resourceTitle={projectGroup.title}
|
||||
url={`/${projectGroup.id}/projects`}
|
||||
allowFavorite={false}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-12 border-t border-t-[#1e293c] pt-12">
|
||||
<div className="container">
|
||||
<h2 className="text-md font-regular absolute -top-[17px] left-4 flex rounded-lg border border-[#1e293c] bg-slate-900 px-3 py-1 text-slate-400 sm:left-1/2 sm:-translate-x-1/2">
|
||||
Best Practices
|
||||
</h2>
|
||||
|
||||
<div className="grid grid-cols-1 gap-3 px-2 sm:grid-cols-2 sm:px-0 lg:grid-cols-3">
|
||||
{builtInBestPractices.map((roadmap) => {
|
||||
const roadmapProgress = learningRoadmapsToShow.find(
|
||||
(lr) => lr.resourceId === roadmap.id,
|
||||
);
|
||||
|
||||
const percentageDone =
|
||||
(((roadmapProgress?.skipped || 0) +
|
||||
(roadmapProgress?.done || 0)) /
|
||||
(roadmapProgress?.total || 1)) *
|
||||
100;
|
||||
|
||||
return (
|
||||
<HeroRoadmap
|
||||
key={roadmap.id}
|
||||
resourceId={roadmap.id}
|
||||
resourceType="best-practice"
|
||||
resourceTitle={roadmap.title}
|
||||
isFavorite={roadmap.isFavorite}
|
||||
percentageDone={percentageDone}
|
||||
isNew={roadmap.isNew}
|
||||
url={`/best-practices/${roadmap.id}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-12 border-t border-t-[#1e293c] pt-12">
|
||||
<div className="container">
|
||||
<h2 className="text-md font-regular absolute -top-[17px] left-4 flex rounded-lg border border-[#1e293c] bg-slate-900 px-3 py-1 text-slate-400 sm:left-1/2 sm:-translate-x-1/2">
|
||||
Questions
|
||||
</h2>
|
||||
|
||||
<div className="grid grid-cols-1 gap-3 px-2 sm:grid-cols-2 sm:px-0 lg:grid-cols-3">
|
||||
{questionGroups.map((questionGroup) => {
|
||||
return (
|
||||
<HeroRoadmap
|
||||
percentageDone={0}
|
||||
key={questionGroup.id}
|
||||
resourceId={questionGroup.id}
|
||||
resourceType="roadmap"
|
||||
resourceTitle={questionGroup.frontmatter.briefTitle}
|
||||
url={`/questions/${questionGroup.id}`}
|
||||
allowFavorite={false}
|
||||
isNew={questionGroup.frontmatter.isNew}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-5 bg-gray-50 px-4 py-5 sm:gap-16 sm:px-0 sm:py-16">
|
||||
<FeaturedGuideList
|
||||
heading="Guides"
|
||||
guides={guides}
|
||||
questions={questionGroups
|
||||
.filter((questionGroup) => questionGroup.frontmatter.authorId)
|
||||
.slice(0, 7)}
|
||||
/>
|
||||
<FeaturedVideoList heading="Videos" videos={videos} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DashboardCardSkeleton() {
|
||||
return (
|
||||
<div className="h-[128px] animate-pulse rounded-lg border border-gray-300 bg-white"></div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,80 +6,24 @@ import { isMobileScreen } from '../lib/is-mobile.ts';
|
||||
type FeatureAnnouncementProps = {};
|
||||
|
||||
export function FeatureAnnouncement(props: FeatureAnnouncementProps) {
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
|
||||
const videoModal = (
|
||||
<Modal
|
||||
onClose={() => setIsPlaying(false)}
|
||||
bodyClassName={'h-auto overflow-hidden'}
|
||||
wrapperClassName={'md:max-w-3xl lg:max-w-4xl xl:max-w-5xl'}
|
||||
>
|
||||
<div className="text-balance bg-gradient-to-r from-gray-100 px-4 py-2 text-left text-sm md:py-3 lg:text-base">
|
||||
<span
|
||||
className="relative -top-px mr-1.5 rounded bg-blue-300 px-1.5 py-0.5 text-xs font-semibold uppercase text-gray-800"
|
||||
style={{ lineHeight: '1.5' }}
|
||||
>
|
||||
New
|
||||
</span>
|
||||
Projects are live on the{' '}
|
||||
<a
|
||||
href={'/projects'}
|
||||
className="font-medium text-blue-500 underline underline-offset-2"
|
||||
>
|
||||
backend roadmap
|
||||
</a>
|
||||
<span className={'hidden md:inline'}>
|
||||
{' '}
|
||||
and are coming soon on the others{' '}
|
||||
</span>
|
||||
<PartyPopper className="relative -top-[3px] ml-2 inline-block h-5 w-5 text-blue-500 md:ml-1 md:h-6 md:w-6" />
|
||||
</div>
|
||||
<div
|
||||
className="iframe-container"
|
||||
style={{
|
||||
position: 'relative',
|
||||
paddingBottom: '56.25%',
|
||||
height: 0,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{/*https://www.youtube.com/embed/?playsinline=1&disablekb=1&&iv_load_policy=3&cc_load_policy=0&controls=0&rel=0&autoplay=1&mute=1&origin=https%3A%2F%2Fytch.xyz&widgetid=1*/}
|
||||
<iframe
|
||||
src="https://www.youtube.com/embed/9lS3slfJ0x0?start=31&autoplay=1&disablekb=1&rel=0&cc_load_policy=0&rel=0&autoplay=1&origin=https%3A%2F%2Froadmap.sh&widgetid=1&showinfo=0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
return null;
|
||||
return (
|
||||
<>
|
||||
{isPlaying && videoModal}
|
||||
<button
|
||||
<a
|
||||
className="rounded-md border border-dashed border-purple-600 px-3 py-1.5 text-purple-400 transition-colors hover:border-purple-400 hover:text-purple-200"
|
||||
onClick={() => {
|
||||
setIsPlaying(true);
|
||||
}}
|
||||
href="/courses/sql"
|
||||
>
|
||||
<span className="relative sm:-top-[1px] mr-1 text-xs font-semibold uppercase text-white">
|
||||
<PlayCircle className="inline-block h-4 w-4 relative -top-[2px] mr-1" />
|
||||
Watch
|
||||
<PartyPopper className="inline-block h-4 w-4 relative -top-[2px] mr-1" />
|
||||
Courses
|
||||
</span>{' '}
|
||||
<span className={'hidden sm:inline'}>
|
||||
Practice your skills with projects
|
||||
Our first paid course about SQL is now live!
|
||||
</span>
|
||||
<span className={'inline text-sm sm:hidden'}>
|
||||
Build projects to skill up
|
||||
Our SQL course is now live!
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
import type { GuideFileType } from '../lib/guide';
|
||||
import GuideListItem from './GuideListItem.astro';
|
||||
import { QuestionGroupType } from '../lib/question-group';
|
||||
|
||||
export interface Props {
|
||||
heading: string;
|
||||
guides: GuideFileType[];
|
||||
questions: QuestionGroupType[];
|
||||
}
|
||||
|
||||
const { heading, guides, questions = [] } = Astro.props;
|
||||
|
||||
const sortedGuides: (QuestionGroupType | GuideFileType)[] = [
|
||||
...guides,
|
||||
...questions,
|
||||
].sort((a, b) => {
|
||||
const aDate = new Date(a.frontmatter.date);
|
||||
const bDate = new Date(b.frontmatter.date);
|
||||
|
||||
return bDate.getTime() - aDate.getTime();
|
||||
});
|
||||
---
|
||||
|
||||
<div class='container'>
|
||||
<h2 class='block text-2xl font-bold sm:text-3xl'>{heading}</h2>
|
||||
|
||||
<div class='mt-3 sm:my-5'>
|
||||
{sortedGuides.map((guide) => <GuideListItem guide={guide} />)}
|
||||
</div>
|
||||
|
||||
<a
|
||||
href='/guides'
|
||||
class='hidden rounded-full bg-gradient-to-r from-slate-600 to-black px-3 py-2 text-xs font-medium text-white transition-colors hover:from-blue-600 hover:to-blue-800 sm:inline'
|
||||
>
|
||||
View All Guides →
|
||||
</a>
|
||||
|
||||
<div class='mt-3 block sm:hidden'>
|
||||
<a
|
||||
href='/guides'
|
||||
class='font-regular block rounded-md border border-black p-2 text-center text-sm text-black hover:bg-black hover:text-gray-50'
|
||||
>
|
||||
View All Guides →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
51
src/components/FeaturedGuides/FeaturedGuideList.tsx
Normal file
51
src/components/FeaturedGuides/FeaturedGuideList.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import type { GuideFileType } from '../../lib/guide';
|
||||
import type { QuestionGroupType } from '../../lib/question-group';
|
||||
import { GuideListItem } from './GuideListItem';
|
||||
|
||||
export interface FeaturedGuidesProps {
|
||||
heading: string;
|
||||
guides: GuideFileType[];
|
||||
questions: QuestionGroupType[];
|
||||
}
|
||||
|
||||
export function FeaturedGuideList(props: FeaturedGuidesProps) {
|
||||
const { heading, guides, questions = [] } = props;
|
||||
|
||||
const sortedGuides: (QuestionGroupType | GuideFileType)[] = [
|
||||
...guides,
|
||||
...questions,
|
||||
].sort((a, b) => {
|
||||
const aDate = new Date(a.frontmatter.date as string);
|
||||
const bDate = new Date(b.frontmatter.date as string);
|
||||
|
||||
return bDate.getTime() - aDate.getTime();
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<h2 className="block text-2xl font-bold sm:text-3xl">{heading}</h2>
|
||||
|
||||
<div className="mt-3 sm:my-5">
|
||||
{sortedGuides.map((guide) => (
|
||||
<GuideListItem key={guide.id} guide={guide} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<a
|
||||
href="/guides"
|
||||
className="hidden rounded-full bg-gradient-to-r from-slate-600 to-black px-3 py-2 text-xs font-medium text-white transition-colors hover:from-blue-600 hover:to-blue-800 sm:inline"
|
||||
>
|
||||
View All Guides →
|
||||
</a>
|
||||
|
||||
<div className="mt-3 block sm:hidden">
|
||||
<a
|
||||
href="/guides"
|
||||
className="font-regular block rounded-md border border-black p-2 text-center text-sm text-black hover:bg-black hover:text-gray-50"
|
||||
>
|
||||
View All Guides →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
57
src/components/FeaturedGuides/GuideListItem.tsx
Normal file
57
src/components/FeaturedGuides/GuideListItem.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import type { GuideFileType, GuideFrontmatter } from '../../lib/guide';
|
||||
import { type QuestionGroupType } from '../../lib/question-group';
|
||||
|
||||
export interface GuideListItemProps {
|
||||
guide: GuideFileType | QuestionGroupType;
|
||||
}
|
||||
|
||||
function isQuestionGroupType(
|
||||
guide: GuideFileType | QuestionGroupType,
|
||||
): guide is QuestionGroupType {
|
||||
return (guide as QuestionGroupType).questions !== undefined;
|
||||
}
|
||||
|
||||
export function GuideListItem(props: GuideListItemProps) {
|
||||
const { guide } = props;
|
||||
const { frontmatter, id } = guide;
|
||||
|
||||
let pageUrl = '';
|
||||
let guideType = '';
|
||||
|
||||
if (isQuestionGroupType(guide)) {
|
||||
pageUrl = `/questions/${id}`;
|
||||
guideType = 'Questions';
|
||||
} else {
|
||||
const excludedBySlug = (frontmatter as GuideFrontmatter).excludedBySlug;
|
||||
pageUrl = excludedBySlug ? excludedBySlug : `/guides/${id}`;
|
||||
guideType = (frontmatter as GuideFrontmatter).type;
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
className="text-md group block flex items-center justify-between border-b py-2 text-gray-600 no-underline hover:text-blue-600"
|
||||
href={pageUrl}
|
||||
>
|
||||
<span className="text-sm transition-transform group-hover:translate-x-2 md:text-base">
|
||||
{frontmatter.title}
|
||||
|
||||
{frontmatter.isNew && (
|
||||
<span className="ml-2.5 rounded-sm bg-green-300 px-1.5 py-0.5 text-xs font-medium uppercase text-green-900">
|
||||
New
|
||||
<span className="hidden sm:inline">
|
||||
·
|
||||
{new Date(frontmatter.date || '').toLocaleString('default', {
|
||||
month: 'long',
|
||||
})}
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
<span className="hidden text-xs capitalize text-gray-500 sm:block">
|
||||
{guideType}
|
||||
</span>
|
||||
|
||||
<span className="block text-xs text-gray-400 sm:hidden"> »</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
import type { VideoFileType } from '../lib/video';
|
||||
import VideoListItem from './VideoListItem.astro';
|
||||
|
||||
export interface Props {
|
||||
heading: string;
|
||||
videos: VideoFileType[];
|
||||
}
|
||||
|
||||
const { heading, videos } = Astro.props;
|
||||
---
|
||||
|
||||
<div class='container'>
|
||||
<h2 class='text-2xl sm:text-3xl font-bold block'>{heading}</h2>
|
||||
|
||||
<div class='mt-3 sm:my-5'>
|
||||
{videos.map((video) => <VideoListItem video={video} />)}
|
||||
</div>
|
||||
|
||||
<a
|
||||
href='/videos'
|
||||
class='hidden sm:inline transition-colors py-2 px-3 text-xs font-medium rounded-full bg-gradient-to-r from-slate-600 to-black hover:from-blue-600 hover:to-blue-800 text-white'
|
||||
>
|
||||
View All Videos →
|
||||
</a>
|
||||
|
||||
<div class='block sm:hidden mt-3'>
|
||||
<a
|
||||
href='/videos'
|
||||
class='text-sm font-regular block p-2 border border-black text-black rounded-md text-center hover:bg-black hover:text-gray-50'
|
||||
>
|
||||
View All Videos →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
39
src/components/FeaturedVideos/FeaturedVideoList.tsx
Normal file
39
src/components/FeaturedVideos/FeaturedVideoList.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import type { VideoFileType } from '../../lib/video';
|
||||
import { VideoListItem } from './VideoListItem';
|
||||
|
||||
export interface FeaturedVideoListProps {
|
||||
heading: string;
|
||||
videos: VideoFileType[];
|
||||
}
|
||||
|
||||
export function FeaturedVideoList(props: FeaturedVideoListProps) {
|
||||
const { heading, videos } = props;
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<h2 className="block text-2xl font-bold sm:text-3xl">{heading}</h2>
|
||||
|
||||
<div className="mt-3 sm:my-5">
|
||||
{videos.map((video) => (
|
||||
<VideoListItem key={video.id} video={video} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<a
|
||||
href="/videos"
|
||||
className="hidden rounded-full bg-gradient-to-r from-slate-600 to-black px-3 py-2 text-xs font-medium text-white transition-colors hover:from-blue-600 hover:to-blue-800 sm:inline"
|
||||
>
|
||||
View All Videos →
|
||||
</a>
|
||||
|
||||
<div className="mt-3 block sm:hidden">
|
||||
<a
|
||||
href="/videos"
|
||||
className="font-regular block rounded-md border border-black p-2 text-center text-sm text-black hover:bg-black hover:text-gray-50"
|
||||
>
|
||||
View All Videos →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
38
src/components/FeaturedVideos/VideoListItem.tsx
Normal file
38
src/components/FeaturedVideos/VideoListItem.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { VideoFileType } from '../../lib/video';
|
||||
|
||||
export interface VideoListItemProps {
|
||||
video: VideoFileType;
|
||||
}
|
||||
|
||||
export function VideoListItem(props: VideoListItemProps) {
|
||||
const { video } = props;
|
||||
const { frontmatter, id } = video;
|
||||
|
||||
return (
|
||||
<a
|
||||
className="block no-underline py-2 group text-md items-center text-gray-600 hover:text-blue-600 flex justify-between border-b"
|
||||
href={`/videos/${id}`}
|
||||
>
|
||||
<span className="group-hover:translate-x-2 transition-transform">
|
||||
{frontmatter.title}
|
||||
|
||||
{frontmatter.isNew && (
|
||||
<span className="bg-green-300 text-green-900 text-xs font-medium px-1.5 py-0.5 rounded-sm uppercase ml-1.5">
|
||||
New
|
||||
<span className="hidden sm:inline">
|
||||
·
|
||||
{new Date(frontmatter.date).toLocaleString('default', {
|
||||
month: 'long',
|
||||
})}
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
<span className="capitalize text-gray-500 text-xs hidden sm:block">
|
||||
{frontmatter.duration}
|
||||
</span>
|
||||
|
||||
<span className="text-gray-400 text-xs block sm:hidden"> »</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
import { getGuideTableOfContent, type GuideFileType } from '../../lib/guide';
|
||||
import MarkdownFile from '../MarkdownFile.astro';
|
||||
import { TableOfContent } from '../TableOfContent/TableOfContent';
|
||||
import { replaceVariables } from '../../lib/markdown';
|
||||
import { RelatedGuides } from './RelatedGuides';
|
||||
|
||||
interface Props {
|
||||
@@ -16,18 +15,17 @@ const tableOfContent = getGuideTableOfContent(allHeadings);
|
||||
|
||||
const showTableOfContent = tableOfContent.length > 0;
|
||||
const showRelatedGuides =
|
||||
guide?.frontmatter?.relatedGuides &&
|
||||
Object.keys(guide?.frontmatter?.relatedGuides).length > 0;
|
||||
guide?.relatedGuides && Object.keys(guide?.relatedGuides).length > 0;
|
||||
const { frontmatter: guideFrontmatter, author } = guide;
|
||||
---
|
||||
|
||||
<article class='lg:grid lg:max-w-full lg:grid-cols-[1fr_minmax(0,700px)_1fr]'>
|
||||
{
|
||||
(showTableOfContent || showRelatedGuides) && (
|
||||
<div class='bg-gradient-to-r from-gray-50 py-0 lg:col-start-3 lg:col-end-4 lg:row-start-1'>
|
||||
<div class='sticky top-0 lg:relative bg-gradient-to-r from-gray-50 py-0 lg:col-start-3 lg:col-end-4 lg:row-start-1'>
|
||||
<RelatedGuides
|
||||
relatedTitle={guideFrontmatter?.relatedTitle}
|
||||
relatedGuides={guideFrontmatter?.relatedGuides || {}}
|
||||
relatedGuides={guide?.relatedGuides || {}}
|
||||
client:load
|
||||
/>
|
||||
<TableOfContent toc={tableOfContent} client:load />
|
||||
@@ -45,7 +43,7 @@ const { frontmatter: guideFrontmatter, author } = guide;
|
||||
>
|
||||
<MarkdownFile>
|
||||
<h1 class='mb-3 text-balance text-4xl font-bold'>
|
||||
{replaceVariables(guideFrontmatter.title)}
|
||||
{guideFrontmatter.title}
|
||||
</h1>
|
||||
<p class='my-0 flex items-center justify-start text-sm text-gray-400'>
|
||||
<a
|
||||
|
||||
@@ -24,14 +24,10 @@ export function RelatedGuides(props: RelatedGuidesProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'relative min-w-[250px] px-5 pt-0 max-lg:hidden lg:pt-10',
|
||||
)}
|
||||
>
|
||||
<div className={cn('relative min-w-[250px] pt-0 lg:px-5 lg:pt-10')}>
|
||||
<h4 className="text-lg font-medium max-lg:hidden">{relatedTitle}</h4>
|
||||
<button
|
||||
className="flex w-full items-center justify-between gap-2 bg-gray-300 px-3 py-2 text-sm font-medium lg:hidden"
|
||||
className="flex border-b w-full items-center justify-between gap-2 bg-gray-300 px-3 py-2 text-sm font-medium lg:hidden"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
{relatedTitle}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
---
|
||||
import type { GuideFileType } from '../lib/guide';
|
||||
import { replaceVariables } from '../lib/markdown';
|
||||
|
||||
export interface Props {
|
||||
guide: GuideFileType;
|
||||
}
|
||||
|
||||
const { guide } = Astro.props;
|
||||
const { frontmatter, author } = guide;
|
||||
|
||||
return undefined;
|
||||
---
|
||||
|
||||
<div class='border-b bg-white py-5 sm:py-12'>
|
||||
<div class='container text-left sm:text-center'>
|
||||
<p
|
||||
class='hidden items-center justify-start text-gray-400 sm:flex sm:justify-center'
|
||||
>
|
||||
{
|
||||
author?.frontmatter && (
|
||||
<>
|
||||
<a
|
||||
href={`/authors/${author.id}`}
|
||||
class='inline-flex items-center font-medium hover:text-gray-600 hover:underline'
|
||||
>
|
||||
<img
|
||||
alt={author.frontmatter.name}
|
||||
src={author.frontmatter.imageUrl}
|
||||
class='mr-2 inline h-5 w-5 rounded-full'
|
||||
/>
|
||||
{author.frontmatter.name}
|
||||
</a>
|
||||
<span class='mx-1.5'>·</span>
|
||||
</>
|
||||
)
|
||||
}
|
||||
<span class='capitalize'>{frontmatter.type} Guide</span>
|
||||
<span class='mx-1.5'>·</span>
|
||||
<a
|
||||
class='text-blue-400 hover:text-blue-500 hover:underline'
|
||||
href={`https://github.com/kamranahmedse/developer-roadmap/tree/master/src/data/guides/${guide.id}.md`}
|
||||
target='_blank'>Improve this Guide</a
|
||||
>
|
||||
</p>
|
||||
<h1 class='my-0 text-balance text-2xl font-bold sm:my-3.5 sm:text-5xl'>
|
||||
{replaceVariables(frontmatter.title)}
|
||||
</h1>
|
||||
<p class='hidden text-xl text-gray-400 sm:block'>
|
||||
{replaceVariables(frontmatter.description)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,62 +0,0 @@
|
||||
---
|
||||
import type { GuideFileType, GuideFrontmatter } from '../lib/guide';
|
||||
import { replaceVariables } from '../lib/markdown';
|
||||
import { QuestionGroupType } from '../lib/question-group';
|
||||
|
||||
export interface Props {
|
||||
guide: GuideFileType | QuestionGroupType;
|
||||
}
|
||||
|
||||
function isQuestionGroupType(
|
||||
guide: GuideFileType | QuestionGroupType,
|
||||
): guide is QuestionGroupType {
|
||||
return (guide as QuestionGroupType).questions !== undefined;
|
||||
}
|
||||
|
||||
const { guide } = Astro.props;
|
||||
const { frontmatter, id } = guide;
|
||||
|
||||
let pageUrl = '';
|
||||
let guideType = '';
|
||||
|
||||
if (isQuestionGroupType(guide)) {
|
||||
pageUrl = `/questions/${id}`;
|
||||
guideType = 'Questions';
|
||||
} else {
|
||||
const excludedBySlug = (frontmatter as GuideFrontmatter).excludedBySlug;
|
||||
pageUrl = excludedBySlug ? excludedBySlug : `/guides/${id}`;
|
||||
guideType = (frontmatter as GuideFrontmatter).type;
|
||||
}
|
||||
---
|
||||
|
||||
<a
|
||||
class:list={[
|
||||
'text-md group block flex items-center justify-between border-b py-2 text-gray-600 no-underline hover:text-blue-600',
|
||||
]}
|
||||
href={pageUrl}
|
||||
>
|
||||
<span
|
||||
class='text-sm transition-transform group-hover:translate-x-2 md:text-base'
|
||||
>
|
||||
{replaceVariables(frontmatter.title)}
|
||||
|
||||
{
|
||||
frontmatter.isNew && (
|
||||
<span class='ml-1.5 rounded-sm bg-green-300 px-1.5 py-0.5 text-xs font-medium uppercase text-green-900'>
|
||||
New
|
||||
<span class='hidden sm:inline'>
|
||||
·
|
||||
{new Date(frontmatter.date).toLocaleString('default', {
|
||||
month: 'long',
|
||||
})}
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
</span>
|
||||
<span class='hidden text-xs capitalize text-gray-500 sm:block'>
|
||||
{guideType}
|
||||
</span>
|
||||
|
||||
<span class='block text-xs text-gray-400 sm:hidden'> »</span>
|
||||
</a>
|
||||
@@ -1,164 +1,229 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { EmptyProgress } from './EmptyProgress';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { HeroRoadmaps, type HeroTeamRoadmaps } from './HeroRoadmaps';
|
||||
import { isLoggedIn } from '../../lib/jwt';
|
||||
import type { AllowedMemberRoles } from '../ShareOptions/ShareTeamMemberList.tsx';
|
||||
import {
|
||||
FolderKanban,
|
||||
MapIcon,
|
||||
Plus,
|
||||
Sparkle,
|
||||
Eye,
|
||||
EyeOff,
|
||||
Square,
|
||||
SquareCheckBig,
|
||||
} from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import type { ProjectStatusDocument } from '../Projects/ListProjectSolutions.tsx';
|
||||
import { CheckIcon } from '../ReactIcons/CheckIcon.tsx';
|
||||
import type { UserProgress } from '../TeamProgress/TeamProgressPage.tsx';
|
||||
import { HeroProject } from './HeroProject';
|
||||
import { HeroRoadmap } from './HeroRoadmap';
|
||||
import { CreateRoadmapButton } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapButton.tsx';
|
||||
import { HeroItemsGroup } from './HeroItemsGroup';
|
||||
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx';
|
||||
|
||||
export type UserProgressResponse = {
|
||||
resourceId: string;
|
||||
resourceType: 'roadmap' | 'best-practice';
|
||||
resourceTitle: string;
|
||||
isFavorite: boolean;
|
||||
done: number;
|
||||
learning: number;
|
||||
skipped: number;
|
||||
total: number;
|
||||
updatedAt: Date;
|
||||
isCustomResource: boolean;
|
||||
roadmapSlug?: string;
|
||||
team?: {
|
||||
name: string;
|
||||
id: string;
|
||||
role: AllowedMemberRoles;
|
||||
};
|
||||
}[];
|
||||
export type AIRoadmapType = {
|
||||
id: string;
|
||||
title: string;
|
||||
slug: string;
|
||||
};
|
||||
|
||||
function renderProgress(progressList: UserProgressResponse) {
|
||||
progressList.forEach((progress) => {
|
||||
const href =
|
||||
progress.resourceType === 'best-practice'
|
||||
? `/best-practices/${progress.resourceId}`
|
||||
: `/${progress.resourceId}`;
|
||||
const element = document.querySelector(`a[href="${href}"]`);
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
type FavoriteRoadmapsProps = {
|
||||
progress: UserProgress[];
|
||||
projects: (ProjectStatusDocument & {
|
||||
title: string;
|
||||
})[];
|
||||
customRoadmaps: UserProgress[];
|
||||
aiRoadmaps: AIRoadmapType[];
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('mark-favorite', {
|
||||
detail: {
|
||||
resourceId: progress.resourceId,
|
||||
resourceType: progress.resourceType,
|
||||
isFavorite: progress.isFavorite,
|
||||
},
|
||||
}),
|
||||
);
|
||||
export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
|
||||
const { progress, isLoading, customRoadmaps, aiRoadmaps, projects } = props;
|
||||
const [showCompleted, setShowCompleted] = useState(false);
|
||||
const [isCreatingCustomRoadmap, setIsCreatingCustomRoadmap] = useState(false);
|
||||
|
||||
const totalDone = progress.done + progress.skipped;
|
||||
const percentageDone = (totalDone / progress.total) * 100;
|
||||
|
||||
const progressBar: HTMLElement | null =
|
||||
element.querySelector('[data-progress]');
|
||||
if (progressBar) {
|
||||
progressBar.style.width = `${percentageDone}%`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
type ProgressResponse = UserProgressResponse;
|
||||
|
||||
export function FavoriteRoadmaps() {
|
||||
const isAuthenticated = isLoggedIn();
|
||||
if (!isAuthenticated) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [isPreparing, setIsPreparing] = useState(true);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [progress, setProgress] = useState<ProgressResponse>([]);
|
||||
const [containerOpacity, setContainerOpacity] = useState(0);
|
||||
|
||||
function showProgressContainer() {
|
||||
const heroEl = document.getElementById('hero-text')!;
|
||||
if (!heroEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
heroEl.classList.add('opacity-0');
|
||||
setTimeout(() => {
|
||||
heroEl.parentElement?.removeChild(heroEl);
|
||||
setIsPreparing(false);
|
||||
|
||||
setTimeout(() => {
|
||||
setContainerOpacity(100);
|
||||
}, 50);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
async function loadProgress() {
|
||||
setIsLoading(true);
|
||||
|
||||
const { response: progressList, error } = await httpGet<ProgressResponse>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-get-hero-roadmaps`,
|
||||
);
|
||||
|
||||
if (error || !progressList) {
|
||||
return;
|
||||
}
|
||||
|
||||
setProgress(progressList);
|
||||
setIsLoading(false);
|
||||
showProgressContainer();
|
||||
|
||||
// render progress on featured items
|
||||
renderProgress(progressList);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadProgress().finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('refresh-favorites', loadProgress);
|
||||
return () => window.removeEventListener('refresh-favorites', loadProgress);
|
||||
}, []);
|
||||
|
||||
if (isPreparing) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hasProgress = progress?.length > 0;
|
||||
const customRoadmaps = progress?.filter(
|
||||
(p) => p.isCustomResource && !p.team?.name,
|
||||
const completedProjects = projects.filter(
|
||||
(project) => project.submittedAt && project.repositoryUrl,
|
||||
);
|
||||
const inProgressProjects = projects.filter(
|
||||
(project) => !project.submittedAt || !project.repositoryUrl,
|
||||
);
|
||||
const defaultRoadmaps = progress?.filter((p) => !p.isCustomResource);
|
||||
const teamRoadmaps: HeroTeamRoadmaps = progress
|
||||
?.filter((p) => p.isCustomResource && p.team?.name)
|
||||
.reduce((acc: HeroTeamRoadmaps, curr) => {
|
||||
const currTeam = curr.team!;
|
||||
if (!acc[currTeam.name]) {
|
||||
acc[currTeam.name] = [];
|
||||
}
|
||||
|
||||
acc[currTeam.name].push(curr);
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
const projectsToShow = [
|
||||
...inProgressProjects,
|
||||
...(showCompleted ? completedProjects : []),
|
||||
];
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`transition-opacity duration-500 opacity-${containerOpacity}`}
|
||||
>
|
||||
<div
|
||||
className={`flex min-h-[192px] bg-gradient-to-b sm:min-h-[280px] ${
|
||||
hasProgress && `border-t border-t-[#1e293c]`
|
||||
}`}
|
||||
<div className="flex flex-col">
|
||||
{isCreatingCustomRoadmap && (
|
||||
<CreateRoadmapModal
|
||||
onClose={() => {
|
||||
setIsCreatingCustomRoadmap(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<HeroItemsGroup
|
||||
icon={<CheckIcon additionalClasses="mr-1.5 h-[14px] w-[14px]" />}
|
||||
isLoading={isLoading}
|
||||
title="Your progress and bookmarks"
|
||||
isEmpty={!isLoading && progress.length === 0}
|
||||
emptyTitle={
|
||||
<>
|
||||
No bookmars found
|
||||
<a
|
||||
href="#role-based-roadmaps"
|
||||
className="ml-1.5 inline-flex items-center gap-1 font-medium text-blue-500 underline-offset-2 hover:underline"
|
||||
>
|
||||
<SquareCheckBig className="size-3.5" strokeWidth={2.5} />
|
||||
Bookmark a roadmap
|
||||
</a>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div className="container min-h-full">
|
||||
{!isLoading && progress?.length == 0 && <EmptyProgress />}
|
||||
{hasProgress && (
|
||||
<HeroRoadmaps
|
||||
teamRoadmaps={teamRoadmaps}
|
||||
customRoadmaps={customRoadmaps}
|
||||
progress={defaultRoadmaps}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{progress.map((resource) => (
|
||||
<HeroRoadmap
|
||||
key={`${resource.resourceType}-${resource.resourceId}`}
|
||||
resourceId={resource.resourceId}
|
||||
resourceType={resource.resourceType}
|
||||
resourceTitle={resource.resourceTitle}
|
||||
isFavorite={resource.isFavorite}
|
||||
percentageDone={
|
||||
((resource.skipped + resource.done) / resource.total) * 100
|
||||
}
|
||||
url={
|
||||
resource.resourceType === 'roadmap'
|
||||
? `/${resource.resourceId}`
|
||||
: `/best-practices/${resource.resourceId}`
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</HeroItemsGroup>
|
||||
|
||||
<HeroItemsGroup
|
||||
icon={<MapIcon className="mr-1.5 h-[14px] w-[14px]" />}
|
||||
isLoading={isLoading}
|
||||
title="Your custom roadmaps"
|
||||
isEmpty={!isLoading && customRoadmaps.length === 0}
|
||||
emptyTitle={
|
||||
<>
|
||||
No custom roadmaps found
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsCreatingCustomRoadmap(true);
|
||||
}}
|
||||
className="ml-1.5 inline-flex items-center gap-1 font-medium text-blue-500 underline-offset-2 hover:underline"
|
||||
>
|
||||
<SquareCheckBig className="size-3.5" strokeWidth={2.5} />
|
||||
Create custom roadmap
|
||||
</button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{customRoadmaps.map((customRoadmap) => (
|
||||
<HeroRoadmap
|
||||
key={customRoadmap.resourceId}
|
||||
resourceId={customRoadmap.resourceId}
|
||||
resourceType={'roadmap'}
|
||||
resourceTitle={customRoadmap.resourceTitle}
|
||||
percentageDone={
|
||||
((customRoadmap.skipped + customRoadmap.done) /
|
||||
customRoadmap.total) *
|
||||
100
|
||||
}
|
||||
url={`/r/${customRoadmap?.roadmapSlug}`}
|
||||
allowFavorite={false}
|
||||
/>
|
||||
))}
|
||||
<CreateRoadmapButton />
|
||||
</HeroItemsGroup>
|
||||
|
||||
<HeroItemsGroup
|
||||
icon={<Sparkle className="mr-1.5 h-[14px] w-[14px]" />}
|
||||
isLoading={isLoading}
|
||||
title="Your AI roadmaps"
|
||||
isEmpty={!isLoading && aiRoadmaps.length === 0}
|
||||
emptyTitle={
|
||||
<>
|
||||
No AI roadmaps found
|
||||
<a
|
||||
href="/ai"
|
||||
className="ml-1.5 inline-flex items-center gap-1 font-medium text-blue-500 underline-offset-2 hover:underline"
|
||||
>
|
||||
<SquareCheckBig className="size-3.5" strokeWidth={2.5} />
|
||||
Generate AI roadmap
|
||||
</a>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{aiRoadmaps.map((aiRoadmap) => (
|
||||
<HeroRoadmap
|
||||
key={aiRoadmap.id}
|
||||
resourceId={aiRoadmap.id}
|
||||
resourceType={'roadmap'}
|
||||
resourceTitle={aiRoadmap.title}
|
||||
url={`/ai/${aiRoadmap.slug}`}
|
||||
percentageDone={0}
|
||||
allowFavorite={false}
|
||||
isTrackable={false}
|
||||
/>
|
||||
))}
|
||||
|
||||
<a
|
||||
href="/ai"
|
||||
className={
|
||||
'flex h-full w-full items-center justify-center gap-1 overflow-hidden rounded-md border border-dashed border-gray-800 p-3 text-sm text-gray-400 hover:border-gray-600 hover:bg-gray-900 hover:text-gray-300'
|
||||
}
|
||||
>
|
||||
<Plus size={16} />
|
||||
Generate New
|
||||
</a>
|
||||
</HeroItemsGroup>
|
||||
|
||||
<HeroItemsGroup
|
||||
icon={<FolderKanban className="mr-1.5 h-[14px] w-[14px]" />}
|
||||
isLoading={isLoading}
|
||||
title="Your active projects"
|
||||
isEmpty={!isLoading && projectsToShow.length === 0}
|
||||
emptyTitle={
|
||||
<>
|
||||
No active projects found
|
||||
<a
|
||||
href="/projects"
|
||||
className="ml-1.5 inline-flex items-center gap-1 font-medium text-blue-500 underline-offset-2 hover:underline"
|
||||
>
|
||||
<SquareCheckBig className="size-3.5" strokeWidth={2.5} />
|
||||
Start a new project
|
||||
</a>
|
||||
</>
|
||||
}
|
||||
rightContent={
|
||||
completedProjects.length > 0 && (
|
||||
<button
|
||||
onClick={() => setShowCompleted(!showCompleted)}
|
||||
className="hidden items-center gap-2 rounded-md text-xs text-slate-400 hover:text-slate-300 sm:flex"
|
||||
>
|
||||
{showCompleted ? (
|
||||
<EyeOff className="h-3.5 w-3.5" />
|
||||
) : (
|
||||
<Eye className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{completedProjects.length} Completed
|
||||
</button>
|
||||
)
|
||||
}
|
||||
className="border-b-0"
|
||||
>
|
||||
{projectsToShow.map((project) => (
|
||||
<HeroProject key={project._id} project={project} />
|
||||
))}
|
||||
|
||||
<a
|
||||
href="/projects"
|
||||
className="flex min-h-[80px] items-center justify-center gap-2 rounded-md border border-dashed border-slate-800 p-4 text-sm text-slate-400 hover:border-slate-600 hover:bg-slate-900/50 hover:text-slate-300"
|
||||
>
|
||||
<Plus size={16} />
|
||||
Start a new project
|
||||
</a>
|
||||
</HeroItemsGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
78
src/components/HeroSection/HeroItemsGroup.tsx
Normal file
78
src/components/HeroSection/HeroItemsGroup.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import { useEffect, useRef, useState, type ReactNode } from 'react';
|
||||
import { cn } from '../../lib/classname';
|
||||
import { HeroTitle } from './HeroTitle';
|
||||
|
||||
type HeroItemsGroupProps = {
|
||||
icon: any;
|
||||
isLoading?: boolean;
|
||||
isEmpty?: boolean;
|
||||
emptyTitle?: ReactNode;
|
||||
title: string | ReactNode;
|
||||
rightContent?: ReactNode;
|
||||
children?: ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function HeroItemsGroup(props: HeroItemsGroupProps) {
|
||||
const {
|
||||
icon,
|
||||
isLoading = false,
|
||||
isEmpty = false,
|
||||
emptyTitle,
|
||||
title,
|
||||
rightContent,
|
||||
children,
|
||||
className,
|
||||
} = props;
|
||||
|
||||
const storageKey = `hero-group-${title}-collapsed`;
|
||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
||||
|
||||
function isCollapsedByStorage() {
|
||||
const stored = localStorage.getItem(storageKey);
|
||||
|
||||
return stored === 'true';
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setIsCollapsed(isCollapsedByStorage());
|
||||
}, [isLoading]);
|
||||
|
||||
const isLoadingOrCollapsedOrEmpty = isLoading || isCollapsed || isEmpty;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'border-b border-gray-800/50',
|
||||
{
|
||||
'py-4': !isLoadingOrCollapsedOrEmpty,
|
||||
'py-4 ': isLoadingOrCollapsedOrEmpty,
|
||||
'opacity-50 transition-opacity hover:opacity-100':
|
||||
isCollapsed && !isLoading,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="container">
|
||||
<HeroTitle
|
||||
icon={icon}
|
||||
isLoading={isLoading}
|
||||
isEmpty={isEmpty}
|
||||
emptyTitle={emptyTitle}
|
||||
title={title}
|
||||
rightContent={rightContent}
|
||||
isCollapsed={isCollapsed}
|
||||
onToggleCollapse={() => {
|
||||
setIsCollapsed(!isCollapsed);
|
||||
localStorage.setItem(storageKey, (!isCollapsed).toString());
|
||||
}}
|
||||
/>
|
||||
{!isLoadingOrCollapsedOrEmpty && (
|
||||
<div className="mt-4 grid grid-cols-1 gap-2.5 sm:grid-cols-2 md:grid-cols-3">
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
52
src/components/HeroSection/HeroProject.tsx
Normal file
52
src/components/HeroSection/HeroProject.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { ThumbsUp } from 'lucide-react';
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
import { getRelativeTimeString } from '../../lib/date';
|
||||
import type { ProjectStatusDocument } from '../Projects/ListProjectSolutions.tsx';
|
||||
|
||||
type HeroProjectProps = {
|
||||
project: ProjectStatusDocument & {
|
||||
title: string;
|
||||
};
|
||||
};
|
||||
|
||||
export function HeroProject({ project }: HeroProjectProps) {
|
||||
return (
|
||||
<a
|
||||
href={`/projects/${project.projectId}`}
|
||||
className="group relative flex flex-col justify-between gap-2 rounded-md border border-slate-800 bg-slate-900 p-3.5 hover:border-slate-600"
|
||||
>
|
||||
<div className="relative z-10 flex items-start justify-between gap-2">
|
||||
<h3 className="truncate font-medium text-slate-300 group-hover:text-slate-100">
|
||||
{project.title}
|
||||
</h3>
|
||||
<span
|
||||
className={cn(
|
||||
'absolute -right-2 -top-2 flex flex-shrink-0 items-center gap-1 rounded-full text-xs uppercase tracking-wide',
|
||||
{
|
||||
'text-green-600/50': project.submittedAt && project.repositoryUrl,
|
||||
'text-yellow-600': !project.submittedAt || !project.repositoryUrl,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{project.submittedAt && project.repositoryUrl ? 'Done' : ''}
|
||||
</span>
|
||||
</div>
|
||||
<div className="relative z-10 flex items-center gap-2 text-xs text-slate-400">
|
||||
{project.submittedAt && project.repositoryUrl && (
|
||||
<span className="flex items-center gap-1">
|
||||
<ThumbsUp className="h-3 w-3" />
|
||||
{project.upvotes}
|
||||
</span>
|
||||
)}
|
||||
{project.startedAt && (
|
||||
<span>Started {getRelativeTimeString(project.startedAt)}</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="absolute inset-0 rounded-md bg-gradient-to-br from-slate-800/50 via-transparent to-transparent" />
|
||||
{project.submittedAt && project.repositoryUrl && (
|
||||
<div className="absolute inset-0 rounded-md bg-gradient-to-br from-green-950/20 via-transparent to-transparent" />
|
||||
)}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
74
src/components/HeroSection/HeroRoadmap.tsx
Normal file
74
src/components/HeroSection/HeroRoadmap.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
import type { ResourceType } from '../../lib/resource-progress.ts';
|
||||
import { MarkFavorite } from '../FeaturedItems/MarkFavorite.tsx';
|
||||
|
||||
type ProgressRoadmapProps = {
|
||||
url: string;
|
||||
percentageDone: number;
|
||||
allowFavorite?: boolean;
|
||||
|
||||
resourceId: string;
|
||||
resourceType: ResourceType;
|
||||
resourceTitle: string;
|
||||
isFavorite?: boolean;
|
||||
|
||||
isTrackable?: boolean;
|
||||
isNew?: boolean;
|
||||
};
|
||||
|
||||
export function HeroRoadmap(props: ProgressRoadmapProps) {
|
||||
const {
|
||||
url,
|
||||
percentageDone,
|
||||
resourceType,
|
||||
resourceId,
|
||||
resourceTitle,
|
||||
isFavorite,
|
||||
allowFavorite = true,
|
||||
isTrackable = true,
|
||||
isNew = false,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<a
|
||||
href={url}
|
||||
className={cn(
|
||||
'relative flex flex-col overflow-hidden rounded-md border p-3 text-sm text-slate-400 hover:text-slate-300',
|
||||
{
|
||||
'border-slate-800 bg-slate-900 hover:border-slate-600': isTrackable,
|
||||
'border-slate-700/50 bg-slate-800/50 hover:border-slate-600/70':
|
||||
!isTrackable,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<span title={resourceTitle} className="relative z-20 truncate">
|
||||
{resourceTitle}
|
||||
</span>
|
||||
|
||||
{isTrackable && (
|
||||
<span
|
||||
className="absolute bottom-0 left-0 top-0 z-10 bg-[#172a3a]"
|
||||
style={{ width: `${percentageDone}%` }}
|
||||
></span>
|
||||
)}
|
||||
|
||||
{allowFavorite && (
|
||||
<MarkFavorite
|
||||
resourceId={resourceId}
|
||||
resourceType={resourceType}
|
||||
favorite={isFavorite}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isNew && (
|
||||
<span className="absolute bottom-1.5 right-2 flex items-center rounded-br rounded-tl text-xs font-medium text-purple-300">
|
||||
<span className="mr-1.5 flex h-2 w-2">
|
||||
<span className="absolute inline-flex h-2 w-2 animate-ping rounded-full bg-purple-400 opacity-75" />
|
||||
<span className="relative inline-flex h-2 w-2 rounded-full bg-purple-500" />
|
||||
</span>
|
||||
New
|
||||
</span>
|
||||
)}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -1,264 +0,0 @@
|
||||
import type { UserProgressResponse } from './FavoriteRoadmaps';
|
||||
import { CheckIcon } from '../ReactIcons/CheckIcon';
|
||||
import { MarkFavorite } from '../FeaturedItems/MarkFavorite';
|
||||
import { Spinner } from '../ReactIcons/Spinner';
|
||||
import type { ResourceType } from '../../lib/resource-progress';
|
||||
import { MapIcon, Users2 } from 'lucide-react';
|
||||
import { CreateRoadmapButton } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapButton';
|
||||
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
|
||||
import { type ReactNode, useState } from 'react';
|
||||
import { FeatureAnnouncement } from '../FeatureAnnouncement.tsx';
|
||||
|
||||
type ProgressRoadmapProps = {
|
||||
url: string;
|
||||
percentageDone: number;
|
||||
allowFavorite?: boolean;
|
||||
|
||||
resourceId: string;
|
||||
resourceType: ResourceType;
|
||||
resourceTitle: string;
|
||||
isFavorite?: boolean;
|
||||
};
|
||||
function HeroRoadmap(props: ProgressRoadmapProps) {
|
||||
const {
|
||||
url,
|
||||
percentageDone,
|
||||
resourceType,
|
||||
resourceId,
|
||||
resourceTitle,
|
||||
isFavorite,
|
||||
allowFavorite = true,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<a
|
||||
href={url}
|
||||
className="relative flex flex-col overflow-hidden rounded-md border border-slate-800 bg-slate-900 p-3 text-sm text-slate-400 hover:border-slate-600 hover:text-slate-300"
|
||||
>
|
||||
<span className="relative z-20">{resourceTitle}</span>
|
||||
|
||||
<span
|
||||
className="absolute bottom-0 left-0 top-0 z-10 bg-[#172a3a]"
|
||||
style={{ width: `${percentageDone}%` }}
|
||||
></span>
|
||||
|
||||
{allowFavorite && (
|
||||
<MarkFavorite
|
||||
resourceId={resourceId}
|
||||
resourceType={resourceType}
|
||||
favorite={isFavorite}
|
||||
/>
|
||||
)}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
type ProgressTitleProps = {
|
||||
icon: any;
|
||||
isLoading?: boolean;
|
||||
title: string | ReactNode;
|
||||
};
|
||||
|
||||
export function HeroTitle(props: ProgressTitleProps) {
|
||||
const { isLoading = false, title, icon } = props;
|
||||
|
||||
return (
|
||||
<p className="mb-4 flex items-center text-sm text-gray-400">
|
||||
{!isLoading && icon}
|
||||
{isLoading && (
|
||||
<span className="mr-1.5">
|
||||
<Spinner />
|
||||
</span>
|
||||
)}
|
||||
{title}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
export type HeroTeamRoadmaps = Record<string, UserProgressResponse>;
|
||||
|
||||
type ProgressListProps = {
|
||||
progress: UserProgressResponse;
|
||||
customRoadmaps: UserProgressResponse;
|
||||
teamRoadmaps?: HeroTeamRoadmaps;
|
||||
isLoading?: boolean;
|
||||
};
|
||||
|
||||
export function HeroRoadmaps(props: ProgressListProps) {
|
||||
const {
|
||||
teamRoadmaps = {},
|
||||
progress,
|
||||
isLoading = false,
|
||||
customRoadmaps,
|
||||
} = props;
|
||||
|
||||
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
|
||||
const [creatingRoadmapTeamId, setCreatingRoadmapTeamId] = useState<string>();
|
||||
|
||||
return (
|
||||
<div className="relative pb-12 pt-4 sm:pt-7">
|
||||
<p className="mb-7 mt-2 text-sm">
|
||||
<FeatureAnnouncement />
|
||||
</p>
|
||||
{isCreatingRoadmap && (
|
||||
<CreateRoadmapModal
|
||||
teamId={creatingRoadmapTeamId}
|
||||
onClose={() => {
|
||||
setIsCreatingRoadmap(false);
|
||||
setCreatingRoadmapTeamId(undefined);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{
|
||||
<HeroTitle
|
||||
icon={
|
||||
(<CheckIcon additionalClasses="mr-1.5 h-[14px] w-[14px]" />) as any
|
||||
}
|
||||
isLoading={isLoading}
|
||||
title="Your progress and favorite roadmaps."
|
||||
/>
|
||||
}
|
||||
|
||||
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3">
|
||||
{progress.map((resource) => (
|
||||
<HeroRoadmap
|
||||
key={`${resource.resourceType}-${resource.resourceId}`}
|
||||
resourceId={resource.resourceId}
|
||||
resourceType={resource.resourceType}
|
||||
resourceTitle={resource.resourceTitle}
|
||||
isFavorite={resource.isFavorite}
|
||||
percentageDone={
|
||||
((resource.skipped + resource.done) / resource.total) * 100
|
||||
}
|
||||
url={
|
||||
resource.resourceType === 'roadmap'
|
||||
? `/${resource.resourceId}`
|
||||
: `/best-practices/${resource.resourceId}`
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-5">
|
||||
{
|
||||
<HeroTitle
|
||||
icon={<MapIcon className="mr-1.5 h-[14px] w-[14px]" />}
|
||||
title="Your custom roadmaps"
|
||||
/>
|
||||
}
|
||||
|
||||
{customRoadmaps.length === 0 && (
|
||||
<p className="rounded-md border border-dashed border-gray-800 p-2 text-sm text-gray-600">
|
||||
You haven't created any custom roadmaps yet.{' '}
|
||||
<button
|
||||
className="text-gray-500 underline underline-offset-2 hover:text-gray-400"
|
||||
onClick={() => setIsCreatingRoadmap(true)}
|
||||
>
|
||||
Create one!
|
||||
</button>
|
||||
</p>
|
||||
)}
|
||||
|
||||
{customRoadmaps.length > 0 && (
|
||||
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3">
|
||||
{customRoadmaps.map((customRoadmap) => {
|
||||
return (
|
||||
<HeroRoadmap
|
||||
key={customRoadmap.resourceId}
|
||||
resourceId={customRoadmap.resourceId}
|
||||
resourceType={'roadmap'}
|
||||
resourceTitle={customRoadmap.resourceTitle}
|
||||
percentageDone={
|
||||
((customRoadmap.skipped + customRoadmap.done) /
|
||||
customRoadmap.total) *
|
||||
100
|
||||
}
|
||||
url={`/r/${customRoadmap?.roadmapSlug}`}
|
||||
allowFavorite={false}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
<CreateRoadmapButton />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{Object.keys(teamRoadmaps).map((teamName) => {
|
||||
const currentTeam: UserProgressResponse[0]['team'] =
|
||||
teamRoadmaps?.[teamName]?.[0]?.team;
|
||||
const roadmapsList = teamRoadmaps[teamName].filter(
|
||||
(roadmap) => !!roadmap.resourceTitle,
|
||||
);
|
||||
const canManageTeam = ['admin', 'manager'].includes(currentTeam?.role!);
|
||||
|
||||
return (
|
||||
<div className="mt-5" key={teamName}>
|
||||
{
|
||||
<HeroTitle
|
||||
icon={<Users2 className="mr-1.5 h-[14px] w-[14px]" />}
|
||||
title={
|
||||
<>
|
||||
Team{' '}
|
||||
<a
|
||||
className="mx-1 font-medium underline underline-offset-2 transition-colors hover:text-gray-300"
|
||||
href={`/team/activity?t=${currentTeam?.id}`}
|
||||
>
|
||||
{teamName}
|
||||
</a>
|
||||
Roadmaps
|
||||
</>
|
||||
}
|
||||
/>
|
||||
}
|
||||
|
||||
{roadmapsList.length === 0 && (
|
||||
<p className="rounded-md border border-dashed border-gray-800 p-2 text-sm text-gray-600">
|
||||
Team does not have any roadmaps yet.{' '}
|
||||
{canManageTeam && (
|
||||
<button
|
||||
className="text-gray-500 underline underline-offset-2 hover:text-gray-400"
|
||||
onClick={() => {
|
||||
setCreatingRoadmapTeamId(currentTeam?.id);
|
||||
setIsCreatingRoadmap(true);
|
||||
}}
|
||||
>
|
||||
Create one!
|
||||
</button>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{roadmapsList.length > 0 && (
|
||||
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3">
|
||||
{roadmapsList.map((customRoadmap) => {
|
||||
return (
|
||||
<HeroRoadmap
|
||||
key={customRoadmap.resourceId}
|
||||
resourceId={customRoadmap.resourceId}
|
||||
resourceType={'roadmap'}
|
||||
resourceTitle={customRoadmap.resourceTitle}
|
||||
percentageDone={
|
||||
((customRoadmap.skipped + customRoadmap.done) /
|
||||
customRoadmap.total) *
|
||||
100
|
||||
}
|
||||
url={`/r/${customRoadmap?.roadmapSlug}`}
|
||||
allowFavorite={false}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{canManageTeam && (
|
||||
<CreateRoadmapButton
|
||||
teamId={currentTeam?.id}
|
||||
text="Create Team Roadmap"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
71
src/components/HeroSection/HeroTitle.tsx
Normal file
71
src/components/HeroSection/HeroTitle.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { Spinner } from '../ReactIcons/Spinner.tsx';
|
||||
import { ChevronDown, ChevronsDownUp, ChevronsUpDown } from 'lucide-react';
|
||||
import { cn } from '../../lib/classname.ts';
|
||||
|
||||
type HeroTitleProps = {
|
||||
icon: any;
|
||||
isLoading?: boolean;
|
||||
title: string | ReactNode;
|
||||
rightContent?: ReactNode;
|
||||
isCollapsed?: boolean;
|
||||
onToggleCollapse?: () => void;
|
||||
isEmpty?: boolean;
|
||||
emptyTitle?: ReactNode;
|
||||
};
|
||||
|
||||
export function HeroTitle(props: HeroTitleProps) {
|
||||
const {
|
||||
isLoading = false,
|
||||
title,
|
||||
icon,
|
||||
rightContent,
|
||||
isCollapsed = false,
|
||||
onToggleCollapse,
|
||||
isEmpty = false,
|
||||
emptyTitle,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<p className="flex items-center gap-0.5 text-sm text-gray-400">
|
||||
{!isLoading && icon}
|
||||
{isLoading && (
|
||||
<span className="mr-1.5">
|
||||
<Spinner />
|
||||
</span>
|
||||
)}
|
||||
{!isEmpty ? title : emptyTitle || title}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{!isCollapsed && rightContent}
|
||||
|
||||
{!isLoading && !isEmpty && (
|
||||
<button
|
||||
onClick={onToggleCollapse}
|
||||
className={cn(
|
||||
'ml-2 inline-flex items-center gap-1 rounded-md bg-slate-800 py-0.5 pl-1 pr-1.5 text-xs uppercase tracking-wider text-slate-400 hover:bg-slate-700',
|
||||
{
|
||||
'bg-slate-800 text-slate-500 hover:bg-slate-800 hover:text-slate-400':
|
||||
!isCollapsed,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{isCollapsed && (
|
||||
<>
|
||||
<ChevronsUpDown className="h-3.5 w-3.5" /> Expand
|
||||
</>
|
||||
)}
|
||||
{!isCollapsed && (
|
||||
<>
|
||||
<ChevronsDownUp className="h-3.5 w-3.5" /> Collapse
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -8,7 +8,7 @@ const { class: className } = Astro.props;
|
||||
|
||||
<div
|
||||
class:list={[
|
||||
'container prose prose-xl prose-h2:mb-3 prose-h2:mt-10 prose-h2:scroll-mt-5 prose-h2:text-balance prose-h2:text-3xl prose-h3:mt-2 prose-h3:scroll-mt-5 prose-h3:text-balance prose-h4:text-balance prose-h5:text-balance prose-h5:font-medium prose-blockquote:font-normal prose-code:bg-transparent prose-img:mt-1 prose-h2:sm:scroll-mt-10 prose-h3:sm:scroll-mt-10',
|
||||
'container prose prose-xl prose-h2:mb-3 prose-h2:mt-10 prose-h2:scroll-mt-5 prose-h2:text-balance prose-h2:text-3xl prose-h3:mt-2 prose-h4:text-2xl prose-h3:scroll-mt-5 prose-h3:text-balance prose-h4:text-balance prose-h5:text-balance prose-h5:font-medium prose-blockquote:font-normal prose-code:bg-transparent prose-img:mt-1 prose-h2:sm:scroll-mt-10 prose-h3:sm:scroll-mt-10',
|
||||
className,
|
||||
]}
|
||||
>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
---
|
||||
import { Menu } from 'lucide-react';
|
||||
import { AccountStreak } from '../AccountStreak/AccountStreak';
|
||||
import Icon from '../AstroIcon.astro';
|
||||
import { NavigationDropdown } from '../NavigationDropdown';
|
||||
import { AccountDropdown } from './AccountDropdown';
|
||||
import NewIndicator from './NewIndicator.astro';
|
||||
import { AccountStreak } from '../AccountStreak/AccountStreak';
|
||||
import { RoadmapDropdownMenu } from '../RoadmapDropdownMenu/RoadmapDropdownMenu';
|
||||
import { AccountDropdown } from './AccountDropdown';
|
||||
import { CourseAnnouncement } from '../SQLCourse/CourseAnnouncement';
|
||||
---
|
||||
|
||||
<CourseAnnouncement client:load />
|
||||
|
||||
<div class='bg-slate-900 py-5 text-white sm:py-8'>
|
||||
<nav class='container flex items-center justify-between'>
|
||||
<div class='flex items-center gap-5'>
|
||||
@@ -48,7 +49,7 @@ import { RoadmapDropdownMenu } from '../RoadmapDropdownMenu/RoadmapDropdownMenu'
|
||||
</a>
|
||||
<a
|
||||
href='/changelog'
|
||||
class='group relative text-blue-300 hover:text-white hidden md:block ml-0.5'
|
||||
class='group relative ml-0.5 hidden text-blue-300 hover:text-white md:block'
|
||||
>
|
||||
Changelog
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME, removeAuthToken } from '../../lib/jwt';
|
||||
import { REDIRECT_PAGE_AFTER_AUTH } from '../Authenticator/authenticator.ts';
|
||||
|
||||
export function logout() {
|
||||
localStorage.removeItem(REDIRECT_PAGE_AFTER_AUTH);
|
||||
removeAuthToken();
|
||||
|
||||
// Reloading will automatically redirect the user if required
|
||||
window.location.reload();
|
||||
window.location.href = '/';
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
|
||||
@@ -109,7 +109,7 @@ export function NavigationDropdown() {
|
||||
</button>
|
||||
<div
|
||||
className={cn(
|
||||
'pointer-events-none invisible absolute left-0 top-full z-[999] mt-2 w-48 min-w-[320px] -translate-y-1 rounded-lg bg-slate-800 py-2 opacity-0 shadow-xl transition-all duration-100',
|
||||
'pointer-events-none invisible absolute left-0 top-full z-[90] mt-2 w-48 min-w-[320px] -translate-y-1 rounded-lg bg-slate-800 py-2 opacity-0 shadow-xl transition-all duration-100',
|
||||
{
|
||||
'pointer-events-auto visible translate-y-2.5 opacity-100':
|
||||
$navigationDropdownOpen,
|
||||
|
||||
@@ -37,6 +37,9 @@ export function OnboardingNudge(props: OnboardingNudgeProps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// @TODO put it back once <CourseAnnouncement /> is removed
|
||||
return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
|
||||
@@ -16,6 +16,8 @@ import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx';
|
||||
import { SelectLanguages } from './SelectLanguages.tsx';
|
||||
import type { ProjectFrontmatter } from '../../lib/project.ts';
|
||||
import { ProjectSolutionModal } from './ProjectSolutionModal.tsx';
|
||||
import { SortProjects } from './SortProjects.tsx';
|
||||
import { ProjectSolutionRow } from './ProjectSolutionRow';
|
||||
|
||||
export interface ProjectStatusDocument {
|
||||
_id?: string;
|
||||
@@ -57,11 +59,13 @@ type ListProjectSolutionsResponse = {
|
||||
type QueryParams = {
|
||||
p?: string;
|
||||
l?: string;
|
||||
s?: string;
|
||||
};
|
||||
|
||||
type PageState = {
|
||||
currentPage: number;
|
||||
language: string;
|
||||
sort: string;
|
||||
};
|
||||
|
||||
type ListProjectSolutionsProps = {
|
||||
@@ -69,30 +73,6 @@ type ListProjectSolutionsProps = {
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export const submittedAlternatives = [
|
||||
'submitted their solution',
|
||||
'got it done',
|
||||
'submitted their take',
|
||||
'finished the project',
|
||||
'submitted their work',
|
||||
'completed the project',
|
||||
'got it done',
|
||||
'delivered their project',
|
||||
'handed in their solution',
|
||||
'provided their deliverables',
|
||||
'submitted their approach',
|
||||
'sent in their project',
|
||||
'presented their take',
|
||||
'shared their completed task',
|
||||
'submitted their approach',
|
||||
'completed it',
|
||||
'finalized their solution',
|
||||
'delivered their approach',
|
||||
'turned in their project',
|
||||
'submitted their final draft',
|
||||
'delivered their solution',
|
||||
];
|
||||
|
||||
export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
const { projectId, project: projectData } = props;
|
||||
|
||||
@@ -100,6 +80,7 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
const [pageState, setPageState] = useState<PageState>({
|
||||
currentPage: 0,
|
||||
language: '',
|
||||
sort: 'rating',
|
||||
});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@@ -108,12 +89,17 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
ListProjectSolutionsResponse['data'][number] | null
|
||||
>(null);
|
||||
|
||||
const loadSolutions = async (page = 1, language: string = '') => {
|
||||
const loadSolutions = async (
|
||||
page = 1,
|
||||
language: string = '',
|
||||
sort: string = 'rating',
|
||||
) => {
|
||||
const { response, error } = await httpGet<ListProjectSolutionsResponse>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-list-project-solutions/${projectId}`,
|
||||
{
|
||||
currPage: page,
|
||||
...(language ? { languages: language } : {}),
|
||||
sort,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -178,6 +164,7 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
setPageState({
|
||||
currentPage: +(queryParams.p || '1'),
|
||||
language: queryParams.l || '',
|
||||
sort: queryParams.s || 'rating',
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -187,17 +174,27 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pageState.currentPage !== 1 || pageState.language !== '') {
|
||||
if (
|
||||
pageState.currentPage !== 1 ||
|
||||
pageState.language !== '' ||
|
||||
pageState.sort !== 'rating'
|
||||
) {
|
||||
setUrlParams({
|
||||
p: String(pageState.currentPage),
|
||||
l: pageState.language,
|
||||
s: pageState.sort,
|
||||
});
|
||||
} else {
|
||||
deleteUrlParam('p');
|
||||
deleteUrlParam('l');
|
||||
deleteUrlParam('s');
|
||||
}
|
||||
|
||||
loadSolutions(pageState.currentPage, pageState.language).finally(() => {
|
||||
loadSolutions(
|
||||
pageState.currentPage,
|
||||
pageState.language,
|
||||
pageState.sort,
|
||||
).finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, [pageState]);
|
||||
@@ -216,6 +213,13 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
|
||||
const selectedLanguage = pageState.language;
|
||||
|
||||
const setSelectedLanguage = (language: string) => {
|
||||
setPageState((prev) => ({
|
||||
...prev,
|
||||
language: prev.language === language ? '' : language,
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-4 overflow-hidden rounded-lg border bg-white p-3 sm:p-5">
|
||||
{leavingRoadmapModal}
|
||||
@@ -224,19 +228,32 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
<h1 className="mb-1 text-xl font-semibold">
|
||||
{projectData.title} Solutions
|
||||
</h1>
|
||||
<p className="text-sm text-gray-500">{projectData.description}</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
Solutions submitted by the community
|
||||
</p>
|
||||
</div>
|
||||
{!isLoading && (
|
||||
<SelectLanguages
|
||||
projectId={projectId}
|
||||
selectedLanguage={selectedLanguage}
|
||||
onSelectLanguage={(language) => {
|
||||
setPageState((prev) => ({
|
||||
...prev,
|
||||
language: prev.language === language ? '' : language,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
<div className="flex flex-shrink-0 items-center gap-2">
|
||||
<SortProjects
|
||||
selectedSort={pageState.sort}
|
||||
onSelectSort={(sort) => {
|
||||
setPageState((prev) => ({
|
||||
...prev,
|
||||
sort,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
<SelectLanguages
|
||||
projectId={projectId}
|
||||
selectedLanguage={selectedLanguage}
|
||||
onSelectLanguage={(language) => {
|
||||
setPageState((prev) => ({
|
||||
...prev,
|
||||
language: prev.language === language ? '' : language,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -245,73 +262,16 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
|
||||
) : (
|
||||
<>
|
||||
<div className="flex min-h-[500px] flex-col divide-y divide-gray-100">
|
||||
{solutions?.data.map((solution, counter) => {
|
||||
const avatar = solution.user.avatar || '';
|
||||
return (
|
||||
<div
|
||||
key={solution._id}
|
||||
className="flex flex-col gap-2 py-2 text-sm text-gray-500"
|
||||
>
|
||||
<div className="flex flex-col justify-between gap-2 text-sm text-gray-500 sm:flex-row sm:items-center sm:gap-0">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<img
|
||||
src={
|
||||
avatar
|
||||
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
|
||||
: '/images/default-avatar.png'
|
||||
}
|
||||
alt={solution.user.name}
|
||||
className="mr-0.5 h-7 w-7 rounded-full"
|
||||
/>
|
||||
<span className="font-medium text-black">
|
||||
{solution.user.name}
|
||||
</span>
|
||||
<span className="hidden sm:inline">
|
||||
{submittedAlternatives[
|
||||
counter % submittedAlternatives.length
|
||||
] || 'submitted their solution'}
|
||||
</span>{' '}
|
||||
<span className="flex-grow text-right text-gray-400 sm:flex-grow-0 sm:text-left sm:font-medium sm:text-black">
|
||||
{getRelativeTimeString(solution?.submittedAt!)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
<span className="flex shrink-0 overflow-hidden rounded-full border">
|
||||
<VoteButton
|
||||
icon={ThumbsUp}
|
||||
isActive={solution?.voteType === 'upvote'}
|
||||
count={solution.upvotes || 0}
|
||||
onClick={() => {
|
||||
handleSubmitVote(solution._id!, 'upvote');
|
||||
}}
|
||||
/>
|
||||
|
||||
<VoteButton
|
||||
icon={ThumbsDown}
|
||||
isActive={solution?.voteType === 'downvote'}
|
||||
count={solution.downvotes || 0}
|
||||
hideCount={true}
|
||||
onClick={() => {
|
||||
handleSubmitVote(solution._id!, 'downvote');
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<button
|
||||
className="ml-1 flex items-center gap-1 rounded-full border px-2 py-1 text-xs text-black transition-colors hover:border-black hover:bg-black hover:text-white"
|
||||
onClick={() => {
|
||||
setShowLeavingRoadmapModal(solution);
|
||||
}}
|
||||
>
|
||||
<GitHubIcon className="h-4 w-4 text-current" />
|
||||
Visit Solution
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{solutions?.data.map((solution, counter) => (
|
||||
<ProjectSolutionRow
|
||||
key={solution._id}
|
||||
solution={solution}
|
||||
counter={counter}
|
||||
onVote={handleSubmitVote}
|
||||
onVisitSolution={setShowLeavingRoadmapModal}
|
||||
onLanguageClick={setSelectedLanguage}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{(solutions?.totalPages || 0) > 1 && (
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import { ArrowUpRight, ThumbsDown, ThumbsUp } from 'lucide-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import { deleteUrlParam, getUrlParams } from '../../lib/browser';
|
||||
import { ModalLoader } from '../UserProgress/ModalLoader';
|
||||
import { Modal } from '../Modal';
|
||||
import { httpGet, httpPost } from '../../lib/http';
|
||||
import {
|
||||
submittedAlternatives,
|
||||
type AllowedVoteType,
|
||||
} from './ListProjectSolutions';
|
||||
import { getRelativeTimeString } from '../../lib/date';
|
||||
import { ArrowUpRight, ThumbsDown, ThumbsUp, Trophy } from 'lucide-react';
|
||||
import { VoteButton } from './VoteButton';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon';
|
||||
import { httpGet, httpPost } from '../../lib/http';
|
||||
import { isLoggedIn } from '../../lib/jwt';
|
||||
import { showLoginPopup } from '../../lib/popup';
|
||||
import { pageProgressMessage } from '../../stores/page';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import { Modal } from '../Modal';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon';
|
||||
import { ModalLoader } from '../UserProgress/ModalLoader';
|
||||
import { type AllowedVoteType } from './ListProjectSolutions';
|
||||
import { VoteButton } from './VoteButton';
|
||||
|
||||
type UserProjectSolutionResponse = {
|
||||
id?: string;
|
||||
@@ -135,8 +132,12 @@ export function ProjectSolutionModal(props: ProjectSolutionModalProps) {
|
||||
bodyClassName={'h-auto'}
|
||||
>
|
||||
<div className="relative p-6">
|
||||
<h1 className="text-2xl text-balance mb-1 font-bold text-gray-900">{projectTitle}</h1>
|
||||
<p className="text-sm text-balance text-gray-600">{projectDescription}</p>
|
||||
<h1 className="mb-1 text-balance text-2xl font-bold text-gray-900">
|
||||
{projectTitle}
|
||||
</h1>
|
||||
<p className="text-balance text-sm text-gray-600">
|
||||
{projectDescription}
|
||||
</p>
|
||||
|
||||
<div className="my-5 rounded-lg bg-gray-100 p-4">
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -150,7 +151,9 @@ export function ProjectSolutionModal(props: ProjectSolutionModalProps) {
|
||||
className="h-12 w-12 rounded-full border-2 border-white shadow-md"
|
||||
/>
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-900">{solution?.user.name}'s Solution</h2>
|
||||
<h2 className="text-lg font-semibold text-gray-900">
|
||||
{solution?.user.name}'s Solution
|
||||
</h2>
|
||||
<p className="text-sm text-gray-600">
|
||||
Submitted their solution{' '}
|
||||
{getRelativeTimeString(solution?.submittedAt!)}
|
||||
|
||||
137
src/components/Projects/ProjectSolutionRow.tsx
Normal file
137
src/components/Projects/ProjectSolutionRow.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { ThumbsDown, ThumbsUp } from 'lucide-react';
|
||||
import { getRelativeTimeString } from '../../lib/date';
|
||||
import { VoteButton } from './VoteButton';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon';
|
||||
import type {
|
||||
AllowedVoteType,
|
||||
ProjectStatusDocument,
|
||||
} from './ListProjectSolutions';
|
||||
|
||||
export const submittedAlternatives = [
|
||||
'submitted their solution',
|
||||
'got it done',
|
||||
'submitted their take',
|
||||
'finished the project',
|
||||
'submitted their work',
|
||||
'completed the project',
|
||||
'got it done',
|
||||
'delivered their project',
|
||||
'handed in their solution',
|
||||
'provided their deliverables',
|
||||
'submitted their approach',
|
||||
'sent in their project',
|
||||
'presented their take',
|
||||
'shared their completed task',
|
||||
'submitted their approach',
|
||||
'completed it',
|
||||
'finalized their solution',
|
||||
'delivered their approach',
|
||||
'turned in their project',
|
||||
'submitted their final draft',
|
||||
'delivered their solution',
|
||||
];
|
||||
|
||||
type ProjectSolutionRowProps = {
|
||||
solution: ProjectStatusDocument & {
|
||||
user: {
|
||||
id: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
};
|
||||
voteType?: AllowedVoteType | 'none';
|
||||
};
|
||||
counter: number;
|
||||
onVote: (solutionId: string, voteType: AllowedVoteType) => void;
|
||||
onVisitSolution: (solution: ProjectSolutionRowProps['solution']) => void;
|
||||
onLanguageClick?: (language: string) => void;
|
||||
};
|
||||
|
||||
export function ProjectSolutionRow(props: ProjectSolutionRowProps) {
|
||||
const { solution, counter, onVote, onVisitSolution, onLanguageClick } = props;
|
||||
|
||||
const avatar = solution.user.avatar || '';
|
||||
|
||||
return (
|
||||
<div className="group flex flex-col border-gray-100 px-3 py-2.5 text-sm hover:bg-gray-50/50 sm:flex-row sm:justify-between">
|
||||
<div className="flex min-w-0 items-start gap-3">
|
||||
<img
|
||||
src={
|
||||
avatar
|
||||
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
|
||||
: '/images/default-avatar.png'
|
||||
}
|
||||
alt={solution.user.name}
|
||||
className="h-7 w-7 flex-shrink-0 rounded-full sm:h-8 sm:w-8"
|
||||
/>
|
||||
<div className="min-w-0 flex-auto">
|
||||
<div className="flex flex-wrap items-baseline gap-x-1.5 gap-y-0.5">
|
||||
<span className="max-w-[150px] truncate font-medium text-gray-900 sm:max-w-[180px]">
|
||||
{solution.user.name}
|
||||
</span>
|
||||
<span className="hidden truncate text-xs text-gray-500 sm:block sm:text-sm">
|
||||
{submittedAlternatives[counter % submittedAlternatives.length] ||
|
||||
'submitted their solution'}
|
||||
</span>
|
||||
<span
|
||||
className="text-xs text-gray-400"
|
||||
title={new Date(solution?.submittedAt!).toLocaleString()}
|
||||
>
|
||||
· {getRelativeTimeString(solution?.submittedAt!)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mt-2.5 flex gap-1.5">
|
||||
<div className="flex gap-1">
|
||||
<span className="flex shrink-0 overflow-hidden rounded-full border">
|
||||
<VoteButton
|
||||
icon={ThumbsUp}
|
||||
isActive={solution?.voteType === 'upvote'}
|
||||
count={solution.upvotes || 0}
|
||||
onClick={() => {
|
||||
onVote(solution._id!, 'upvote');
|
||||
}}
|
||||
/>
|
||||
|
||||
<VoteButton
|
||||
icon={ThumbsDown}
|
||||
isActive={solution?.voteType === 'downvote'}
|
||||
count={solution.downvotes || 0}
|
||||
hideCount={true}
|
||||
onClick={() => {
|
||||
onVote(solution._id!, 'downvote');
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="flex items-center gap-1 rounded-full border px-2 py-1 text-xs text-black transition-colors hover:border-black hover:bg-black hover:text-white"
|
||||
onClick={() => {
|
||||
onVisitSolution(solution);
|
||||
}}
|
||||
>
|
||||
<GitHubIcon className="h-3.5 w-3.5 text-current" />
|
||||
<span>Visit Solution</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-2.5 hidden sm:mt-0 sm:block sm:pl-4">
|
||||
{solution.languages && solution.languages.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
{solution.languages.slice(0, 2).map((lang) => (
|
||||
<button
|
||||
key={lang}
|
||||
onClick={() => onLanguageClick?.(lang)}
|
||||
className="inline-flex items-center rounded-md border border-gray-200 bg-white px-2 py-0.5 text-xs font-medium text-gray-700 transition-colors hover:border-gray-300 hover:bg-gray-50 hover:text-gray-900"
|
||||
>
|
||||
{lang}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react';
|
||||
import { useOutsideClick } from '../../hooks/use-outside-click';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import { ChevronDown, X } from 'lucide-react';
|
||||
import { ChevronDown, Search, X } from 'lucide-react';
|
||||
|
||||
type SelectLanguagesProps = {
|
||||
projectId: string;
|
||||
@@ -14,10 +14,44 @@ export function SelectLanguages(props: SelectLanguagesProps) {
|
||||
const { projectId, onSelectLanguage, selectedLanguage } = props;
|
||||
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||
const optionsRef = useRef<HTMLDivElement>(null);
|
||||
const toast = useToast();
|
||||
|
||||
const [distinctLanguages, setDistinctLanguages] = useState<string[]>([]);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [highlightedIndex, setHighlightedIndex] = useState(0);
|
||||
|
||||
const filteredLanguages = distinctLanguages.filter((language) =>
|
||||
language.toLowerCase().includes(searchQuery.toLowerCase()),
|
||||
);
|
||||
|
||||
// Handle scrolling of highlighted option into view
|
||||
useEffect(() => {
|
||||
if (!isOpen || !optionsRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = optionsRef.current.getElementsByTagName('button');
|
||||
const highlightedOption = options[highlightedIndex];
|
||||
if (!highlightedOption) {
|
||||
return;
|
||||
}
|
||||
|
||||
const containerRect = optionsRef.current.getBoundingClientRect();
|
||||
const optionRect = highlightedOption.getBoundingClientRect();
|
||||
|
||||
const isAbove = optionRect.top < containerRect.top;
|
||||
const isBelow = optionRect.bottom > containerRect.bottom;
|
||||
|
||||
if (isAbove || isBelow) {
|
||||
highlightedOption.scrollIntoView({
|
||||
block: 'nearest',
|
||||
behavior: 'instant',
|
||||
});
|
||||
}
|
||||
}, [highlightedIndex, isOpen]);
|
||||
|
||||
const loadDistinctLanguages = async () => {
|
||||
const { response, error } = await httpGet<string[]>(
|
||||
@@ -34,53 +68,124 @@ export function SelectLanguages(props: SelectLanguagesProps) {
|
||||
|
||||
useOutsideClick(dropdownRef, () => {
|
||||
setIsOpen(false);
|
||||
setSearchQuery('');
|
||||
setHighlightedIndex(0);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
loadDistinctLanguages().finally(() => {});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="relative flex">
|
||||
<button
|
||||
className="flex items-center gap-1 rounded-md border border-gray-300 py-1.5 pl-3 pr-2 text-xs font-medium text-gray-900"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
{selectedLanguage || 'Select Language'}
|
||||
useEffect(() => {
|
||||
if (isOpen && searchInputRef.current) {
|
||||
searchInputRef.current.focus();
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
<ChevronDown className="ml-1 h-4 w-4" />
|
||||
</button>
|
||||
{selectedLanguage && (
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
switch (e.key) {
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
setHighlightedIndex((prev) =>
|
||||
prev >= filteredLanguages.length - 1 ? 0 : prev + 1,
|
||||
);
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
setHighlightedIndex((prev) =>
|
||||
prev <= 0 ? filteredLanguages.length - 1 : prev - 1,
|
||||
);
|
||||
break;
|
||||
case 'Enter':
|
||||
e.preventDefault();
|
||||
if (filteredLanguages[highlightedIndex]) {
|
||||
onSelectLanguage(filteredLanguages[highlightedIndex]);
|
||||
setIsOpen(false);
|
||||
setSearchQuery('');
|
||||
setHighlightedIndex(0);
|
||||
}
|
||||
break;
|
||||
case 'Escape':
|
||||
setIsOpen(false);
|
||||
setSearchQuery('');
|
||||
setHighlightedIndex(0);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-shrink-0">
|
||||
<div className="relative">
|
||||
<button
|
||||
className="ml-1 text-red-500 text-xs border border-red-500 rounded-md px-2 py-1"
|
||||
onClick={() => onSelectLanguage('')}
|
||||
className="flex items-center gap-1 rounded-md border border-gray-300 py-1.5 pl-3 pr-2 text-xs font-medium text-gray-900"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
Clear
|
||||
{selectedLanguage || 'Select Language'}
|
||||
<ChevronDown className="ml-1 h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
{selectedLanguage && (
|
||||
<button
|
||||
className="absolute -right-1.5 -top-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onSelectLanguage('');
|
||||
}}
|
||||
>
|
||||
<X className="size-3" strokeWidth={2.5} />
|
||||
<span className="sr-only">Clear selection</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isOpen && (
|
||||
<div
|
||||
className="absolute right-0 top-full z-10 w-full min-w-[200px] max-w-[200px] translate-y-1.5 overflow-hidden rounded-md border border-gray-300 bg-white p-1 shadow-lg"
|
||||
ref={dropdownRef}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
{distinctLanguages.map((language) => {
|
||||
const isSelected = selectedLanguage === language;
|
||||
<div className="relative mb-1 px-1">
|
||||
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
|
||||
<input
|
||||
ref={searchInputRef}
|
||||
type="text"
|
||||
className="w-full rounded-md border border-gray-200 py-1.5 pl-9 pr-3 text-sm focus:border-gray-300 focus:outline-none"
|
||||
placeholder="Search languages..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => {
|
||||
setSearchQuery(e.target.value);
|
||||
setHighlightedIndex(0);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div ref={optionsRef} className="max-h-[200px] overflow-y-auto">
|
||||
{filteredLanguages.map((language, index) => {
|
||||
const isSelected = selectedLanguage === language;
|
||||
const isHighlighted = index === highlightedIndex;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={language}
|
||||
className="flex w-full items-center rounded-md px-4 py-1.5 text-left text-sm text-gray-700 hover:bg-gray-100 aria-selected:bg-gray-100"
|
||||
onClick={() => {
|
||||
onSelectLanguage(language);
|
||||
setIsOpen(false);
|
||||
}}
|
||||
aria-selected={isSelected}
|
||||
>
|
||||
{language}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
return (
|
||||
<button
|
||||
key={language}
|
||||
className={`flex w-full items-center rounded-md px-4 py-1.5 text-left text-sm text-gray-700 hover:bg-gray-100 aria-selected:bg-gray-100 ${
|
||||
isHighlighted ? 'bg-gray-100' : ''
|
||||
}`}
|
||||
onClick={() => {
|
||||
onSelectLanguage(language);
|
||||
setIsOpen(false);
|
||||
setSearchQuery('');
|
||||
setHighlightedIndex(0);
|
||||
}}
|
||||
aria-selected={isSelected}
|
||||
>
|
||||
{language}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
{filteredLanguages.length === 0 && (
|
||||
<div className="px-4 py-2 text-sm text-gray-500">
|
||||
No languages found
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
66
src/components/Projects/SortProjects.tsx
Normal file
66
src/components/Projects/SortProjects.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { useOutsideClick } from '../../hooks/use-outside-click';
|
||||
import { ChevronDown } from 'lucide-react';
|
||||
|
||||
type SortOption = {
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
const sortOptions: SortOption[] = [
|
||||
{ label: 'Latest First', value: 'latest' },
|
||||
{ label: 'Oldest First', value: 'oldest' },
|
||||
{ label: 'Highest Rating', value: 'rating' },
|
||||
];
|
||||
|
||||
type SortProjectsProps = {
|
||||
selectedSort: string;
|
||||
onSelectSort: (sort: string) => void;
|
||||
};
|
||||
|
||||
export function SortProjects(props: SortProjectsProps) {
|
||||
const { selectedSort, onSelectSort } = props;
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useOutsideClick(dropdownRef, () => {
|
||||
setIsOpen(false);
|
||||
});
|
||||
|
||||
const selectedOption =
|
||||
sortOptions.find((option) => option.value === selectedSort) ||
|
||||
sortOptions[0];
|
||||
|
||||
return (
|
||||
<div className="relative flex-shrink-0" ref={dropdownRef}>
|
||||
<button
|
||||
className="flex items-center gap-1 rounded-md border border-gray-300 py-1.5 pl-3 pr-2 text-xs font-medium text-gray-900"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
{selectedOption.label}
|
||||
<ChevronDown className="ml-1 h-4 w-4" />
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div className="absolute right-0 top-full z-10 mt-1.5 min-w-[150px] overflow-hidden rounded-md border border-gray-300 bg-white shadow-lg">
|
||||
<div className="py-1">
|
||||
{sortOptions.map((option) => (
|
||||
<button
|
||||
key={option.value}
|
||||
className={`flex w-full items-center px-4 py-1.5 text-left text-sm text-gray-700 hover:bg-gray-100 ${
|
||||
selectedSort === option.value ? 'bg-gray-100' : ''
|
||||
}`}
|
||||
onClick={() => {
|
||||
onSelectSort(option.value);
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -287,28 +287,32 @@ export function ProjectStepper(props: ProjectStepperProps) {
|
||||
number={2}
|
||||
/>
|
||||
|
||||
<span className="text-gray-600 sm:hidden">·</span>
|
||||
<button
|
||||
className={cn(
|
||||
'flex items-center gap-2 text-sm sm:hidden',
|
||||
isCopied ? 'text-green-500' : 'text-gray-600',
|
||||
)}
|
||||
onClick={() => {
|
||||
copyText(projectSolutionUrl);
|
||||
}}
|
||||
>
|
||||
{isCopied ? (
|
||||
<>
|
||||
<CheckIcon additionalClasses="h-3 w-3" />
|
||||
URL Copied
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Share className="h-3 w-3 stroke-[2.5px]" />
|
||||
Share your Solution
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
{activeStep > 1 && (
|
||||
<>
|
||||
<span className="text-gray-600 sm:hidden">·</span>
|
||||
<button
|
||||
className={cn(
|
||||
'flex items-center gap-2 text-sm sm:hidden',
|
||||
isCopied ? 'text-green-500' : 'text-gray-600',
|
||||
)}
|
||||
onClick={() => {
|
||||
copyText(projectSolutionUrl);
|
||||
}}
|
||||
>
|
||||
{isCopied ? (
|
||||
<>
|
||||
<CheckIcon additionalClasses="h-3 w-3" />
|
||||
URL Copied
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Share className="h-3 w-3 stroke-[2.5px]" />
|
||||
Share your Solution
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<StepperStepSeparator isActive={activeStep > 1} />
|
||||
<MilestoneStep
|
||||
|
||||
@@ -103,7 +103,7 @@ export function QuestionCard(props: QuestionCardProps) {
|
||||
|
||||
{question.isLongAnswer && (
|
||||
<div
|
||||
className={`qa-answer prose prose-sm prose-quoteless mx-auto flex w-full max-w-[600px] flex-grow flex-col items-start justify-center py-0 px-4 text-left text-sm prose-h1:mb-2.5 prose-h1:mt-7 prose-h2:mb-3 prose-h2:mt-0 prose-h3:mb-[5px] prose-h3:mt-[10px] prose-p:mb-2 prose-p:mt-0 prose-blockquote:font-normal prose-blockquote:not-italic prose-blockquote:text-gray-700 prose-pre:!mb-6 prose-pre:w-full prose-ul:my-2 prose-li:m-0 prose-li:mb-0.5 sm:px-5 sm:text-lg sm:prose-p:mb-4`}
|
||||
className={`qa-answer prose prose-h5:font-semibold prose-h5:mb-2 prose-h5:text-black prose-sm prose-quoteless mx-auto flex w-full max-w-[600px] flex-grow flex-col items-start justify-center py-0 px-4 text-left text-sm prose-h1:mb-2.5 prose-h1:mt-7 prose-h2:mb-3 prose-h2:mt-0 prose-h3:mb-[5px] prose-h3:mt-[10px] prose-p:mb-2 prose-p:mt-0 prose-blockquote:font-normal prose-blockquote:not-italic prose-blockquote:text-gray-700 prose-pre:!mb-6 prose-pre:w-full prose-ul:my-2 prose-li:m-0 prose-li:mb-0.5 sm:px-5 sm:text-lg sm:prose-p:mb-4`}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: markdownToHtml(question.answer, false),
|
||||
}}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
---
|
||||
import {
|
||||
getGuideTableOfContent,
|
||||
type GuideFileType,
|
||||
HeadingGroupType,
|
||||
} from '../../lib/guide';
|
||||
import { getGuideTableOfContent, type HeadingGroupType } from '../../lib/guide';
|
||||
import { markdownToHtml } from '../../lib/markdown';
|
||||
import { type QuestionGroupType } from '../../lib/question-group';
|
||||
import { RelatedGuides } from '../Guide/RelatedGuides';
|
||||
import MarkdownFile from '../MarkdownFile.astro';
|
||||
import { TableOfContent } from '../TableOfContent/TableOfContent';
|
||||
import { markdownToHtml, replaceVariables } from '../../lib/markdown';
|
||||
import { QuestionGroupType } from '../../lib/question-group';
|
||||
import { QuestionsList } from './QuestionsList';
|
||||
import { RelatedGuides } from '../Guide/RelatedGuides';
|
||||
|
||||
interface Props {
|
||||
questionGroup: QuestionGroupType;
|
||||
@@ -22,14 +18,12 @@ const tableOfContent: HeadingGroupType[] = [
|
||||
...getGuideTableOfContent(allHeadings),
|
||||
{
|
||||
depth: 2,
|
||||
title: 'Test with Flashcards',
|
||||
children: [],
|
||||
slug: 'test-with-flashcards',
|
||||
text: 'Test yourself with Flashcards',
|
||||
},
|
||||
{
|
||||
depth: 2,
|
||||
title: 'Questions List',
|
||||
children: [
|
||||
{
|
||||
depth: 2,
|
||||
@@ -68,7 +62,7 @@ const { frontmatter: guideFrontmatter, author } = questionGroup;
|
||||
<div class='bg-gradient-to-r from-gray-50 py-0 lg:col-start-3 lg:col-end-4 lg:row-start-1'>
|
||||
<RelatedGuides
|
||||
relatedTitle={guideFrontmatter?.relatedTitle}
|
||||
relatedGuides={guideFrontmatter?.relatedGuides || {}}
|
||||
relatedGuides={questionGroup?.relatedGuides || {}}
|
||||
client:load
|
||||
/>
|
||||
<TableOfContent toc={tableOfContent} client:load />
|
||||
@@ -86,7 +80,7 @@ const { frontmatter: guideFrontmatter, author } = questionGroup;
|
||||
>
|
||||
<MarkdownFile>
|
||||
<h1 class='mb-3 text-balance text-4xl font-bold'>
|
||||
{replaceVariables(guideFrontmatter.title)}
|
||||
{guideFrontmatter.title}
|
||||
</h1>
|
||||
{
|
||||
author && (
|
||||
@@ -142,8 +136,8 @@ const { frontmatter: guideFrontmatter, author } = questionGroup;
|
||||
</h3>
|
||||
{questionGroup.questions
|
||||
.filter((q) => {
|
||||
return q.topics
|
||||
.map((t) => t.toLowerCase())
|
||||
return q?.topics
|
||||
?.map((t) => t.toLowerCase())
|
||||
.includes(questionLevel);
|
||||
})
|
||||
.map((q) => (
|
||||
@@ -155,6 +149,11 @@ const { frontmatter: guideFrontmatter, author } = questionGroup;
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{questionGroup.ending && (
|
||||
<div class='mb-5'>
|
||||
<div set:html={markdownToHtml(questionGroup.ending, false)} />
|
||||
</div>
|
||||
)}
|
||||
</MarkdownFile>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
20
src/components/ReactIcons/HackerNewsIcon.tsx
Normal file
20
src/components/ReactIcons/HackerNewsIcon.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { cn } from '../../lib/classname';
|
||||
|
||||
interface HackerNewsIconProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function HackerNewsIcon(props: HackerNewsIconProps) {
|
||||
const { className } = props;
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
fill="currentColor"
|
||||
className={cn('h-[26px] w-[26px]', className)}
|
||||
>
|
||||
<path d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM21.2 229.2H21c.1-.1.2-.3.3-.4 0 .1 0 .3-.1.4zm218 53.9V384h-31.4V281.3L128 128h37.3c52.5 98.3 49.2 101.2 59.3 125.6 12.3-27 5.8-24.4 60.6-125.6H320l-80.8 155.1z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
20
src/components/ReactIcons/RedditIcon.tsx
Normal file
20
src/components/ReactIcons/RedditIcon.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { cn } from '../../lib/classname';
|
||||
|
||||
interface RedditIconProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function RedditIcon(props: RedditIconProps) {
|
||||
const { className } = props;
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
fill="currentColor"
|
||||
className={cn('h-[26px] w-[26px]', className)}
|
||||
>
|
||||
<path d="M283.2 345.5c2.7 2.7 2.7 6.8 0 9.2-24.5 24.5-93.8 24.6-118.4 0-2.7-2.4-2.7-6.5 0-9.2 2.4-2.4 6.5-2.4 8.9 0 18.7 19.2 81 19.6 100.5 0 2.4-2.3 6.6-2.3 9 0zm-91.3-53.8c0-14.9-11.9-26.8-26.5-26.8a26.67 26.67 0 0 0-26.8 26.8c0 14.6 11.9 26.5 26.8 26.5 14.6 0 26.5-11.9 26.5-26.5zm90.7-26.8c-14.6 0-26.5 11.9-26.5 26.8 0 14.6 11.9 26.5 26.5 26.5 14.9 0 26.8-11.9 26.8-26.5a26.67 26.67 0 0 0-26.8-26.8zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-99.7 140.6c-10.1 0-19 4.2-25.6 10.7-24.1-16.7-56.5-27.4-92.5-28.6l18.7-84.2 59.5 13.4c0 14.6 11.9 26.5 26.5 26.5 14.9 0 26.8-12.2 26.8-26.8s-11.9-26.8-26.8-26.8c-10.4 0-19.3 6.2-23.8 14.9l-65.7-14.6c-3.3-.9-6.5 1.5-7.4 4.8l-20.5 92.8c-35.7 1.5-67.8 12.2-91.9 28.9-6.5-6.8-15.8-11-25.9-11-37.5 0-49.8 50.4-15.5 67.5-1.2 5.4-1.8 11-1.8 16.7 0 56.5 63.7 102.3 141.9 102.3 78.5 0 142.2-45.8 142.2-102.3 0-5.7-.6-11.6-2.1-17 33.6-17.2 21.2-67.2-16.1-67.2z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
28
src/components/ReactIcons/RoadmapLogo.tsx
Normal file
28
src/components/ReactIcons/RoadmapLogo.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { SVGProps } from 'react';
|
||||
|
||||
type RoadmapLogoIconProps = SVGProps<SVGSVGElement> & {
|
||||
color?: 'white' | 'black';
|
||||
};
|
||||
|
||||
export function RoadmapLogoIcon(props: RoadmapLogoIconProps) {
|
||||
const { color = 'white', ...rest } = props;
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="30"
|
||||
height="30"
|
||||
viewBox="0 0 283 283"
|
||||
{...rest}
|
||||
>
|
||||
<path
|
||||
fill={color === 'black' ? '#000' : '#fff'}
|
||||
d="M0 39C0 17.46 17.46 0 39 0h205c21.539 0 39 17.46 39 39v205c0 21.539-17.461 39-39 39H39c-21.54 0-39-17.461-39-39V39Z"
|
||||
/>
|
||||
<path
|
||||
fill={color === 'black' ? '#fff' : '#000'}
|
||||
d="M121.215 210.72c-1.867.56-4.854 1.12-8.96 1.68-3.92.56-8.027.84-12.32.84-4.107 0-7.84-.28-11.2-.84-3.174-.56-5.88-1.68-8.12-3.36s-4.014-3.92-5.32-6.72c-1.12-2.987-1.68-6.813-1.68-11.48v-84c0-4.293.746-7.933 2.24-10.92 1.68-3.173 4.013-5.973 7-8.4s6.626-4.573 10.92-6.44c4.48-2.053 9.24-3.827 14.28-5.32a106.176 106.176 0 0 1 15.68-3.36 95.412 95.412 0 0 1 16.24-1.4c8.96 0 16.053 1.773 21.28 5.32 5.226 3.36 7.84 8.96 7.84 16.8 0 2.613-.374 5.227-1.12 7.84-.747 2.427-1.68 4.667-2.8 6.72a133.1 133.1 0 0 0-12.04.56c-4.107.373-8.12.933-12.04 1.68s-7.654 1.587-11.2 2.52c-3.36.747-6.254 1.68-8.68 2.8v95.48zm45.172-22.4c0-7.84 2.426-14.373 7.28-19.6s11.48-7.84 19.88-7.84 15.026 2.613 19.88 7.84 7.28 11.76 7.28 19.6-2.427 14.373-7.28 19.6-11.48 7.84-19.88 7.84-15.027-2.613-19.88-7.84-7.28-11.76-7.28-19.6z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -18,7 +18,7 @@ export function TwitterIcon(props: TwitterIconProps) {
|
||||
<rect width="23" height="23" rx="3" fill={boxColor} />
|
||||
<path
|
||||
d="M12.9285 10.3522L18.5135 4H17.1905L12.339 9.5144L8.467 4H4L9.8565 12.3395L4 19H5.323L10.443 13.1754L14.533 19H19M5.8005 4.97619H7.833L17.1895 18.0718H15.1565"
|
||||
fill='currentColor'
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { pageProgressMessage } from '../../stores/page';
|
||||
import type { UserProgressResponse } from '../HeroSection/FavoriteRoadmaps';
|
||||
import { SelectionButton } from './SelectionButton';
|
||||
import type { UserProgressResponse } from '../Roadmaps/RoadmapsPage';
|
||||
|
||||
type RoadmapSelectProps = {
|
||||
selectedRoadmaps: string[];
|
||||
|
||||
@@ -17,7 +17,7 @@ const links = [
|
||||
isHighlighted: true,
|
||||
},
|
||||
{
|
||||
link: '/ai/explore',
|
||||
link: '/ai',
|
||||
label: 'AI Roadmaps',
|
||||
description: 'Generate roadmaps with AI',
|
||||
Icon: Sparkles,
|
||||
@@ -64,7 +64,7 @@ export function RoadmapDropdownMenu() {
|
||||
</button>
|
||||
<div
|
||||
className={cn(
|
||||
'pointer-events-none invisible absolute left-0 top-full z-[999] mt-2 w-48 min-w-[320px] -translate-y-1 rounded-lg bg-slate-800 py-2 opacity-0 shadow-2xl transition-all duration-100',
|
||||
'pointer-events-none invisible absolute left-0 top-full z-[90] mt-2 w-48 min-w-[320px] -translate-y-1 rounded-lg bg-slate-800 py-2 opacity-0 shadow-2xl transition-all duration-100',
|
||||
{
|
||||
'pointer-events-auto visible translate-y-2.5 opacity-100':
|
||||
$roadmapsDropdownOpen,
|
||||
|
||||
@@ -13,7 +13,7 @@ import { MarkFavorite } from './FeaturedItems/MarkFavorite';
|
||||
import { type RoadmapFrontmatter } from '../lib/roadmap';
|
||||
import { ShareRoadmapButton } from './ShareRoadmapButton';
|
||||
import { DownloadRoadmapButton } from './DownloadRoadmapButton';
|
||||
|
||||
import { CourseAnnouncement } from './SQLCourse/CourseAnnouncement';
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
|
||||
@@ -8,24 +8,43 @@ import {
|
||||
import { useRef, useState } from 'react';
|
||||
import { useOutsideClick } from '../hooks/use-outside-click';
|
||||
import { markdownToHtml } from '../lib/markdown';
|
||||
import { cn } from '../lib/classname';
|
||||
import { useScrollPosition } from '../hooks/use-scroll-position';
|
||||
|
||||
type RoadmapTitleQuestionProps = {
|
||||
question: string;
|
||||
answer: string;
|
||||
roadmapId?: string;
|
||||
};
|
||||
|
||||
export function RoadmapTitleQuestion(props: RoadmapTitleQuestionProps) {
|
||||
const { question, answer } = props;
|
||||
const { question, answer, roadmapId } = props;
|
||||
|
||||
const [isAnswerVisible, setIsAnswerVisible] = useState(false);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const h2Ref = useRef<HTMLHeadingElement>(null);
|
||||
|
||||
useOutsideClick(ref, () => {
|
||||
setIsAnswerVisible(false);
|
||||
});
|
||||
|
||||
const { y: scrollY } = useScrollPosition();
|
||||
|
||||
return (
|
||||
<div className="relative hidden rounded-b-[5px] border-t bg-white text-sm font-medium hover:bg-gray-50 sm:block">
|
||||
<div
|
||||
className={cn(
|
||||
'relative hidden rounded-b-[5px] border-t bg-white text-sm font-medium hover:bg-gray-50 sm:block',
|
||||
{
|
||||
'rounded-0 -mx-4 sm:mx-0': isAnswerVisible,
|
||||
// @FIXME:
|
||||
// The line below is to keep the question hidden on mobile devices except for
|
||||
// the frontend roadmap. This is because we did not use to have the question
|
||||
// on mobile devices before and we don't want to cause any SEO issues. It will
|
||||
// be enabled on other roadmaps in the future.
|
||||
block: roadmapId === 'frontend',
|
||||
},
|
||||
)}
|
||||
>
|
||||
{isAnswerVisible && (
|
||||
<div className="fixed left-0 right-0 top-0 z-[100] h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50"></div>
|
||||
)}
|
||||
@@ -47,15 +66,25 @@ export function RoadmapTitleQuestion(props: RoadmapTitleQuestionProps) {
|
||||
</h2>
|
||||
|
||||
<div
|
||||
className={`absolute left-0 right-0 top-0 z-[100] mt-0 rounded-md border bg-white ${
|
||||
isAnswerVisible ? 'block' : 'hidden'
|
||||
className={`absolute left-0 right-0 top-0 z-[100] mt-0 border bg-white ${
|
||||
isAnswerVisible ? 'rounded-0 block sm:rounded-md' : 'hidden'
|
||||
}`}
|
||||
ref={ref}
|
||||
>
|
||||
{isAnswerVisible && (
|
||||
<h2
|
||||
className="flex cursor-pointer select-none items-center border-b px-[7px] py-[9px] text-base font-medium"
|
||||
onClick={() => setIsAnswerVisible(false)}
|
||||
className={cn(
|
||||
'sticky top-0 flex cursor-pointer select-none items-center rounded-t-md border-b bg-white px-[7px] py-[9px] text-base font-medium',
|
||||
)}
|
||||
onClick={() => {
|
||||
setIsAnswerVisible(false);
|
||||
if (
|
||||
scrollY > (h2Ref?.current?.getBoundingClientRect().top || 0)
|
||||
) {
|
||||
ref.current?.scrollIntoView();
|
||||
}
|
||||
}}
|
||||
ref={h2Ref}
|
||||
>
|
||||
<span className="flex flex-grow items-center">
|
||||
<Info className="mr-2 inline-block h-4 w-4" strokeWidth={2.5} />
|
||||
@@ -67,7 +96,7 @@ export function RoadmapTitleQuestion(props: RoadmapTitleQuestionProps) {
|
||||
</h2>
|
||||
)}
|
||||
<div
|
||||
className="bg-gray-100 p-3 text-base [&>h2]:mb-2 [&>h2]:mt-5 [&>h2]:text-[17px] [&>h2]:font-medium [&>p:last-child]:mb-0 [&>p>a]:font-semibold [&>p>a]:underline [&>p>a]:underline-offset-2 [&>p]:mb-3 [&>p]:font-normal [&>p]:leading-relaxed [&>p]:text-gray-800"
|
||||
className="bg-gray-100 p-3 text-base [&>h2]:mb-2 [&>h2]:mt-5 [&>h2]:text-[17px] [&>h2]:font-medium [&>p:last-child]:mb-0 [&>p>a]:font-semibold [&>p>a]:underline [&>p>a]:underline-offset-2 [&>p]:mb-3 [&>p]:font-normal [&>p]:leading-relaxed [&>p]:text-gray-800 [&>ul>li]:mb-2 [&>ul>li]:font-normal"
|
||||
dangerouslySetInnerHTML={{ __html: markdownToHtml(answer, false) }}
|
||||
></div>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user