Added single user fetch to user api
This commit is contained in:
parent
cd66b5bba5
commit
0a3d759733
12 changed files with 127 additions and 37 deletions
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
<flag v-if="column.showFlag" :tooltip-text="getCellValue(item, column)" :iso="getCellValue(item, column)"></flag>
|
||||
<span v-else-if="column.iconResolver == null">{{ getCellValue(item, column) }}</span>
|
||||
<span v-else-if="column.badgeResolver">{{ getCellValue(item, column) }}</span>
|
||||
<component v-else
|
||||
:is="getCellValue(item, column)"
|
||||
weight="regular"
|
||||
|
|
|
|||
|
|
@ -13,16 +13,19 @@
|
|||
>
|
||||
<div v-if="toast.icon" class="toast__icon">
|
||||
<component
|
||||
:is="toast.icon"
|
||||
weight="regular"
|
||||
size="24"
|
||||
class="icon-btn"
|
||||
:is="toast.icon"
|
||||
weight="regular"
|
||||
size="24"
|
||||
class="icon-btn"
|
||||
/>
|
||||
</div>
|
||||
<div class="toast__content">
|
||||
<div v-if="toast.title" class="toast__title">{{ toast.title }}</div>
|
||||
<div class="toast__message">{{ toast.message }}</div>
|
||||
</div>
|
||||
<div v-if="toast.count > 1" class="toast__badge">
|
||||
{{ toast.count }}
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</teleport>
|
||||
|
|
@ -49,8 +52,40 @@ export default {
|
|||
* @param {string} options.variant - Toast variant: 'success', 'error', 'warning', 'info'
|
||||
* @param {number} options.duration - Auto-dismiss duration in ms (0 = no auto-dismiss)
|
||||
* @param {string} options.icon - Icon name (optional)
|
||||
* @param {boolean} options.stack - Whether to stack identical toasts (default: true)
|
||||
*/
|
||||
addToast(options = {}) {
|
||||
const shouldStack = options.stack !== undefined ? options.stack : true;
|
||||
|
||||
// Check if an identical toast already exists
|
||||
if (shouldStack) {
|
||||
const existingToast = this.toasts.find(t =>
|
||||
t.message === options.message &&
|
||||
t.title === (options.title || null) &&
|
||||
t.variant === this.mapVariant(options.variant || 'primary')
|
||||
);
|
||||
|
||||
if (existingToast) {
|
||||
// Increment count and reset timer
|
||||
existingToast.count = (existingToast.count || 1) + 1;
|
||||
|
||||
// Clear existing timeout
|
||||
if (existingToast.timeoutId) {
|
||||
clearTimeout(existingToast.timeoutId);
|
||||
}
|
||||
|
||||
// Set new timeout
|
||||
const duration = options.duration !== undefined ? options.duration : 5000;
|
||||
if (duration > 0) {
|
||||
existingToast.timeoutId = setTimeout(() => {
|
||||
this.removeToast(existingToast.id);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
return existingToast.id;
|
||||
}
|
||||
}
|
||||
|
||||
const toast = {
|
||||
id: this.nextId++,
|
||||
message: options.message || 'Notification',
|
||||
|
|
@ -58,13 +93,15 @@ export default {
|
|||
variant: this.mapVariant(options.variant || 'primary' ),
|
||||
duration: options.duration !== undefined ? options.duration : 5000,
|
||||
icon: options.icon ? `Ph${options.icon.charAt(0).toUpperCase() + options.icon.slice(1)}` : null,
|
||||
count: 1,
|
||||
timeoutId: null
|
||||
};
|
||||
|
||||
this.toasts.push(toast)
|
||||
|
||||
// Auto-dismiss if duration is set
|
||||
if (toast.duration > 0) {
|
||||
setTimeout(() => {
|
||||
toast.timeoutId = setTimeout(() => {
|
||||
this.removeToast(toast.id)
|
||||
}, toast.duration)
|
||||
}
|
||||
|
|
@ -94,6 +131,10 @@ export default {
|
|||
removeToast(id) {
|
||||
const index = this.toasts.findIndex(toast => toast.id === id)
|
||||
if (index > -1) {
|
||||
// Clear timeout if exists
|
||||
if (this.toasts[index].timeoutId) {
|
||||
clearTimeout(this.toasts[index].timeoutId);
|
||||
}
|
||||
this.toasts.splice(index, 1)
|
||||
}
|
||||
},
|
||||
|
|
@ -102,6 +143,12 @@ export default {
|
|||
* Remove all toasts
|
||||
*/
|
||||
clearToasts() {
|
||||
// Clear all timeouts
|
||||
this.toasts.forEach(toast => {
|
||||
if (toast.timeoutId) {
|
||||
clearTimeout(toast.timeoutId);
|
||||
}
|
||||
});
|
||||
this.toasts = []
|
||||
},
|
||||
|
||||
|
|
@ -150,12 +197,11 @@ export default {
|
|||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.toast:hover {
|
||||
transform: translateY(-2px);
|
||||
|
||||
box-shadow: 0 0.5rem 0.9rem rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
|
|
@ -197,22 +243,50 @@ export default {
|
|||
word-break: break-word;
|
||||
}
|
||||
|
||||
.toast__badge {
|
||||
flex-shrink: 0;
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
border-radius: 50%;
|
||||
background-color: #002F54;
|
||||
color: #5AF0B4;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.toast-primary {
|
||||
background-color: #5AF0B4;
|
||||
color: #002F54;
|
||||
}
|
||||
|
||||
.toast-primary .toast__badge {
|
||||
background-color: #002F54;
|
||||
color: #5AF0B4;
|
||||
}
|
||||
|
||||
.toast--secondary {
|
||||
color: #002F54;
|
||||
background-color: #c3cfdf;
|
||||
}
|
||||
|
||||
.toast--secondary .toast__badge {
|
||||
background-color: #002F54;
|
||||
color: #c3cfdf;
|
||||
}
|
||||
|
||||
.toast--exception{
|
||||
background-color: #BC2B72;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.toast--exception .toast__badge {
|
||||
background-color: #ffffff;
|
||||
color: #BC2B72;
|
||||
}
|
||||
|
||||
/* Transition animations */
|
||||
.toast-enter-active {
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@
|
|||
{{ premise.hs_code }}
|
||||
</div>
|
||||
<div class="edit-calculation-cell-line edit-calculation-cell-subline"
|
||||
v-if="premise.tariff_rate">
|
||||
v-if="(premise.tariff_rate ?? null) !== null">
|
||||
Tariff rate:
|
||||
{{ toPercent(premise.tariff_rate) }} %
|
||||
{{ toPercent(premise.tariff_rate) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ import ModalDialog from "@/components/UI/ModalDialog.vue";
|
|||
import {mapStores} from "pinia";
|
||||
import {useValidityPeriodStore} from "@/store/validityPeriod.js";
|
||||
import AutosuggestSearchbar from "@/components/UI/AutoSuggestSearchBar.vue";
|
||||
import DataTable from "@/components/UI/DataTable.vue";
|
||||
import TableView from "@/components/UI/TableView.vue";
|
||||
import RadioOption from "@/components/UI/RadioOption.vue";
|
||||
import {useMatrixRateStore} from "@/store/matrixRate.js";
|
||||
|
|
@ -80,7 +79,7 @@ export default {
|
|||
},
|
||||
components: {
|
||||
StagedRates,
|
||||
RadioOption, TableView, DataTable, AutosuggestSearchbar, ModalDialog, Tooltip, IconButton, Dropdown
|
||||
RadioOption, TableView, AutosuggestSearchbar, ModalDialog, Tooltip, IconButton, Dropdown
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useValidityPeriodStore, useMatrixRateStore, useContainerRateStore),
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ public class SecurityConfig {
|
|||
|
||||
} else if (identifyBy.equals("workday") && workdayId != null && !workdayId.isEmpty()) {
|
||||
log.debug("Fetch user by workday id {}", workdayId);
|
||||
user = userRepository.getByWorkdayId(workdayId);
|
||||
user = userRepository.getByWorkdayId(workdayId).orElse(null);
|
||||
}
|
||||
|
||||
if (user != null) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import org.springframework.validation.annotation.Validated;
|
|||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* REST Controller for managing user-related operations.
|
||||
|
|
@ -51,6 +52,22 @@ public class UserController {
|
|||
.body(users.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a single user by its workday id.
|
||||
*
|
||||
* @param workdayId The workday id of the user to retrieve.
|
||||
* @return A ResponseEntity containing the user, along with pagination headers.
|
||||
*/
|
||||
@GetMapping({"/{workdayId}/", "/{workdayId}"})
|
||||
@PreAuthorize("hasRole('RIGHT-MANAGEMENT')")
|
||||
public ResponseEntity<Optional<UserDTO>> getUser(@PathVariable String workdayId) {
|
||||
|
||||
Optional<UserDTO> users = userService.getUser(workdayId);
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.body(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the details of an existing user or creates a new one if it does not exist.
|
||||
* Users are identified by its workday id. If a group from the group membership does not exist
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@ public class UserDTO {
|
|||
@JsonProperty("workday_id")
|
||||
private String workdayId;
|
||||
|
||||
@JsonProperty("is_active")
|
||||
private boolean isActive;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1)
|
||||
@JsonProperty("groups")
|
||||
|
|
@ -65,14 +62,6 @@ public class UserDTO {
|
|||
this.workdayId = workdayId;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return isActive;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
isActive = active;
|
||||
}
|
||||
|
||||
public List<String> getGroups() {
|
||||
return groups;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import java.sql.Statement;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class UserRepository {
|
||||
|
|
@ -145,12 +146,12 @@ public class UserRepository {
|
|||
}
|
||||
|
||||
@Transactional
|
||||
public User getByWorkdayId(String workdayId) {
|
||||
public Optional<User> getByWorkdayId(String workdayId) {
|
||||
List<User> results = jdbcTemplate.query("SELECT * FROM sys_user WHERE workday_id = ?",
|
||||
new UserMapper(),
|
||||
workdayId);
|
||||
|
||||
return results.isEmpty() ? null : results.getFirst();
|
||||
return results.isEmpty() ? Optional.empty() : Optional.of(results.getFirst());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ public class UserTransformer {
|
|||
public UserDTO toUserDTO(User entity) {
|
||||
UserDTO dto = new UserDTO();
|
||||
|
||||
dto.setActive(entity.getActive());
|
||||
dto.setEmail(entity.getEmail());
|
||||
dto.setFirstName(entity.getFirstName());
|
||||
dto.setLastName(entity.getLastName());
|
||||
|
|
@ -25,7 +24,7 @@ public class UserTransformer {
|
|||
public User fromUserDTO(UserDTO dto) {
|
||||
User entity = new User();
|
||||
|
||||
entity.setActive(dto.isActive());
|
||||
entity.setActive(true);
|
||||
entity.setEmail(dto.getEmail());
|
||||
entity.setFirstName(dto.getFirstName());
|
||||
entity.setLastName(dto.getLastName());
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Service class responsible for handling business logic related to users.
|
||||
* Provides methods to retrieve and update user information.
|
||||
|
|
@ -38,6 +40,16 @@ public class UserService {
|
|||
return SearchQueryResult.map(userRepository.listUsers(new SearchQueryPagination(page, limit)), userTransformer::toUserDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a single user by its workday id.
|
||||
*
|
||||
* @param workdayId The workday id of the user to retrieve.
|
||||
* @return A ResponseEntity containing the user, along with pagination headers.
|
||||
*/
|
||||
public Optional<UserDTO> getUser(String workdayId) {
|
||||
return userRepository.getByWorkdayId(workdayId).map(userTransformer::toUserDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing user's information.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ spring.sql.init.mode=never
|
|||
lcc.allowed_cors=
|
||||
lcc.allowed_oauth_token_cors=*
|
||||
|
||||
logging.level.org.springframework.ws=DEBUG
|
||||
logging.level.org.springframework.oxm=DEBUG
|
||||
|
||||
lcc.auth.identify.by=workday
|
||||
lcc.auth.claim.workday=employeeid
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
INSERT INTO sys_group(group_name, group_description)
|
||||
VALUES ('none', 'no rights');
|
||||
INSERT INTO sys_group(group_name, group_description)
|
||||
VALUES ('basic', 'Login, generate reports');
|
||||
VALUES ('basic', 'can generate reports');
|
||||
INSERT INTO sys_group(group_name, group_description)
|
||||
VALUES ('calculation', 'Login, generate reports, do calculations');
|
||||
VALUES ('calculation', 'can generate reports, do calculations');
|
||||
INSERT INTO sys_group(group_name, group_description)
|
||||
VALUES ('freight', 'Login, generate reports, edit freight rates');
|
||||
VALUES ('freight', 'manage freight rates');
|
||||
INSERT INTO sys_group(group_name, group_description)
|
||||
VALUES ('packaging', 'Login, generate reports, edit packaging data');
|
||||
VALUES ('packaging', 'manage packaging data');
|
||||
INSERT INTO sys_group(group_name, group_description)
|
||||
VALUES ('material', 'Login, generate reports, edit material data');
|
||||
VALUES ('material', 'manage material data');
|
||||
INSERT INTO sys_group(group_name, group_description)
|
||||
VALUES ('super',
|
||||
'Login, generate reports, do calculations, edit freight rates, edit packaging data');
|
||||
'can generate reports, do calculations, manage freight rates, manage packaging data, manage material data, manage general system settings');
|
||||
INSERT INTO sys_group(group_name, group_description)
|
||||
VALUES ('service', 'Register API Tokens');
|
||||
VALUES ('service', 'register external applications');
|
||||
INSERT INTO sys_group(group_name, group_description)
|
||||
VALUES ('right-management',
|
||||
'Add/Remove users, groups, etc.');
|
||||
'add users, manage user groups');
|
||||
Loading…
Add table
Reference in a new issue