diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..742ab9d --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +VITE_RULES_URL= diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index b1311b3..b33e52b 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -4,38 +4,39 @@ name: Build and deploy on: push: - branches: [ "main" ] + branches: ["main"] + +env: + VITE_RULES_URL: https://utarwyn.github.io/ecoCode/rules.json # only for testing purposes jobs: build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - - name: Use Node.js 18.X - uses: actions/setup-node@v3 - with: - node-version: 18.X - cache: 'npm' + - uses: actions/checkout@v3 - - name: Install dependencies - run: npm install + - name: Use Node.js 18.X + uses: actions/setup-node@v3 + with: + node-version: 18.X + cache: "npm" - - name: Lint - run: npm run lint + - name: Install dependencies + run: npm install - - name: Build - run: npm run build + - name: Lint + run: npm run lint - - name: Replace symlinks by the targeted file - run: find ./dist -type l -exec sh -c 'cp --remove-destination "$(readlink "{}")" "{}"' \; - - name: Archive production artifacts - uses: actions/upload-pages-artifact@v2 - with: - path: ./dist + - name: Build + run: npm run build + - name: Replace symlinks by the targeted file + run: find ./dist -type l -exec sh -c 'cp --remove-destination "$(readlink "{}")" "{}"' \; + - name: Archive production artifacts + uses: actions/upload-pages-artifact@v2 + with: + path: ./dist # Deploy job deploy: @@ -44,8 +45,8 @@ jobs: # Grant GITHUB_TOKEN the permissions required to make a Pages deployment permissions: - pages: write # to deploy to Pages - id-token: write # to verify the deployment originates from an appropriate source + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source # Deploy to the github-pages environment environment: diff --git a/src/App.vue b/src/App.vue index b30e0cb..6b353e0 100755 --- a/src/App.vue +++ b/src/App.vue @@ -1,11 +1,17 @@ diff --git a/src/assets/icons/circle_chevron_down.svg b/src/assets/icons/circle_chevron_down.svg new file mode 100644 index 0000000..2301aeb --- /dev/null +++ b/src/assets/icons/circle_chevron_down.svg @@ -0,0 +1 @@ + diff --git a/src/assets/icons/circle_chevron_up.svg b/src/assets/icons/circle_chevron_up.svg new file mode 100644 index 0000000..2ddadae --- /dev/null +++ b/src/assets/icons/circle_chevron_up.svg @@ -0,0 +1 @@ + diff --git a/src/assets/icons/info.svg b/src/assets/icons/info.svg new file mode 100644 index 0000000..ba4ac9b --- /dev/null +++ b/src/assets/icons/info.svg @@ -0,0 +1 @@ + diff --git a/src/assets/icons/triangle-alert.svg b/src/assets/icons/triangle-alert.svg new file mode 100644 index 0000000..f78657a --- /dev/null +++ b/src/assets/icons/triangle-alert.svg @@ -0,0 +1 @@ + diff --git a/src/assets/variables.css b/src/assets/variables.css index c952720..f1ad607 100644 --- a/src/assets/variables.css +++ b/src/assets/variables.css @@ -1,7 +1,9 @@ :root { /* Colors */ --color-primary: #355086; + --color-primary-new: #035c25; --color-on-primary: #ffffff; + --color-primary-container: hsl(220 43% 37% / 5%); --color-primary-lighter: hsl(220, 43%, 65%); --color-primary-focus-ring: hsl(220, 43%, 37%, 20%); --color-secondary: #57c18b; @@ -12,9 +14,12 @@ --color-on-quaternary: #ffffff; --color-additionnal-1: hsl(40, 100%, 89%); --color-additionnal-1-hover: hsl(40, 100%, 81%); + --color-warning-container: rgba(255, 206, 133, 50%); + --color-on-warning-container: #97743f; --color-surface: white; --color-on-surface: #022826; + --color-on-surface-bright: #59646A; /* Shadows */ --shadow-small: 0px 2px 2px rgba(0, 0, 0, .04); diff --git a/src/components/rules/RuleCard.vue b/src/components/rules/RuleCard.vue new file mode 100644 index 0000000..c657b90 --- /dev/null +++ b/src/components/rules/RuleCard.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/components/rules/RuleFilterItem.vue b/src/components/rules/RuleFilterItem.vue new file mode 100644 index 0000000..447c25a --- /dev/null +++ b/src/components/rules/RuleFilterItem.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/src/components/rules/RuleSeverity.vue b/src/components/rules/RuleSeverity.vue new file mode 100644 index 0000000..65ae2d3 --- /dev/null +++ b/src/components/rules/RuleSeverity.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/components/rules/RulesFilters.vue b/src/components/rules/RulesFilters.vue new file mode 100644 index 0000000..84d74be --- /dev/null +++ b/src/components/rules/RulesFilters.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/src/components/shared/AppBadge.vue b/src/components/shared/AppBadge.vue new file mode 100644 index 0000000..fe406b2 --- /dev/null +++ b/src/components/shared/AppBadge.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/src/composables/rule-filters.ts b/src/composables/rule-filters.ts new file mode 100644 index 0000000..a5a3309 --- /dev/null +++ b/src/composables/rule-filters.ts @@ -0,0 +1,38 @@ +import { computed, ref } from "vue"; + +const createDefaultState = (values: string[]): Record => { + return values.reduce((acc, value) => ({ ...acc, [value]: false }), {}); +}; + +const isFilterEnabled = (filter: RuleFilter): boolean => { + return Object.values(filter).some((value) => value); +}; + +export type RuleFilter = Record; + +export type RuleFilters = { + technologies: RuleFilter; + severities: RuleFilter; + statuses: RuleFilter; +}; + +export const useRuleFilters = ({ items, meta }: RuleList) => { + const filters = ref({ + technologies: createDefaultState(meta.technologies), + severities: createDefaultState(meta.severities), + statuses: createDefaultState(meta.statuses), + }); + + const filteredRules = computed(() => { + const { technologies, severities, statuses } = filters.value; + return items.filter( + (item) => + (!isFilterEnabled(technologies) || + item.technologies.some((tech) => technologies[tech])) && + (!isFilterEnabled(severities) || severities[item.severity]) && + (!isFilterEnabled(statuses) || statuses[item.status]), + ); + }); + + return { filters, filteredRules }; +}; diff --git a/src/global.d.ts b/src/global.d.ts index 916a603..ffb8685 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,8 +1,27 @@ -declare type MemberLinkType = 'linkedin' | 'github'; +declare type MemberLinkType = "linkedin" | "github"; declare type Member = { - name: string - company?: string - profile: string - links: Partial> -} + name: string; + company?: string; + profile: string; + links: Partial>; +}; + +declare type Rule = { + id: string; + name: string; + severity: "CRITICAL" | "INFO" | "MAJOR" | "MINOR"; + technologies: string[]; + status: string; +}; + +declare type RuleMeta = { + technologies: string[]; + severities: string[]; + statuses: string[]; +}; + +declare type RuleList = { + items: Rule[]; + meta: RuleMeta; +}; diff --git a/src/router/index.ts b/src/router/index.ts index 173b084..a7e60b7 100755 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -38,6 +38,11 @@ const router = createRouter({ }, ], }, + { + path: "/rules", + name: "rules", + component: () => import("@/views/RulesViews.vue"), + }, ], }); diff --git a/src/views/RulesViews.vue b/src/views/RulesViews.vue new file mode 100644 index 0000000..4b9a60a --- /dev/null +++ b/src/views/RulesViews.vue @@ -0,0 +1,123 @@ + + + + +