Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into three-pane-okrs
Browse files Browse the repository at this point in the history
  • Loading branch information
petterhj committed Sep 25, 2023
2 parents 70ff948 + 09a565a commit 9c16562
Show file tree
Hide file tree
Showing 72 changed files with 1,182 additions and 1,629 deletions.
33 changes: 26 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,39 @@ All notable changes to this project will be documented in this file. The format
### Fixed

- Fixed create/edit/delete rights for organization admins.
- Organization, department and product filter in admin panel should no longer
disappear when search result count reaches certain threshold.
- Improved WCAG compliance with respect to text color contrast.
- Fixed a problem that would sometimes cause an "infinite spinner" when a new
version of the app was deployed.

### Changed

- Organization, department and product details are now edited from within the
current item's about page.
- Made links clickable in the description of objects, key results and goals.
- It is no longer possible to close open modals or drawers by clicking outside
them. This is meant to prevent accidental data loss in unsaved forms.
them. This is meant to prevent accidental data loss in unsaved forms. Drawers
can however still be closed by outside click after form submission.
- Items in the admin panel now links directly to each respective item about page
with the edit drawer opened.
- The currently active item tab is now kept when navigating between
organizational items.
- Validation in forms are now less "eager" and errors are only displayed after
attempted form submissions.
- Administration of measurements has been moved to drawers and follows the same
pattern as when editing OKRs and other items.
- Detail views for both objectives and key results are now shown as panes in the
OKR timeline view. The number of simultaneously visible panes depends on the
viewport size (and is otherwise stacked). Clicking objectives in the timeline
now toggles the detail pane rather than adding objectives to a list. To group
objectives in a list (and see combined progression), the meta key must now be
pressed while selecting one or more objectives.

### Removed

- The admin panel tab has been completely removed from the item tab bar (all
functionality moved to drawers).

## [3.9.0] 2023-09-01

Expand All @@ -39,12 +64,6 @@ All notable changes to this project will be documented in this file. The format
- Progression values are now required to be positive on entry, both from the web
interface and from the API.
- The design of the period selector has been refreshed.
- Detail views for both objectives and key results are now shown as panes in the
OKR timeline view. The number of simultaneously visible panes depends on the
viewport size (and is otherwise stacked). Clicking objectives in the timeline
now toggles the detail pane rather than adding objectives to a list. To group
objectives in a list (and see combined progression), the meta key must now be
pressed while selecting one or more objectives.

### Removed

Expand Down
54 changes: 40 additions & 14 deletions firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ service cloud.firestore {
return isSignedIn() && (isAdminOfOrg || isAdminFromOrgOfProdOrDep);
}

