Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concept deprecation form fields #113

Merged
merged 10 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/deploy_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ jobs:
run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
- name: Generate Key
run: php artisan key:generate
- name: Execute tests (Unit and Feature tests) via PHPUnit
env:
DB_PORT: 5432
run: vendor/bin/phpunit
# Awaiting PSQL container or service setup
# - name: Execute tests (Unit and Feature tests) via PHPUnit
# env:
# DB_PORT: 5432
# run: vendor/bin/phpunit
deploy-production:
name: Deploy Project to PRODUCTION Server
runs-on: self-hosted
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/test_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ jobs:
run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
- name: Generate Key
run: php artisan key:generate
- name: Execute tests (Unit and Feature tests) via PHPUnit
env:
DB_PORT: 5432
run: vendor/bin/phpunit
# Awaiting PSQL container or service setup
# - name: Execute tests (Unit and Feature tests) via PHPUnit
# env:
# DB_PORT: 5432
# run: vendor/bin/phpunit
27 changes: 20 additions & 7 deletions app/Http/Controllers/API/ConceptController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Http\Resources\ConceptResource;
use App\Models\Concept;
use App\Models\Term;
use App\Models\Vocabulary;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
Expand All @@ -20,7 +21,7 @@ class ConceptController extends Controller
*/
public function __construct()
{
$this->middleware('auth:sanctum')->except(['index', 'show', 'reconcile', 'search']);
$this->middleware('auth:sanctum')->except(['index', 'show', 'reconcile', 'search', 'categories']);
$this->authorizeResource(Concept::class);
}

Expand Down Expand Up @@ -62,9 +63,7 @@ public function index(Request $request)
$join->on('concepts.id', '=', 'preferred_terms.concept_id')
->where('preferred_terms.preferred', true);
})
->where(
'deprecated', '=', false
);
->where('deprecated', '=', false);

if ($sortBy === 'preferredTerm') {
$items->orderBy('preferred_terms.text', $sortOrder); // Order by the preferred term
Expand Down Expand Up @@ -255,9 +254,9 @@ public function deprecate(Request $request, Concept $concept)
if ($to) {
$replaceConcept = Concept::findOrFail($to);
$concept->setDeprecatedTo($replaceConcept);
} else {
$concept->deprecated = !$concept->deprecated;
$concept->save();

// NOTE: Not under version history, deprecation cannot be undone
DB::table('identity_concepts')->where('concept_id', $concept->id)->update(['concept_id' => $replaceConcept->id]);
}

return response()->json($concept, 200);
Expand Down Expand Up @@ -349,4 +348,18 @@ public function reconcile(Request $request)

return response()->json($terms->get());
}

/**
* Return array of categories.
*
* @return \Illuminate\Http\Response
*/
public function categories()
{
$categories = Vocabulary::where('type', 'concept_category')->get()
->map(function ($cat) {
return ['value' => $cat['id'], 'text' => $cat['value']];
});
return response()->json($categories, 200);
}
}
7 changes: 5 additions & 2 deletions app/Models/Concept.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class Concept extends Model
{
Expand Down Expand Up @@ -33,10 +34,12 @@ public function deprecatedTo()
return $this->belongsTo("\App\Models\Concept", "deprecated_to");
}

public function setDeprecatedTo($concept)
public function setDeprecatedTo($replacementConcept)
{
$this->deprecated = true;
return $this->deprecatedTo()->associate($concept)

DB::table('identity_concepts')->where('concept_id', $this->id)->update(['concept_id' => $replacementConcept->id]);
return $this->deprecatedTo()->associate($replacementConcept)
->save();
}

Expand Down
5 changes: 5 additions & 0 deletions docs/local-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,8 @@ Run the following command to stop your project.
```sh
ddev stop
```

### Running Laravel PHPUnit Tests
```sh
ddev artisan test
```
11 changes: 11 additions & 0 deletions resources/js/api/ConceptService.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ export default {
}
},

async deprecateConcept(conceptId, deprecatedToId) {
try {
const { data } = await apiClient.put(`/${conceptId}/deprecate`, {
to: deprecatedToId,
});
return [null, data];
} catch (error) {
return [error, null];
}
},

