mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2026-04-05 17:15:33 +00:00
refactor(webapp): ds-radio -> html (#9403)
This commit is contained in:
parent
83df85001d
commit
4727eb6eb4
@ -4,7 +4,7 @@ defineStep(/^I confirm the reporting dialog .*:$/, message => {
|
|||||||
cy.contains(message) // wait for element to become visible
|
cy.contains(message) // wait for element to become visible
|
||||||
cy.get('.os-modal')
|
cy.get('.os-modal')
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get('.ds-radio-option-label')
|
cy.get('.report-radio-option')
|
||||||
.first()
|
.first()
|
||||||
.click({
|
.click({
|
||||||
force: true
|
force: true
|
||||||
|
|||||||
@ -13,7 +13,7 @@ Phase 0: Analyse ██████████ 100% (8/8 Schritte) ✅
|
|||||||
Phase 3: OsButton ██████████ 100% (133/133 Buttons) ✅
|
Phase 3: OsButton ██████████ 100% (133/133 Buttons) ✅
|
||||||
Phase 4: Tier 1 ██████████ 100% (OsButton, OsIcon, OsSpinner, OsCard) ✅
|
Phase 4: Tier 1 ██████████ 100% (OsButton, OsIcon, OsSpinner, OsCard) ✅
|
||||||
Phase 4: Tier A → HTML ██████████ 100% (10 ds-* Wrapper → Plain HTML) ✅
|
Phase 4: Tier A → HTML ██████████ 100% (10 ds-* Wrapper → Plain HTML) ✅
|
||||||
Phase 4: Tier B ████████░░ 80% (ds-chip→OsBadge✅, ds-tag→OsBadge✅, ds-grid✅, ds-number→OsNumber✅, ds-radio⬜)
|
Phase 4: Tier B ██████████ 100% (ds-chip→OsBadge✅, ds-tag→OsBadge✅, ds-grid✅, ds-number→OsNumber✅, ds-radio→HTML✅)
|
||||||
Phase 4: Tier B+ ████████░░ 75% (ds-table→HTML✅) | Tier 2 begonnen (OsModal✅) | Rest ausstehend (OsInput, OsMenu, OsSelect)
|
Phase 4: Tier B+ ████████░░ 75% (ds-table→HTML✅) | Tier 2 begonnen (OsModal✅) | Rest ausstehend (OsInput, OsMenu, OsSelect)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ Phase 4: Tier B+ ████████░░ 75% (ds-table→HTML✅)
|
|||||||
| ✅ → Plain HTML | Section, Placeholder, List, ListItem, Container, Heading, Text, Space, Flex, FlexItem, Grid, GridItem, Table (13) |
|
| ✅ → Plain HTML | Section, Placeholder, List, ListItem, Container, Heading, Text, Space, Flex, FlexItem, Grid, GridItem, Table (13) |
|
||||||
| ✅ → OsBadge | Chip (20 Nutzungen → OsBadge), Tag (3 → OsBadge shape="square") |
|
| ✅ → OsBadge | Chip (20 Nutzungen → OsBadge), Tag (3 → OsBadge shape="square") |
|
||||||
| ✅ → OsNumber | Number (5 Nutzungen → OsNumber, CountTo.vue gelöscht, vue-count-to entfernt) |
|
| ✅ → OsNumber | Number (5 Nutzungen → OsNumber, CountTo.vue gelöscht, vue-count-to entfernt) |
|
||||||
| ⬜ → Plain HTML | Radio (1) — Tier B Rest |
|
| ✅ → Plain HTML | Radio (1 Datei → native `<input type="radio">` in ReportModal) |
|
||||||
| ⬜ → UI-Library | Modal, Input, Menu, MenuItem, Select (5) — Tier 2-3 |
|
| ⬜ → UI-Library | Modal, Input, Menu, MenuItem, Select (5) — Tier 2-3 |
|
||||||
| ⬜ Offen | Form (18 Dateien — HTML oder OsForm?) |
|
| ⬜ Offen | Form (18 Dateien — HTML oder OsForm?) |
|
||||||
| ⬜ Nicht in Webapp | Code, CopyField, FormItem, InputError, InputLabel, Page, PageTitle, Logo, Avatar, TableCol, TableHeadCol (11) |
|
| ⬜ Nicht in Webapp | Code, CopyField, FormItem, InputError, InputLabel, Page, PageTitle, Logo, Avatar, TableCol, TableHeadCol (11) |
|
||||||
@ -76,7 +76,7 @@ Phase 4: Tier B+ ████████░░ 75% (ds-table→HTML✅)
|
|||||||
| 17 | Input | ⬜ Tier 2 | 23 Dateien → OsInput (gekoppelt mit Form) |
|
| 17 | Input | ⬜ Tier 2 | 23 Dateien → OsInput (gekoppelt mit Form) |
|
||||||
| 18 | InputError | ⬜ Nicht genutzt | Intern von Input genutzt |
|
| 18 | InputError | ⬜ Nicht genutzt | Intern von Input genutzt |
|
||||||
| 19 | InputLabel | ⬜ Nicht genutzt | Intern von Input genutzt |
|
| 19 | InputLabel | ⬜ Nicht genutzt | Intern von Input genutzt |
|
||||||
| 20 | Radio | ⬜ Tier B | 1 Datei → native `<input type="radio">` |
|
| 20 | Radio | ✅ → HTML | 1 Datei → native `<input type="radio">` + `<fieldset>` (ReportModal) |
|
||||||
| 21 | Select | ⬜ Tier 4 | 3 Dateien → OsSelect |
|
| 21 | Select | ⬜ Tier 4 | 3 Dateien → OsSelect |
|
||||||
|
|
||||||
### Layout
|
### Layout
|
||||||
@ -439,7 +439,7 @@ Phase 4: Tier B+ ████████░░ 75% (ds-table→HTML✅)
|
|||||||
15. [x] ds-tag (3 Dateien) → OsBadge shape="square" (UI-Library)
|
15. [x] ds-tag (3 Dateien) → OsBadge shape="square" (UI-Library)
|
||||||
16. [x] ds-grid / ds-grid-item (10 Dateien) → CSS Grid (Plain HTML)
|
16. [x] ds-grid / ds-grid-item (10 Dateien) → CSS Grid (Plain HTML)
|
||||||
17. [ ] ds-number (5 Dateien) → `<div class="ds-number">`
|
17. [ ] ds-number (5 Dateien) → `<div class="ds-number">`
|
||||||
18. [ ] ds-radio (1 Datei) → native `<input type="radio">`
|
18. [x] ds-radio (1 Datei) → native `<input type="radio">` + `<fieldset>` (ReportModal) ✅
|
||||||
|
|
||||||
### Phase 4: Tier 2-4 — UI-Library
|
### Phase 4: Tier 2-4 — UI-Library
|
||||||
18. [x] OsModal (h() Render, Focus-Trap, Scroll-Lock, A11y; ConfirmModal + ReportModal nutzen OsModal; DeleteUserModal/DisableModal/ReleaseModal gelöscht) ✅
|
18. [x] OsModal (h() Render, Focus-Trap, Scroll-Lock, A11y; ConfirmModal + ReportModal nutzen OsModal; DeleteUserModal/DisableModal/ReleaseModal gelöscht) ✅
|
||||||
|
|||||||
@ -81,10 +81,10 @@ Phase 0: ██████████ 100% (6/6 Aufgaben) ✅
|
|||||||
Phase 1: ██████████ 100% (6/6 Aufgaben) ✅
|
Phase 1: ██████████ 100% (6/6 Aufgaben) ✅
|
||||||
Phase 2: ██████████ 100% (26/26 Aufgaben) ✅
|
Phase 2: ██████████ 100% (26/26 Aufgaben) ✅
|
||||||
Phase 3: ██████████ 100% (24/24 Aufgaben) ✅ - Webapp-Integration komplett
|
Phase 3: ██████████ 100% (24/24 Aufgaben) ✅ - Webapp-Integration komplett
|
||||||
Phase 4: ███████░░░ 67% (18/27 Aufgaben) - Tier 1 ✅, Tier A ✅, Infra ✅, OsBadge ✅, ds-grid ✅, ds-table→HTML ✅, OsNumber ✅, OsModal ✅ | Tier B (rest), Tier 2-3 ausstehend
|
Phase 4: ███████░░░ 70% (19/27 Aufgaben) - Tier 1 ✅, Tier A ✅, Infra ✅, OsBadge ✅, ds-grid ✅, ds-table→HTML ✅, OsNumber ✅, OsModal ✅, ds-radio→HTML ✅ | Tier B ✅, Tier 2-3 ausstehend
|
||||||
Phase 5: ░░░░░░░░░░ 0% (0/7 Aufgaben)
|
Phase 5: ░░░░░░░░░░ 0% (0/7 Aufgaben)
|
||||||
───────────────────────────────────────
|
───────────────────────────────────────
|
||||||
Gesamt: ████████░░ 83% (80/96 Aufgaben)
|
Gesamt: ████████░░ 84% (81/96 Aufgaben)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Katalogisierung (Details in KATALOG.md)
|
### Katalogisierung (Details in KATALOG.md)
|
||||||
@ -216,11 +216,20 @@ ds-chip + ds-tag → OsBadge (UI-Library): ✅
|
|||||||
|
|
||||||
## Aktueller Stand
|
## Aktueller Stand
|
||||||
|
|
||||||
**Letzte Aktualisierung:** 2026-02-20 (Session 32)
|
**Letzte Aktualisierung:** 2026-03-14 (Session 33)
|
||||||
|
|
||||||
**Aktuelle Phase:** Phase 4 - Tier 1 ✅, Tier A ✅, OsBadge ✅, ds-grid ✅, ds-table→HTML ✅, OsNumber ✅ | Tier B (rest), Tier 2-3 ausstehend
|
**Aktuelle Phase:** Phase 4 - Tier 1 ✅, Tier A ✅, Tier B ✅, OsModal ✅ | Tier 2-3 ausstehend
|
||||||
|
|
||||||
**Zuletzt abgeschlossen (Session 32 - OsNumber: ds-number + CountTo → OsNumber):**
|
**Zuletzt abgeschlossen (Session 33 - ds-radio → native HTML):**
|
||||||
|
- [x] `<ds-radio>` in ReportModal.vue → native `<fieldset>` + `<input type="radio">` + `<label>`
|
||||||
|
- [x] Accessible Radio-Group: `<fieldset>` mit `<legend>` für Screen-Reader
|
||||||
|
- [x] CSS: `.report-radio-group`, `.report-radio-option`, `.report-radio-option-label` (in ReportModal `<style>`)
|
||||||
|
- [x] ReportModal.spec.js: `.ds-radio-option-label` → `input[type="radio"]` Selektor
|
||||||
|
- [x] Cypress E2E: `.ds-radio-option-label` → `input[type="radio"]` Selektor
|
||||||
|
- [x] 14/14 Unit-Tests bestanden
|
||||||
|
- [x] 0 ds-radio Nutzungen verbleibend
|
||||||
|
|
||||||
|
**Zuvor abgeschlossen (Session 32 - OsNumber: ds-number + CountTo → OsNumber):**
|
||||||
- [x] OsNumber Komponente in packages/ui erstellt (h() Render-Function, requestAnimationFrame Animation)
|
- [x] OsNumber Komponente in packages/ui erstellt (h() Render-Function, requestAnimationFrame Animation)
|
||||||
- [x] Props: count (required), label (optional), animated (optional, 1500ms ease-out)
|
- [x] Props: count (required), label (optional), animated (optional, 1500ms ease-out)
|
||||||
- [x] Animation: requestAnimationFrame-Loop, watch(count) re-animiert von oldVal→newVal
|
- [x] Animation: requestAnimationFrame-Loop, watch(count) re-animiert von oldVal→newVal
|
||||||
@ -279,8 +288,7 @@ ds-chip + ds-tag → OsBadge (UI-Library): ✅
|
|||||||
- [x] Test-Fix: Empty.spec.js `attributes().margin` → `classes().toContain('ds-my-xxx-small')`
|
- [x] Test-Fix: Empty.spec.js `attributes().margin` → `classes().toContain('ds-my-xxx-small')`
|
||||||
- [x] 0 Tier-A `ds-*` Komponenten-Tags verbleibend
|
- [x] 0 Tier-A `ds-*` Komponenten-Tags verbleibend
|
||||||
|
|
||||||
**Verbleibende ds-* Komponenten (7 Typen):**
|
**Verbleibende ds-* Komponenten (6 Typen):**
|
||||||
- Tier B Rest (→ Plain HTML): ds-radio (1)
|
|
||||||
- Tier C (→ UI-Library): ds-input (23), ds-form (18), ds-modal (7), ds-menu/ds-menu-item (17), ds-select (3)
|
- Tier C (→ UI-Library): ds-input (23), ds-form (18), ds-modal (7), ds-menu/ds-menu-item (17), ds-select (3)
|
||||||
|
|
||||||
**Zuvor abgeschlossen (Session 26 - CodeRabbit Review Fixes):**
|
**Zuvor abgeschlossen (Session 26 - CodeRabbit Review Fixes):**
|
||||||
|
|||||||
@ -162,7 +162,7 @@ describe('ReportModal.vue', () => {
|
|||||||
|
|
||||||
describe('click confirm button', () => {
|
describe('click confirm button', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
wrapper.find('.ds-radio-option-label').trigger('click')
|
wrapper.find('.report-radio-option').trigger('click')
|
||||||
await Vue.nextTick()
|
await Vue.nextTick()
|
||||||
wrapper.find('button.confirm').trigger('click')
|
wrapper.find('button.confirm').trigger('click')
|
||||||
await Vue.nextTick()
|
await Vue.nextTick()
|
||||||
|
|||||||
@ -9,13 +9,26 @@
|
|||||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<p v-html="message" />
|
<p v-html="message" />
|
||||||
<div class="ds-mb-small"></div>
|
<div class="ds-mb-small"></div>
|
||||||
<ds-radio
|
<fieldset class="report-radio-group" data-test="report-radio-group" role="radiogroup">
|
||||||
v-model="form.reasonCategory"
|
<legend>{{ $t('report.reason.category.label') }}</legend>
|
||||||
:schema="formSchema.reasonCategory"
|
<div
|
||||||
:label="$t('report.reason.category.label')"
|
v-for="(option, index) in form.reasonCategoryOptions"
|
||||||
:options="form.reasonCategoryOptions"
|
:key="option.value"
|
||||||
labelProp="label"
|
class="report-radio-option"
|
||||||
/>
|
:class="{ 'report-radio-option-selected': form.reasonCategory === option }"
|
||||||
|
role="radio"
|
||||||
|
:aria-checked="String(form.reasonCategory === option)"
|
||||||
|
:tabindex="form.reasonCategory === option || (!form.reasonCategory && index === 0) ? 0 : -1"
|
||||||
|
@click="selectReasonCategory(option)"
|
||||||
|
@keydown.space.prevent="selectReasonCategory(option)"
|
||||||
|
@keydown.enter.prevent="selectReasonCategory(option)"
|
||||||
|
@keydown.down.prevent="focusRadioOption(index + 1)"
|
||||||
|
@keydown.up.prevent="focusRadioOption(index - 1)"
|
||||||
|
>
|
||||||
|
<span class="report-radio-option-mark" />
|
||||||
|
<span class="report-radio-option-label">{{ option.label }}</span>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
<ds-input
|
<ds-input
|
||||||
class="reason-description"
|
class="reason-description"
|
||||||
v-model="form.reasonDescription"
|
v-model="form.reasonDescription"
|
||||||
@ -119,6 +132,18 @@ export default {
|
|||||||
this.$emit('close')
|
this.$emit('close')
|
||||||
}, 1000)
|
}, 1000)
|
||||||
},
|
},
|
||||||
|
selectReasonCategory(option) {
|
||||||
|
this.form.reasonCategory = option
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const selected = this.$el.querySelector('.report-radio-option[aria-checked="true"]')
|
||||||
|
if (selected) selected.focus()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
focusRadioOption(index) {
|
||||||
|
const options = this.form.reasonCategoryOptions
|
||||||
|
const wrappedIndex = (index + options.length) % options.length
|
||||||
|
this.selectReasonCategory(options[wrappedIndex])
|
||||||
|
},
|
||||||
async confirm() {
|
async confirm() {
|
||||||
const { reasonCategory, reasonDescription } = this.form
|
const { reasonCategory, reasonDescription } = this.form
|
||||||
this.loading = true
|
this.loading = true
|
||||||
@ -174,12 +199,54 @@ export default {
|
|||||||
width: 700px !important;
|
width: 700px !important;
|
||||||
max-width: 700px !important;
|
max-width: 700px !important;
|
||||||
}
|
}
|
||||||
.report-modal .ds-radio-option {
|
.report-modal .report-radio-group {
|
||||||
width: 100% !important;
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
.report-modal .ds-radio-option-label {
|
.report-modal .report-radio-group legend {
|
||||||
margin: 5px 20px 5px 5px !important;
|
font-weight: bold;
|
||||||
width: 100% !important;
|
margin-bottom: $space-xx-small;
|
||||||
|
}
|
||||||
|
.report-modal .report-radio-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 4px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.report-modal .report-radio-option-mark {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
min-width: 16px;
|
||||||
|
border: 2px solid $border-color-base;
|
||||||
|
background-color: $background-color-base;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.report-modal .report-radio-option-mark::before {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateY(-50%) translateX(-50%) scale(0);
|
||||||
|
opacity: 0;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: $text-color-primary;
|
||||||
|
transition: all 0.1s ease-in;
|
||||||
|
}
|
||||||
|
.report-modal .report-radio-option-selected .report-radio-option-mark::before {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(-50%) translateX(-50%) scale(1);
|
||||||
|
}
|
||||||
|
.report-modal .report-radio-option-label {
|
||||||
|
cursor: pointer;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
.report-modal .reason-description {
|
.report-modal .reason-description {
|
||||||
margin-top: $space-x-small !important;
|
margin-top: $space-x-small !important;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user