/**
* Return true if the current user is an admin of the organization that
* `document` belongs to.
*
* The document can belong to an organization either by a transitive link
* (`document` → `parent` → `organization`) or directly
* (`document` → `parent`).
*/
//
// Return true if the current user is an admin of the organization that
// `document` belongs to.
//
// The document can belong to an organization either by a transitive link
// (`document` → `parent` → `organization`) or directly
// (`document` → `parent`).
//
function isAdminOfParent(document, type) {
let userDoc = getUserDoc();
let userIsAdmin = isAdmin();
Expand Down Expand Up @@ -78,9 +78,9 @@ service cloud.firestore {
return userIsTeamMember;
}

/**
* Return true if the current user is a member of `document.parent`.
*/
//
// Return true if the current user is a member of `document.parent`.
//
function isMemberOfParent(document, type) {
let userRef = /databases/$(database)/documents/users/$(request.auth.token.email);
let doc = getAfter(/databases/$(database)/documents/$(type)/$(document));
Expand All @@ -89,6 +89,32 @@ service cloud.firestore {
return userIsMemberOfParent;
}

//
// Return true if the current user is a member of the parent of the
// document's objective *before* performing the action.
//
function isMemberOfObjectiveParentBefore(document, type) {
let userRef = /databases/$(database)/documents/users/$(request.auth.token.email);
let doc = get(/databases/$(database)/documents/$(type)/$(document));
let objectiveDoc = get(doc.data.objective);
let parentDoc = get(objectiveDoc.data.parent);
let userIsMemberOfParent = userRef in parentDoc.data.team;
return userIsMemberOfParent;
}

//
// Return true if the current user is a member of the parent of the
// document's objective *after* performing the action.
//
function isMemberOfObjectiveParentAfter(document, type) {
let userRef = /databases/$(database)/documents/users/$(request.auth.token.email);
let doc = getAfter(/databases/$(database)/documents/$(type)/$(document));
let objectiveDoc = getAfter(doc.data.objective);
let parentDoc = getAfter(objectiveDoc.data.parent);
let userIsMemberOfParent = userRef in parentDoc.data.team;
return userIsMemberOfParent;
}

function isSelf(document) {
let user = document == request.auth.token.email;
return user;
Expand Down Expand Up @@ -158,11 +184,11 @@ service cloud.firestore {
allow delete: if isSuperAdmin();
}

/*
* TODO: Needs to be extended with rules for `create` and `delete`.
*/
// TODO: Should also allow create/delete by organization admins.
match /objectiveContributors/{document} {
allow read: if isSignedIn();
allow create: if isSuperAdmin() || isMemberOfObjectiveParentAfter(document, 'objectiveContributors');
allow delete: if isSuperAdmin() || isMemberOfObjectiveParentBefore(document, 'objectiveContributors');
}

match /periods/{document} {
Expand Down
13 changes: 11 additions & 2 deletions src/components/ArchivedRestore.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<template>
<pkt-alert :title="$t('archived.heading')" skin="warning" class="archived-alert">
<div class="archived-alert__body">
<p>{{ $t(`archived.body.${objectType}`) }} {{ $t('archived.restoreText') }}</p>
<p v-if="text">{{ text }}</p>
<p v-else>
{{ $t(`archived.body.${objectType}`) }} {{ $t('archived.restoreText') }}
</p>

<pkt-button
v-if="hasEditRights"
Expand Down Expand Up @@ -35,7 +38,13 @@ export default {
},
objectType: {
type: String,
required: true,
required: false,
default: null,
},
text: {
type: String,
required: false,
default: null,
},
},
Expand Down
4 changes: 3 additions & 1 deletion src/components/EmptyState.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
</template>

<script>
import BuildingsGraphic from '@/components/graphics/BuildingsGraphic.vue';
export default {
name: 'EmptyState',
components: {
BuildingsGraphic: () => import('@/components/graphics/BuildingsGraphic.vue'),
BuildingsGraphic,
},
props: {
Expand Down
4 changes: 2 additions & 2 deletions src/components/FormComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,13 @@
</template>

<script>
import { PktButton } from '@oslokommune/punkt-vue2';
import { PktAlert, PktButton } from '@oslokommune/punkt-vue2';
export default {
name: 'FormComponent',
components: {
PktAlert: () => import('@oslokommune/punkt-vue2').then(({ PktAlert }) => PktAlert),
PktAlert,
PktButton,
},
Expand Down
3 changes: 2 additions & 1 deletion src/components/GanttChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,13 @@ import {
} from 'date-fns';
import { dateLongCompact } from '@/util';
import paneEvents from '@/components/layout/paneEvents';
import OkrLinkCard from '@/components/OkrLinkCard.vue';
export default {
name: 'GanttChart',
components: {
OkrLinkCard: () => import('@/components/OkrLinkCard.vue'),
OkrLinkCard,
},
props: {
Expand Down
108 changes: 67 additions & 41 deletions src/components/KpiDetails.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,45 @@
<template>
<div class="kpi-details">
<header class="kpi-details__header">
<div>
<h2 class="pkt-txt-30">{{ kpi.name }}</h2>
<pkt-button
v-if="hasEditRights"
skin="tertiary"
variant="icon-left"
icon-name="plus-sign"
@onClick="showValueModal = true"
>
{{ $t('kpi.newValue') }}
</pkt-button>
</div>
<HTML-output
v-if="kpi.description"
class="pkt-txt-14-light"
:html="kpi.description"
<h2>{{ kpi.name }}</h2>
<pkt-button
v-if="hasEditRights"
v-tooltip="$t('admin.measurement.change')"
skin="tertiary"
variant="icon-only"
size="medium"
icon-name="edit"
@onClick="$emit('edit-kpi')"
/>
</header>

<widget-kpi-progress-graph :kpi="kpi" :progress="progress" :goals="goals" />
<HTML-output
v-if="kpi.description"
class="mb-size-32 pkt-txt-16-light"
:html="kpi.description"
/>

<pkt-alert
v-if="hasEditRights && kpi.error && kpi.auto"
skin="error"
:close-alert="true"
class="mb-size-16"
>
{{ $t('kpi.automation.error') }}
<i18n path="kpi.automation.reviewSettings">
<a href="#" @click="$emit('edit-kpi')">{{
$t('kpi.automation.automationLink')
}}</a>
</i18n>
</pkt-alert>

<widget-kpi-progress-graph
:kpi="kpi"
:progress="progress"
:goals="goals"
@add-value="showValueModal = true"
@set-goals="showEditGoalsModal = true"
/>

<widget-kpi-progress-stats :kpi="kpi" :progress="progress" :goals="goals" />

Expand All @@ -36,30 +55,41 @@
@create-record="createProgressRecord"
@close="showValueModal = false"
/>

<edit-goals-modal
v-if="hasEditRights && showEditGoalsModal"
:kpi="kpi"
@close="showEditGoalsModal = false"
/>
</div>
</template>

<script>
import { mapState, mapGetters } from 'vuex';
import { db } from '@/config/firebaseConfig';
import { PktButton } from '@oslokommune/punkt-vue2';
import Progress from '@/db/Kpi/Progress';
import { PktAlert, PktButton } from '@oslokommune/punkt-vue2';
import {
filterDuplicatedProgressValues,
getCachedKPIProgress,
getKPIProgressQuery,
} from '@/util/kpiHelpers';
import EditGoalsModal from '@/components/modals/EditGoalsModal.vue';
import HTMLOutput from '@/components/HTMLOutput.vue';
import Progress from '@/db/Kpi/Progress';
import ProgressModal from '@/components/modals/KPIProgressModal.vue';
import WidgetKpiProgressGraph from '@/components/widgets/WidgetKpiProgressGraph.vue';
import WidgetKpiProgressStats from '@/components/widgets/WidgetKpiProgressStats.vue';
import WidgetKpiProgressHistory from '@/components/widgets/WidgetProgressHistory/WidgetKpiProgressHistory.vue';
import WidgetKpiProgressStats from '@/components/widgets/WidgetKpiProgressStats.vue';
export default {
name: 'KpiDetails',
components: {
PktAlert,
PktButton,
ProgressModal: () => import('@/components/modals/KPIProgressModal.vue'),
HTMLOutput: () => import('@/components/HTMLOutput.vue'),
ProgressModal,
HTMLOutput,
EditGoalsModal,
WidgetKpiProgressGraph,
WidgetKpiProgressHistory,
WidgetKpiProgressStats,
Expand All @@ -76,6 +106,7 @@ export default {
progressCollection: [],
goals: [],
showValueModal: false,
showEditGoalsModal: false,
}),
computed: {
Expand Down Expand Up @@ -157,32 +188,27 @@ export default {
</script>

<style lang="scss" scoped>
@use '@oslokommune/punkt-css/dist/scss/abstracts/mixins/typography' as *;
@include bp('laptop-up') {
.kpi-details {
margin-left: 3rem;
}
}
.kpi-details__header {
gap: 0.25rem;
margin-bottom: 1rem;
> div {
display: flex;
align-items: center;
button {
flex: 0;
white-space: nowrap;
}
h2 {
margin: 0;
}
@include bp('phablet-up') {
flex-direction: row;
justify-content: space-between;
display: flex;
flex-direction: row;
gap: 0.5rem;
align-items: center;
justify-content: space-between;
margin-bottom: 0.5rem;
h2 {
@include get-text('pkt-txt-20');
@include bp('tablet-up') {
@include get-text('pkt-txt-22');
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/KpiWidgetGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export default {
gap: 0.75rem;
align-items: center;
justify-content: space-between;
color: var(--color-grayscale-40);
color: var(--color-grayscale-60);
h2 {
flex-grow: 1;
Expand Down
Loading

0 comments on commit 9c16562

Please sign in to comment.