async searchConcepts(searchTerm, perPage = 10) {
try {
const { data } = await apiClient.get('/search', {
Expand Down
11 changes: 10 additions & 1 deletion resources/js/components/Concept/Default.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,18 @@ import MixinEditMode from './mixins/EditMode';
import MixinSource from './mixins/Source';
import MixinTerm from './mixins/Term';
import MixinRelationship from './mixins/Relationship';
import MixinDeprecate from './mixins/Deprecate';

export default {
mixins: [MixinCategory, MixinDirty, MixinEditMode, MixinSource, MixinTerm, MixinRelationship],
mixins: [
MixinCategory,
MixinDirty,
MixinEditMode,
MixinSource,
MixinTerm,
MixinRelationship,
MixinDeprecate,
],
components: {
BModal,
BButton,
Expand Down
49 changes: 49 additions & 0 deletions resources/js/components/Concept/Default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
>
<i class="fa fa-edit"></i> Edit
</BButton>
<BButton
variant="danger"
v-show="getEditMode() && !this.conceptProps.deprecated"
v-b-modal.concept-deprecation-to-search
>
Deprecate
<i class="fa fa-trash"></i>
</BButton>
<BButton
variant="secondary"
@click="leaveEditMode()"
Expand All @@ -21,6 +29,47 @@
Done Editing
</BButton>

<BModal
id="concept-deprecation-to-search"
title="Deprecate Concept"
size="xl"
@ok="deprecateConcept()"
ref="deprecate-modal"
:ok-disabled="!selectedConcept"
>
<div class="form-group">
<label for="relation-search"
>Search and select the concept that replaces
"{{ preferredTerm.text }}"</label
>
<b-form-input
v-model="searchTerm"
@input="searchConcepts"
placeholder="Type to search..."
></b-form-input>


<div v-if="isSearching" class="text-center my-2">
<b-spinner small></b-spinner> Searching...
</div>

<div class="search-results mt-2">
<div
v-for="concept in searchResults"
:key="concept.id"
class="search-result p-2"
:class="{
selected:
selectedConcept && selectedConcept.id === concept.id,
}"
@click="selectConcept(concept)"
>
{{ concept.preferred_term.text }}
</div>
</div>
</div>
</BModal>

<BModal
id="exit-confirmation-modal"
ref="exitModal"
Expand Down
23 changes: 23 additions & 0 deletions resources/js/components/Concept/mixins/Deprecate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import ConceptService from '../../../api/ConceptService';

export default {
methods: {
async deprecateConcept() {
console.log('Deprecating concept', this.selectedConcept);
if (!confirm('This action cannot be undone. Are you sure you want to deprecate?')) {
return;
}
const [error, data] = await ConceptService.deprecateConcept(
this.conceptId,
this.selectedConcept.id,
);

if (error) {
console.error('Failed to deprecate concept:', error);
return;
}
this.flashSuccessAlert();
window.location.reload();
},
},
};
33 changes: 12 additions & 21 deletions resources/js/components/Concept/mixins/Term.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,26 @@ import termApi from '../../../api/TermService';
export default {
data() {
return {
terms: this.termProps.map(
(term, index) => {
term.index = index;
if('undefined' === typeof term.inEdit){
term.inEdit = false;
}
return term;
},
),
terms: this.termProps.map((term, index) => {
term.index = index;
if ('undefined' === typeof term.inEdit) {
term.inEdit = false;
}
return term;
}),
termSearch: [],
allTermsSearch: false,
};
},
computed: {
alternateTerms() {
return this.terms
.filter((term) => !term.preferred)
.sort();
return this.terms.filter((term) => !term.preferred).sort();
},
preferredTerm() {
return this.terms.find((term) => term.preferred);
},
hasEmptyTerm() {
return !!(
this.terms.length &&
!this.terms[
this.terms.length - 1
].text
);
return !!(this.terms.length && !this.terms[this.terms.length - 1].text);
},
},
methods: {
Expand All @@ -54,7 +45,7 @@ export default {
},
async saveTerm(term, termIndex) {
const finalize = (term, termIndex) => {
if(term.inEdit) {
if (term.inEdit) {
this.cancelInlineEdit(term, termIndex);
}

Expand Down Expand Up @@ -136,7 +127,7 @@ export default {
});
},
enableInlineEdit(term, termIndex) {
if(!this.isVocabularyEditor){
if (!this.isVocabularyEditor) {
return;
}

Expand All @@ -146,6 +137,6 @@ export default {
cancelInlineEdit(term, termIndex) {
term.inEdit = false;
this.$set(this.terms, termIndex, term);
}
},
},
};
1 change: 1 addition & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
return $request->user();
});

Route::get('concepts/categories', 'API\ConceptController@categories');
Route::get('concepts/search', 'API\ConceptController@search');
Route::get('concepts/reconcile/{id}', 'API\ConceptController@reconcile');
Route::get('concepts/reconcile', 'API\ConceptController@reconcile');
Expand Down
Loading